Managed Service Column <システム運用コラム>

Kubernetes で WordPress サイトを公開してみる (運用編)

Category: 実践編

2020.05.18

はじめに

前回のブログでは、無事に WordPress サイトの公開までたどり着けました。
しかし、実際のサービスでは、構築したら終わりではなく、その後の運用のほうが大事です。そして、Kubernetes はむしろ、運用のほうで本領を発揮します。

今回は、運用のなかでも特に以下にポイントを絞って、Kubernetes の機能をみてみます。

  • アプリケーションのアップデート
  • Pod に障害が発生した際の自動復旧
  • スケールイン、スケールアウト

アプリケーションのアップデート

本番環境で新しいアプリケーションをリリースすることは非常に大変な作業です。
システムやアプリケーションによっては、ダウンタイムが発生するために、メンテナンス時間を設けなくてはいけないこともあります。
Kubernetes では、ダウンタイムなく、安全にアプリケーションのアップデートを行うことができます。

一例として、公式のイメージに少しだけ修正を加えたものをリリースしてみます。
前回の記事では wp-content 以下を Azure Files による共有領域としました。
実は、WordPress の Docker イメージは毎回、起動時にドキュメントルート以下にファイルを展開するため、
共有領域内のファイルを上書きしてしまいます。
(デフォルトファイルに修正を加えていない限り、影響はありませんが。)

これを解消するために、公式の Docker イメージをカスタマイズしてみましょう。

Azure Container Registory の準備

カスタマイズしたイメージを保管するためのレジストリを用意しましょう。
今回は、Azure にて用意されている Azure Container Registory (以下、ACR) を利用します。

ACR の画面を開きます。

レジストリ名やリージョンを選択します。

できました。

最後に、AKS から ACR にアクセスできるようにします。
これにより、マニュフェストにてレジストリ内のイメージを指定するだけで、AKS 上にデプロイすることができます。

1rworks@Azure:~/build$ az aks update -n wordpress-cluster -g wordpress --attach-acr rworks

イメージのカスタマイズ

Docker ライブラリから、Dockerfile と docker-entrypoint.sh をダウンロードします。
https://github.com/docker-library/wordpress/tree/bf85cc7bf33afbbfadd86ba79b3d8ad325289057/php7.3/apache

1rworks@Azure:~/docker/wordpress$ ls
2docker-entrypoint.sh  Dockerfile

docker-entrypoint.sh は、Docker の起動時に実行されるスクリプトです。
このなかに、WordPress の初期設定を行うコマンドが羅列してあります。
ここに、「展開する前のファイル群から wp-content ディレクトリを削除する」行を追記します。

1                if [ "$user" != '0' ]; then
2                        # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted"
3                        targetTarArgs+=( --no-overwrite-dir )
4                fi
5+               rm -rf /usr/src/wordpress/wp-content
6                tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}"

編集した docker-entrypoint.sh を反映させたイメージを、ビルドして、ACR にプッシュします。
“az acr build” コマンドを利用すれば、Azure 側でビルドが行われ、そのまま ACR にプッシュしてくれます。
ローカルにビルドするための環境を用意する必要はありません。

1rworks@Azure:~/build$ az acr build --image wordpress:v1 --registry rworks --file DockerFile .
2Packing source code into tar to upload...
3Uploading archived source code from '/tmp/build_archive_922bf1d4cc1a431f9250e90182156ebf.tar.gz'...
4Sending context (349.000 Bytes) to registry: rworks...
5Queued a build with ID: ce1
6Waiting for an agent...
72020/04/13 14:53:56 Downloading source code...
8 
9- image:
10    registry: rworks.azurecr.io
11    repository: wordpress
12    tag: v1
13    digest: sha256:d9b24db8c01cf917cc17aeb48118a32293eb6fbf597a0b5154e9a51fd12c4257
14  runtime-dependency:
15    registry: registry.hub.docker.com
16    repository: library/wordpress
17    tag: latest
18    digest: sha256:191d5caf4ef5b8c57721ade777820f3267654325f7902b2ccd377ceeba1c3fe2
19  git: {}
20 
21Run ID: ce1 was successful after 1m4s

“rworks.azurecr.io/wordpress:v1” を指定して pull できるようになりました。

カスタマイズしたイメージのデプロイ

deployment.yaml を書き換えて、新しいイメージをデプロイしてみましょう。

deployment.yaml の image を ACR 上のイメージに書き換えます。

1spec:
2  containers:
3  #- image: wordpress
4  - image: rworks.azurecr.io/wordpress:v1

deployment を更新します。

1rworks@Azure:~$ kubectl apply -f deployment.yaml
2deployment.apps/wordpress configured

古い Pod が削除されるのと同時に、新しい Pod が作成されます。
既定では、このようにローリングアップデートが行われます。

1# 一時的に、Pod が2倍になります
2rworks@Azure:~$ kubectl get pod
3NAME                         READY   STATUS              RESTARTS   AGE
4wordpress-5f59c6698b-cdjkq   0/1     ContainerCreating   0          0s      # ← 新しい Pod
5wordpress-5f59c6698b-jh2r4   1/1     Running             0          5s      # ← 新しい Pod
6wordpress-7b95946f7c-gdm8b   1/1     Running             0          88s     # ← 古い Pod
7wordpress-7b95946f7c-vgnt4   1/1     Terminating         0          88s     # ← 古い Pod
8rworks@Azure:~$ kubectl get pod
9NAME                         READY   STATUS        RESTARTS   AGE
10wordpress-5f59c6698b-cdjkq   1/1     Running       0          14s           # ← 新しい Pod
11wordpress-5f59c6698b-jh2r4   1/1     Running       0          19s           # ← 新しい Pod
12wordpress-7b95946f7c-gdm8b   1/1     Terminating   0          102s          # ← 古い Pod
13wordpress-7b95946f7c-vgnt4   1/1     Terminating   0          102s          # ← 古い Pod
14rworks@Azure:~$ kubectl get pod
15 
16# 最終的に、Pod が入れ替わります
17rworks@Azure:~$ kubectl get pod
18NAME                         READY   STATUS    RESTARTS   AGE
19wordpress-5f59c6698b-cdjkq   1/1     Running   0          42s               # ← 新しい Pod
20wordpress-5f59c6698b-jh2r4   1/1     Running   0          47s               # ← 新しい Pod
21 
22# レプリカセットは古いものも残ります。
23rworks@Azure:~$ kubectl get rs
24NAME                   DESIRED   CURRENT   READY   AGE
25wordpress-5f59c6698b   2         2         2       51s     # ← image が wordpress:v1 のレプリカセット
26wordpress-7b95946f7c   0         0         0       2m14s   # ← image が wordpress のレプリカセット

万が一、アプリケーションに問題が生じた場合は、簡単にロールバックができます。
マニュフェスト deployment.yaml を編集前のものに戻して、再度、kubectl apply を実行します。

1spec:
2  containers:
3  - image: wordpress
4  # - image: rworks.azurecr.io/wordpress:v1

deployment を更新します。

1rworks@Azure:~$ kubectl apply -f deployment.yaml
2deployment.apps/wordpress configured

Pod は新しいものに置き換わっていますが、レプリカセットは一番初めのものに戻っていることが分かります。

1# Pod は新しいものに入れ替わります
2rworks@Azure:~$ kubectl get pod
3NAME                         READY   STATUS    RESTARTS   AGE
4wordpress-7b95946f7c-d826x   1/1     Running   0          23s
5wordpress-7b95946f7c-q7b2l   1/1     Running   0          29s
6 
7# レプリカセットがロールバックされています。
8rworks@Azure:~$ kubectl get rs
9NAME                   DESIRED   CURRENT   READY   AGE
10wordpress-5f59c6698b   0         0         0       11m    # ← image が wordpress:v1 のレプリカセット
11wordpress-7b95946f7c   2         2         2       12m    # ← image が wordpress のレプリカセット

このように、ダウンタイムのないアプリケーションのアップデートを簡単に行うことができます。
(削除される Pod と作成される Pod のタイミングによってはダウンタイムが発生することもあるので、パラメータは調整する必要があります。)
CI ツールと連携することで、アプリケーションのアップデートを完全自動化することも可能です。

Pod に障害が発生した際の自動復旧

Pod には Probe (ヘルスチェック) を設定することができ、Probe に失敗した際には自動で復旧させることができます。
Probe の方法には、”livenessProbe” と “readinessProbe” の2つのタイプがあります。
Probe 失敗後のアクションに違いがあり、前者は Pod の再作成が行われ、後者はサービスからのトラフィックが停止します。
デフォルトでは、livenessProbe が有効になっています。

今回は、livenessProbe を利用することにします。”httpGet” を指定することで、パス / の HTTP ステータスコードをチェックすることにします。
deployment.yaml の “template” 内に、以下の行を追加します。

1  template:
2    metadata:
3      labels:
4        app: wordpress
5        tier: frontend
6    spec:
7      containers:
8      #- image: wordpress
9      - image: rworks.azurecr.io/wordpress:v1
10        name: wordpress
11        envFrom:                      # ← 接続情報と認証情報を key, value を全て読み込み
12        - configMapRef:
13            name: wp-configmap
14        - secretRef:
15            name: db-secret
16        ports:
17        - containerPort: 80
18          name: wordpress
19+        livenessProbe:
20+          httpGet:
21+            path: /
22+            port: 80
23+            scheme: HTTP
24+          initialDelaySeconds: 30  # ← 初回の Probe は30秒待つ
25+          periodSeconds: 10        # ← 10秒間隔で Probe を行う
26+          timeoutSeconds: 5        # ← タイムアウトを5秒に

Pod と MySQL の間に何らかの問題が発生し、一時的に接続できなかった場合を想定します。
wp-config のデータベース接続情報を書き換え、擬似的にこの状況を再現してみます。

1rworks@Azure:~$ kubectl exec -it wordpress-69b76dc56f-q4tgz /bin/bash
2root@wordpress-69b76dc56f-q4tgz:/var/www/html# sed -i 's/wordpress-db-rworks.mysql.database.azure.com/hoge/' wp-config.php
3root@wordpress-69b76dc56f-q4tgz:/var/www/html# grep HOST wp-config.php
4define( 'DB_HOST', 'hoge');

上記の変更後、すぐに自動的に Pod が再作成されました。
EVents を見てみると、HTTP ステータスコード 500 が返ってきたことにより、Probe が失敗したあと、コンテナの再作成が行われていることがわかります。
Pod はマニュフェストから再作成されますので、当然、wp-config.php も元の正しい設定になっています。

1rworks@Azure:~$ kubectl get pod
2NAME                         READY   STATUS    RESTARTS   AGE
3wordpress-69b76dc56f-5srbh   1/1     Running   0          5m28s
4wordpress-69b76dc56f-q4tgz   1/1     Running   1          5m33s   # ← RESTART がカウントアップしています
5 
6 
7rworks@Azure:~$ kubectl describe pod wordpress-69b76dc56f-q4tgz
8[省略]
9  
10Events:
11  Type     Reason     Age                 From                                        Message
12  ----     ------     ----                ----                                        -------
13  Normal   Scheduled  2m10s               default-scheduler                           Successfully assigned default/wordpress-69b76dc56f-q4tgz to aks-agentpool-23520908-vmss000000
14  Warning  Unhealthy  20s (x3 over 40s)   kubelet, aks-agentpool-23520908-vmss000000  Liveness probe failed: HTTP probe failed with statuscode: 500
15  Normal   Killing    20s                 kubelet, aks-agentpool-23520908-vmss000000  Container wordpress failed liveness probe, will be restarted
16  Normal   Pulling    18s (x2 over 2m8s)  kubelet, aks-agentpool-23520908-vmss000000  Pulling image "rworks.azurecr.io/wordpress:v1"
17  Normal   Pulled     18s (x2 over 2m6s)  kubelet, aks-agentpool-23520908-vmss000000  Successfully pulled image "rworks.azurecr.io/wordpress:v1"
18  Normal   Created    17s (x2 over 2m6s)  kubelet, aks-agentpool-23520908-vmss000000  Created container wordpress
19  Normal   Started    17s (x2 over 2m5s)  kubelet, aks-agentpool-23520908-vmss000000  Started container wordpress

このように、Kubernetes は障害発生時に自動で復旧することが分かりました。
これにより、常にマニュフェストで定義したとおりの状態が保たれます。

スケールイン、スケールアウト

Pod のスケールイン、スケールアウトは簡単です。
deployment.yaml の replicass の値を変更するだけです。

1spec:
2  #replicas: 2
3  replicas: 4

deployment を更新します。

1rworks@Azure:~$ kubectl apply -f deployment.yaml
2deployment.apps/wordpress configured

Pod が倍になりました。

1rworks@Azure:~$ kubectl get pod
2NAME                        READY   STATUS    RESTARTS   AGE
3wordpress-f6997b7bc-4fdzt   1/1     Running   0          7s
4wordpress-f6997b7bc-6ttrn   1/1     Running   0          7s
5wordpress-f6997b7bc-7tqnv   1/1     Running   0          15m
6wordpress-f6997b7bc-q4jth   1/1     Running   1          15m

今回は手動で Pod の数を調整しましたが、オートスケール設定を行うことも可能です。

まとめ

コンテナの運用する際にポイントとなる、3つの機能について見てみました。
このように、Kubernetes はコンテナの運用を行う上での強力なツールとなることが分かっていただけたのではないでしょうか。
実際に本番環境にて運用する際には、さらに細かい調整が必要になりますが、一連のブログで「Kubernetes とは何なのか」「Kubernetes では何が出来るのか」をいただき、Kubernetes 利用の手助けになれば幸いです。

システム運用個別相談会(無料)

Tag: コンテナ Kubernetes

Contactお問い合わせ

お見積もり・ご相談など、お気軽にお問い合わせください。

single.php