こんにちは、サイオステクノロジー技術部 武井(Twitter:@noriyukitakei)です。今回は、超低予算で実現する本格的WordPress環境 on Azure Kubernetes Serviceについてお話したいと思います。
実はこの記事が公開される日に、今回ご紹介するWordPress on Azure Kubernetes Service環境にこのブログを移行しております。
今回ご紹介するのは、その名の通り、WordPressをAzure Kubernetes Service上で構築しました。そしてなるべくたくさんの機能を低予算で実現してみました。
では早速システム構成からご説明致します。
- 1 システム構成
-
2
構築しよう!!
- 2.1 Azure Container Registryの構築
- 2.2 Azure Kubernetes Serviceの構築
- 2.3 ノードプールの追加
- 2.4 Azure Database for MySQLの構築
- 2.5 SendGridの構築
- 2.6 WordPressのDockerイメージの修正
- 2.7 NFS Server on VMの構築
- 2.8 PersistentVolumeリソースの作成
- 2.9 PersistentVolumeClaimリソースの作成
- 2.10 ヘルスチェックスクリプトの作成
- 2.11 Sercretリソースの作成
- 2.12 Nodeにラベルを付与
- 2.13 Deploymentリソースの作成
- 2.14 NGINX Ingressの作成
- 2.15 データ移行
- 2.16 動作確認
- 3 気になるお値段は?
- 4 まとめ
システム構成
今回構築したシステムの構成図は以下のとおりです(図が細かいのでクリックして拡大して見てください)。
弊社は以下の2つのブログを運用しており、今回この2つのブログを移行する必要がありました。
- SIOS Tech.lab (https://tech-lab.sios.jp/) → 技術情報全般のブログ(本ブログです)
- OSS on Azure (https://azure.sios.jp/) → Azureに特化したブログ
以前はそれぞれ別々のVirtual Machineで稼働していましたが、今回一つのKubernetesクラスターに統合しました。
構成をざっくりご説明しますと、フロントエンド用Node、バックエンド用Nodeと言われるNodeがそれぞれ2台ずつあり、NGINX IngressでL7ロードバランシングしています。フロントエンド用Nodeには負荷の低い静的HTML参照の処理を格安のBシリーズのVMで、バックエンド用Nodeには負荷の高い管理画面系の処理をFシリーズのコンピュート優先のちょっとお高めのVMで処理しています。メールの送信にはSendGrid、画像やプラグインなどのコンテンツ保存にはNFS Server on VM、データベースにはAzure Database for MySQLを使っております。ご覧のとおり、(ほぼ)フルマネージドな環境となっております。
では、それぞれの機能を詳細にご説明してまいります。
Azure kubernetes Service
言わずとしれた、Azureが提供するKubernetesのマネージドサービです。今回は2つのノードプールを作成し、それぞれフロントエンド用Node、バックエンド用Nodeと呼ばれるものがプール内で稼働しております。
フロントエンド用Nodeは静的なHTML参照などの負荷の低い処理を行います。今回、WordPressのプラグインの一つである「WP Super Cache」というものを使っており、一度ユーザーが参照したものは次回からは静的なHTMLを参照するようにしております。これは比較的負荷の軽い処理であり、これをフロントエンド用Nodeが担当します。このNodeにはBシリーズといわれる、あんまり性能は高くないけど安いVMを使っています。正確なインスタンスサイズはB2sであり、2020年1月9日現在(東日本リージョン)のお値段は、4,538円/月です。
バックエンド用Nodeは、管理画面でブログを作成する処理を担当します。これはPHPで動作しますので、比較的処理が重いものであり、このNodeには、ちょっとお高めだけど高性能なFシリーズのVMを使っております。正確なインスタンスサイズはF2s_v2であり、2020年1月9日現在(東日本リージョン)のお値段は、8,928円です。
フロントエンド用Node、バックエンド用Nodeの振り分けはL7ロードバランサーであるNGINX Ingressで行い、URLで振り分けをしております。/wp-admin(管理画面のロケーション)以下のアクセスはバックエンド用Node、それ以外はフロントエンド用Nodeに振り分けています。ついでにNGINX IngressでSSLの終端も行っています。
NGINX Ingress用のPodはフロントエンド用Nodeにそれぞれ1台ずつ配置されており、その前段にAzure Load Balancerが稼働しており、2台のNGINX Ingress用のPodにL4でロードバランシングしています。こちらについての詳細はAzure Kubernetes ServiceでNGINX Ingressによる負荷分散というブログに記載しております。
Azure Container Registry
Azureが提供するDockerイメージ用のプライベートリポジトリです。もちろんマネージドサービです。今回、Docker Hubで提供されているWordPressの公式イメージをそのまま使いたかったのですが、若干修正しなければいけないところがあり、その修正したイメージをAzure Container Registryに格納しております。
NFS Server on VM
WordPressの画像やプラグインは動的に変化するコンテンツですので、何らかの共有ストレージに格納して各Podから参照させる必要があります。
Azure Kubernetes Serviceで利用できるものは以下の3つがあります。
最初は1を試しました。Azure Filesは、Azureで利用できるマネージドなファイルサーバーであり、SMBプロトコルを介して通信できます。なので、Windowsからでも簡単にマウント出来て非常に便利です。マネージドなので、仮想マシンにsambaサーバー立てたときのように、面倒くさい管理も不要です。
が、Azure Filesを使ったらなぜかWordPressが激オソになりました。どうやら大量の細かいPHPファイルを読み込むのに時間がかかっていたようです。SMBというプロトコルのせいもあるのでしょうか?1ページ読み込むのに8秒くらいかかっていたので、使いものにならなく断念しました。
次に2を試しました。言わずとしれたNFSです。これで激オソが解消されて、激ハヤになりました。プロトコルの違いなのか、それとも他に原因があるのか、詳細はわかってはいないのですが、ほっと胸をなでおろしましたε-(´∀`*)ホッ
しかし、やっぱり今の時代VM使ったら負けみたいな風潮もあるようなないような感じですし、他にマネージドなストレージサービスないかなーと探していたところ、3に行き着きました。東日本リージョンで使える様になったのはつい最近のことらしいので、マジでいいタイミングでした。ただし、めちゃくちゃ料金が高いです(T_T)こんなの払いきれません。
ということで結局2に落ち着きました。これが、「タイトルの(ほぼ)フルマネージド」の「ほぼ」が取れない所以です。ここもマネージドにできたら完璧だったのにー。
このストレージには、SIOS Tech.lab (https://tech-lab.sios.jp/)とOSS on Azure (https://azure.sios.jp/)の2つのブログのコンテンツを格納して、それぞれのPodからマウントしています。図にしますと以下のようになります。
WordPressは画像などのコンテンツはwp-contentディレクトリに格納する仕様になっています。今回は2つのブログがあるので、NFS Server on VM上に作成しがボリュームにtechlab、ossonazという2つのディレクトリを作成して、SIOS Tech.lab (https://tech-lab.sios.jp/)用のPod、OSS on Azure (https://azure.sios.jp/)用のPodからそれぞれをNFSマウントします。
VMのインスタンスサイズはB2sにしておりまして、2020年1月9日現在(東日本リージョン)のお値段は、4,129円/月くらいになります。
Azure Database for MySQL
言わずと知れた、Azureが提供するMySQLのマネージドなサービスです。WordPress用のデータベースとして使っています。ユーザーのブログ参照は先程ご説明したようにキャッシュプラグインを使いますので、静的なHTMLにアクセスすることになります。つまりデータベースへのアクセスが発生するのは管理画面での作業のみです。おそらくあんまりデータベースへのアクセスは発生しません。よって、一番価格の低いBasicの1 vCoreにしております。お値段は、4337円/月です。
Azure Database for MySQLの中には2つのデータベースを構築しており、それぞれSIOS Tech.lab (https://tech-lab.sios.jp/)用とOSS on Azure (https://azure.sios.jp/)用になります。
SendGrid
Azureが提供するメール送信のためのマネージドサービです。Freeでも25,000通/月のメールが送れますので、Freeにしています。なので、お値段は0円です。
構築しよう!!
先程ご紹介した環境の構築方法をご説明致します。今後の手順でご紹介するリソースグループ名を始めとした各種名称は、適宜、ご自身の環境に合わせて修正してくださいませ。
Azure Container Registryの構築
まずはKubernetesがコンテナを作成するためのイメージを持ってくるレジストリを作成します。通常はDockerHubなどの公開レポジトリを使うのではなく、クローズドなレポジトリを使います。Azure Container Registryはそんなクローズドなレポジトリを提供してくれます。
Azureポータルにアクセスして、「リソースの作成」をクリックします。
「container」と入力すると、「Container Registry」が表示されますので、それをクリックします。
「作成」をクリックします。
「レジストリ名」はレジストリを一意に識別する任意の名称を入力します。後ほどこの値は、レジストリのホスト名の一部になりますので、よく考えて変な名前をつけないようにしましょう。「管理者ユーザー」は有効にしておいて下さい。詳細は後ほど説明します。SKUはとりあえず「Standard」にして下さい。後は、環境に合わせて適宜入力して、最後に「作成」をクリックします。
Azure Container Registryのリソースの作成が完了したら、左部メニューの「アクセスキー」をクリックして、「ログインサーバー」「ユーザー名」「パスワード(2つあるうちのいずれか)」をメモして下さい。ちなみにこのユーザーはテスト用に利用する管理用ユーザーです。本番用途では別途サービスプリンシパルを作成して、適切な権限(Azure Container Registryへの読み取り権限のみ)を割り当てて下さい。
Azure Kubernetes Serviceの構築
では、いよいよAzure Kubernetes Serviceの構築です。
Azureポータルにアクセスして、「リソースの作成」をクリックします。
「Kubernetes」と入力すると「Kubernetes Service」が表示されますので、クリックします。
「作成」をクリックします。
「クラスター名」はKubernetesクラスターを一意に識別する任意の名称を入力して下さい。「ノードサイズ」は、コンテナが稼働するNodeの仮想マシンのサイズです。なるべくサイズの小さいのを選んでおいたほうがお財布に優しいです。検証用ですし。後はご自分の環境に合わせて適宜入力して、最後に「確認および作成」をクリックします。
入力項目を確認して「作成」をクリックします。しばらくかかるので、気長に待ちましょう。
kubectlコマンドをインストールします。その前にまず、Azure CLIをインストールしましょう。Macを想定しております。他の環境はここを参考にインストールしてくらはい。
$ brew update && brew install azure-cli
次にkubectlをインストールします。
$ az aks install-cli
kubectlコマンドを動かすための認証情報を作成します。noriaksはAzure Kubernetes Serviceを作成したリソースグループ、norichan-aksはKubernetesクラスター名です。
$ az aks get-credentials --resource-group noriaks --name norichan-aks
これで準備は整いました。
ノードプールの追加
フロントエンド用Nodeはキャッシュされた静的なHTMLを処理するだけですので低価格のVMで、バックエンド用Nodeは管理画面での投稿処理などの高負荷な処理を行うので高価格・高性能なVMを使うと先程ご説明致しました。
ノードごとのインスタンスサイズの使い分けはAzure Kubernetes Serviceのノードプールという機能を使います。ノードプール単位でVMのインスタンスサイズを指定することが出来ます。イメージとしては以下の図みたいな感じです。
まず、Azure Kubernetes Serviceのポータルのトップ画面の左部メニューで「ノードプール」をクリックします。
「ノードプールの追加」をクリックします。
「ノードプール名」に任意の名称、「OSの種類」はLinux、「Kubernetesバージョン」は現時点の最新のもの、「ノードサイズ」はF2s_v2、「ノード数」は2として、「追加」をクリックします。
しばらくするとノードが以下のように追加されていることが確認できると思います。
$ kubectl get node NAME STATUS ROLES AGE VERSION aks-agentpool-13063641-vmss000000 Ready agent 18d v1.14.8 aks-agentpool-13063641-vmss000001 Ready agent 18d v1.14.8 aks-wpadminpool-13063641-vmss000000 Ready agent 15d v1.14.8 aks-wpadminpool-13063641-vmss000001 Ready agent 12d v1.14.8
Azure Database for MySQLの構築
Azureポータルにアクセスして、「リソースの作成」をクリックします。
「Azure Database for MySQL」と入力してエンターを押します。
「作成」をクリックします。
サブスクリプション、リソースグループはご利用の環境に応じたものを入力します。「サーバー名」はMySQLのホスト名の一部になりますので、慎重に考えてください^^;「管理者ユーザー名」「パスワード」はそのままMySQLのユーザー名とパスワードになります。「場所」はご利用の環境に近いところ、「バージョン」は5.7を選択してください。そして、「サーバーの構成」をクリックしてください。
「Basic」のタブをクリックしてvCoreを1にしてください。その他は以下のようにデフォルトのままで「OK」をクリックしてください。
先程の画面に戻りますので、「確認および作成」をクリックしてください。
「作成」をクリックして、しばらくすれば完了です\(^o^)/
SendGridの構築
Azureポータルにアクセスして、「リソースの作成」をクリックします。
「SendGrid」と入力してエンターを押します。
「作成」をクリックします。
サブスクリプション、リソースグループ、場所はご利用の環境に応じたものを入力します。「Name」「Password」はSendGridポータルへのログインIDとパスワードになります。「Pricing Tier」は「Free」を選択してください。「Contact details」は名前や会社名などを入力してください。最後に「Review + Create」をクリックします。
内容を確認して「Create」をクリックすれば完了です\(^o^)/
WordPressのDockerイメージの修正
今回の構築に用いるWordPressのDockerイメージは以下のような構成になっております。
今回はwp-content配下をNFS Server on VMにマウントする予定なのですが、どうやらWordPressのDockerイメージは、Docker起動時に実行されるエントリポイントdocker-entrypoint.shにより、wp-content配下にあるいくつかのプラグインやPHPファイルを上書きしてしまうということが発覚しました。docker-entrypoint.sh実行よりも、wp-contentへのNFS Server on VMのマウントを遅らせることができればいいのですが、そんなことはできそうもないので、docker-entrypoint.shを書き換えることとしました。
/ └── var └── www └── html → WordPressを動作するためのPHPスクリプトがおいてあるディレクトリ └── wp-content → 画像など記事を構成するコンテンツがおいてあるディレクトリ
ソースコードを読んでいると、どうやらDockerfileによって/usr/src/wordpress配下に解凍されたWordPress本体を、/var/www/htmlに展開し直しているようです。それを行っているのが15行目です。なので15行目で展開される前にwp-content配下のファイルをすべて消してしまえばいいのです。
sourceTarArgs=( --create --file - --directory /usr/src/wordpress --owner "$user" --group "$group" ) targetTarArgs=( --extract --file - ) if [ "$user" != '0' ]; then # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" targetTarArgs+=( --no-overwrite-dir ) fi tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}"
なので、16行目を追加しました。
sourceTarArgs=( --create --file - --directory /usr/src/wordpress --owner "$user" --group "$group" ) targetTarArgs=( --extract --file - ) if [ "$user" != '0' ]; then # avoid "tar: .: Cannot utime: Operation not permitted" and "tar: .: Cannot change mode to rwxr-xr-x: Operation not permitted" targetTarArgs+=( --no-overwrite-dir ) fi # これを追加してwp-contentを削除して上書きされるのを防ぐ rm -rf /usr/src/wordpress/wp-content tar "${sourceTarArgs[@]}" . | tar "${targetTarArgs[@]}"
こちらでDockerイメージを作成し直して、Azure Container Registryへプッシュします。
NFS Server on VMの構築
VM上にNFS Serverを構築します。VMの構築の仕方は割愛します。ほぼ、Azure Kubernetes Serviceでの共有ストレージ(NFS Server on VM編)のブログに記載のとおりに構築しております。
#!/bin/bash # This script should be executed on Linux Ubuntu Virtual Machine EXPORT_DIRECTORY=${1:-/export/data} DATA_DIRECTORY=${2:-/data} AKS_SUBNET=${3:-*} echo "Updating packages" apt-get -y update echo "Installing NFS kernel server" apt-get -y install nfs-kernel-server echo "Making data directory ${DATA_DIRECTORY}" mkdir -p ${DATA_DIRECTORY} echo "Making new directory to be exported and linked to data directory: ${EXPORT_DIRECTORY}" mkdir -p ${EXPORT_DIRECTORY} echo "Mount binding ${DATA_DIRECTORY} to ${EXPORT_DIRECTORY}" mount --bind ${DATA_DIRECTORY} ${EXPORT_DIRECTORY} echo "Giving 777 permissions to ${EXPORT_DIRECTORY} directory" chmod 777 ${EXPORT_DIRECTORY} parentdir="$(dirname "$EXPORT_DIRECTORY")" echo "Giving 777 permissions to parent: ${parentdir} directory" chmod 777 $parentdir echo "Appending bound directories into fstab" echo "${DATA_DIRECTORY} ${EXPORT_DIRECTORY} none bind 0 0" >> /etc/fstab echo "Appending localhost and Kubernetes subnet address ${AKS_SUBNET} to exports configuration file" echo "/export ${AKS_SUBNET}(rw,async,insecure,fsid=0,crossmnt,no_subtree_check,all_squash)" >> /etc/exports echo "/export localhost(rw,async,insecure,fsid=0,crossmnt,no_subtree_check)" >> /etc/exports nohup service nfs-kernel-server restart
PersistentVolumeリソースの作成
PersistentVolumeのマニフェストを以下のように作成します。
apiVersion: v1 kind: PersistentVolume metadata: name: techblog-pv labels: type: nfs spec: capacity: storage: 100Gi accessModes: - ReadWriteMany nfs: # 先程構築したNFSサーバーのIPアドレスを指定します。 server: XXX.XXX.XXX.XXX # 先のスクリプトで指定した3つ目の引数のDATA_DIRECTORYを指定します。 path: /data
適用します。
$ kubectl apply -f pv.yml
PersistentVolumeClaimリソースの作成
PersistentVolumeClaimのマニフェストを以下のように作成します。
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: techblog-pvc spec: accessModes: - ReadWriteMany # storageClassNameは必ず空にします。 storageClassName: "" resources: requests: storage: 100Gi selector: matchLabels: type: nfs
適用します。
$ kubectl apply -f pvc.yml
ヘルスチェックスクリプトの作成
Kubernetesの死活監視(LivenessProbe&ReadinessProbe)のためにヘルスチェックスクリプトを作成します。WordPressはMySQLに接続できないと機能しないので、ヘルスチェックにはMySQLに対して簡単なクエリを投げて成功すれば200、失敗すれば500のHTTPステータスコードを返すようにします。
<?php require_once('/var/www/html/wp-load.php'); global $wpdb; $result = $wpdb->get_col('select 1 as val'); if ($result[0] == 1) { https_response_code(200); } else { https_response_code(500); } ?>
完成したらwp-contentディレクトリ直下に配置します。
Sercretリソースの作成
WordPressの設定に必要な項目の中で、「データベースへ接続するパスワード」「各種SALT値」を格納したSecretリソースを作成します。
apiVersion: v1 kind: Secret metadata: name: techblog-secret type: Opaque data: WORDPRESS_DB_PASSWORD: XXXXXX WORDPRESS_AUTH_KEY: XXXXXX WORDPRESS_SECURE_AUTH_KEY: XXXXXX WORDPRESS_LOGGED_IN_KEY: XXXXXX WORDPRESS_NONCE_KEY: XXXXXX WORDPRESS_AUTH_SALT: XXXXXX WORDPRESS_SECURE_AUTH_SALT: XXXXXX WORDPRESS_LOGGED_IN_SALT: XXXXXX WORDPRESS_NONCE_SALT: XXXXXX
適用します。
$ kubectl apply -f secret.yml
Nodeにラベルを付与
フロントエンド用Node、バックエンド用NodeにそれぞれWordPress用のPodを1個ずつ割り当てます。そのためにAffinityを使います。Nodeにラベルを付与して、Podをデプロイするときに特定のラベルが付与されたNodeにスケジューリングするようにします。
まずNodeの情報を取得します。下記のように4つのNodeが表示されます。
$ kubectl get node NAME STATUS ROLES AGE VERSION aks-agentpool-13063641-vmss000000 Ready agent 18d v1.14.8 aks-agentpool-13063641-vmss000001 Ready agent 18d v1.14.8 aks-wpadminpool-13063641-vmss000000 Ready agent 14d v1.14.8 aks-wpadminpool-13063641-vmss000001 Ready agent 11d v1.14.8
フロントエンド用Nodeにuser、バックエンド用Nodeにadminというラベルを付与します。
$ kubectl label node/aks-agentpool-13063641-vmss000000 env=user $ kubectl label node/aks-agentpool-13063641-vmss000001 env=user $ kubectl label node/aks-wpadminpool-13063641-vmss000000 env=admin $ kubectl label node/aks-wpadminpool-13063641-vmss000001 env=admin
Deploymentリソースの作成
SIOS Tech.lab (https://tech-lab.sios.jp/)のブログページ(下図(1))と管理画面(下図(3))、OSS on Azure (https://azure.sios.jp/)のブログページ(下図(2)と管理画面(下図(4))を構成するDeploymentリソースを作成する必要があります。
まず(1)SIOS Tech.lab (https://tech-lab.sios.jp/)のブログページを作成するためのマニフェストを以下のように定義します。
apiVersion: apps/v1beta1 kind: Deployment metadata: name: techlab-user spec: replicas: 2 selector: matchLabels: app: techlab-user # ローリングアップデートする際、次のPodの更新に移るまでの間隔を指定する。 minReadySeconds: 60 # デプロイのタイムアウトで、この時間過ぎてもデプロイが成功しなければ中止する。 progressDeadlineSeconds: 600 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: techlab-user spec: # https://tech-lab.sios.jp/archives/18730を参照 terminationGracePeriodSeconds: 40 containers: - name: wordpress # 先程Azure Container RegistryにプッシュしたWordPressのイメージを指定する。 image: XXXXXX.azurecr.io/techblog/wordpress:php7.4 ports: - containerPort: 80 env: - name: WORDPRESS_DB_HOST value: "XXXXXX.mysql.database.azure.com" - name: WORDPRESS_DB_USER value: "siosadmin@techblog-db" # Secretリソースに登録したデータベースのパスワードを環境変数に格納する。 - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_DB_PASSWORD - name: WORDPRESS_DB_NAME value: "techlab" # Secretリソースに登録したSALT値等をを環境変数に格納する。以下すべて同じ。 - name: WORDPRESS_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_KEY - name: WORDPRESS_SECURE_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_KEY - name: WORDPRESS_LOGGED_IN_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_KEY - name: WORDPRESS_NONCE_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_KEY - name: WORDPRESS_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_SALT - name: WORDPRESS_SECURE_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_SALT - name: WORDPRESS_LOGGED_IN_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_SALT - name: WORDPRESS_NONCE_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_SALT - name: WORDPRESS_CONFIG_EXTRA value: | # MySQLにSSLで接続するための設定を定義する。 define('MYSQL_CLIENT_FLAGS',MYSQLI_CLIENT_SSL); # WP Super Cacheプラグインのキャッシュファイル格納先を指定する。 define( 'WPCACHEHOME', '/var/www/html/wp-content/plugins/wp-super-cache/' ); define('WP_CACHE', true); lifecycle: preStop: exec: # https://tech-lab.sios.jp/archives/18730を参照 # 確実にRollingUpdateを行うためにApacheをGracefulにShutdownする。 command: ["sh", "-c", "sleep 3; apachectl -k graceful-stop; sleep 30"] # ヘルスチェック用の定義をする。 livenessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 # Podがサービスインする準備ができているかどうかをチェックする。 readinessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 resources: limits: memory: "500Mi" requests: memory: "500Mi" # NFS Serverで作成したボリュームをマウントする。 volumeMounts: - name: techblog-vlm mountPath: /var/www/html/wp-content # subPathを切って、NFS Serverのボリューム上に作成されたtechlabディレクトリをマウントする。 subPath: techlab # Azure Container Registryからイメージをpullするためのシークレットをs定義する。 imagePullSecrets: - name: techblogacr-credential volumes: - name: techblog-vlm persistentVolumeClaim: claimName: techblog-pvc # env=userというラベルが付与されたNode(フロントエンド用Node)にPodをスケジューリングする。 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: env operator: In values: - user
次に(3)SIOS Tech.lab (https://tech-lab.sios.jp/)の管理画面を作成するためのマニフェストを以下のように定義します。
apiVersion: apps/v1beta1 kind: Deployment metadata: name: techlab-admin spec: replicas: 2 selector: matchLabels: app: techlab-admin # ローリングアップデートする際、次のPodの更新に移るまでの間隔を指定する。 minReadySeconds: 60 # デプロイのタイムアウトで、この時間過ぎてもデプロイが成功しなければ中止する。 progressDeadlineSeconds: 600 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: techlab-admin spec: # https://tech-lab.sios.jp/archives/18730を参照 terminationGracePeriodSeconds: 40 containers: - name: wordpress # 先程Azure Container RegistryにプッシュしたWordPressのイメージを指定する。 image: XXXXXX.azurecr.io/techblog/wordpress:php7.4 ports: - containerPort: 80 env: - name: WORDPRESS_DB_HOST value: "techblog-db.mysql.database.azure.com" - name: WORDPRESS_DB_USER value: "siosadmin@techblog-db" # Secretリソースに登録したデータベースのパスワードを環境変数に格納する。 - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_DB_PASSWORD - name: WORDPRESS_DB_NAME value: "techlab" # Secretリソースに登録したSALT値等をを環境変数に格納する。以下すべて同じ。 - name: WORDPRESS_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_KEY - name: WORDPRESS_SECURE_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_KEY - name: WORDPRESS_LOGGED_IN_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_KEY - name: WORDPRESS_NONCE_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_KEY - name: WORDPRESS_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_SALT - name: WORDPRESS_SECURE_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_SALT - name: WORDPRESS_LOGGED_IN_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_SALT - name: WORDPRESS_NONCE_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_SALT - name: WORDPRESS_CONFIG_EXTRA value: | # MySQLにSSLで接続するための設定を定義する。 define('MYSQL_CLIENT_FLAGS',MYSQLI_CLIENT_SSL); # WP Super Cacheプラグインのキャッシュファイル格納先を指定する。 define( 'WPCACHEHOME', '/var/www/html/wp-content/plugins/wp-super-cache/' ); define('WP_CACHE', true); lifecycle: preStop: exec: # https://tech-lab.sios.jp/archives/18730を参照 # 確実にRollingUpdateを行うためにApacheをGracefulにShutdownする。 command: ["sh", "-c", "sleep 3; apachectl -k graceful-stop; sleep 30"] # ヘルスチェック用の定義をする。 livenessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 # Podがサービスインする準備ができているかどうかをチェックする。 readinessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 resources: limits: memory: "500Mi" requests: memory: "500Mi" # NFS Serverで作成したボリュームをマウントする。 volumeMounts: - name: techblog-vlm mountPath: /var/www/html/wp-content # subPathを切って、NFS Serverのボリューム上に作成されたtechlabディレクトリをマウントする。 subPath: techlab # Azure Container Registryからイメージをpullするためのシークレットをs定義する。 imagePullSecrets: - name: techblogacr-credential volumes: - name: techblog-vlm persistentVolumeClaim: claimName: techblog-pvc # env=adminというラベルが付与されたNode(バックエンド用Node)にPodをスケジューリングする。 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: env operator: In values: - admin
次に(2)OSS on Azure (https://azure.sios.jp/)のブログページを作成するためのマニフェストを以下のように定義します。
apiVersion: apps/v1beta1 kind: Deployment metadata: name: ossonaz-user spec: replicas: 2 selector: matchLabels: app: ossonaz-user # ローリングアップデートする際、次のPodの更新に移るまでの間隔を指定する。 minReadySeconds: 60 # デプロイのタイムアウトで、この時間過ぎてもデプロイが成功しなければ中止する。 progressDeadlineSeconds: 600 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: ossonaz-user spec: # https://tech-lab.sios.jp/archives/18730を参照 terminationGracePeriodSeconds: 40 containers: - name: wordpress # 先程Azure Container RegistryにプッシュしたWordPressのイメージを指定する。 image: XXXXXX.azurecr.io/techblog/wordpress:php7.4 ports: - containerPort: 80 env: - name: WORDPRESS_DB_HOST value: "techblog-db.mysql.database.azure.com" - name: WORDPRESS_DB_USER value: "siosadmin@techblog-db" # Secretリソースに登録したデータベースのパスワードを環境変数に格納する。 - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_DB_PASSWORD - name: WORDPRESS_DB_NAME value: "ossonaz" # Secretリソースに登録したSALT値等をを環境変数に格納する。以下すべて同じ。 - name: WORDPRESS_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_KEY - name: WORDPRESS_SECURE_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_KEY - name: WORDPRESS_LOGGED_IN_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_KEY - name: WORDPRESS_NONCE_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_KEY - name: WORDPRESS_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_SALT - name: WORDPRESS_SECURE_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_SALT - name: WORDPRESS_LOGGED_IN_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_SALT - name: WORDPRESS_NONCE_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_SALT - name: WORDPRESS_CONFIG_EXTRA value: | define('MYSQL_CLIENT_FLAGS',MYSQLI_CLIENT_SSL); lifecycle: preStop: exec: # https://tech-lab.sios.jp/archives/18730を参照 # 確実にRollingUpdateを行うためにApacheをGracefulにShutdownする。 command: ["sh", "-c", "sleep 3; apachectl -k graceful-stop; sleep 30"] # ヘルスチェック用の定義をする。 livenessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 # Podがサービスインする準備ができているかどうかをチェックする。 readinessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 resources: limits: memory: "500Mi" requests: memory: "500Mi" # NFS Serverで作成したボリュームをマウントする。 volumeMounts: - name: techblog-vlm mountPath: /var/www/html/wp-content # subPathを切って、NFS Serverのボリューム上に作成されたossonazディレクトリをマウントする。 subPath: ossonaz # Azure Container Registryからイメージをpullするためのシークレットを定義する。 imagePullSecrets: - name: techblogacr-credential volumes: - name: techblog-vlm persistentVolumeClaim: claimName: techblog-pvc # env=userというラベルが付与されたNode(フロントエンド用Node)にPodをスケジューリングする。 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: env operator: In values: - user
次に(4)OSS on Azure (https://azure.sios.jp/)の管理画面を作成するためのマニフェストを以下のように定義します。
apiVersion: apps/v1beta1 kind: Deployment metadata: name: ossonaz-admin spec: replicas: 2 selector: matchLabels: app: ossonaz-admin # ローリングアップデートする際、次のPodの更新に移るまでの間隔を指定する。 minReadySeconds: 60 # デプロイのタイムアウトで、この時間過ぎてもデプロイが成功しなければ中止する。 progressDeadlineSeconds: 600 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 template: metadata: labels: app: ossonaz-admin spec: # https://tech-lab.sios.jp/archives/18730を参照 terminationGracePeriodSeconds: 40 containers: - name: wordpress # 先程Azure Container RegistryにプッシュしたWordPressのイメージを指定する。 image: XXXXXX.azurecr.io/techblog/wordpress:php7.4 ports: - containerPort: 80 env: - name: WORDPRESS_DB_HOST value: "techblog-db.mysql.database.azure.com" - name: WORDPRESS_DB_USER value: "siosadmin@techblog-db" # Secretリソースに登録したデータベースのパスワードを環境変数に格納する。 - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_DB_PASSWORD - name: WORDPRESS_DB_NAME value: "ossonaz" # Secretリソースに登録したSALT値等をを環境変数に格納する。以下すべて同じ。 - name: WORDPRESS_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_KEY - name: WORDPRESS_SECURE_AUTH_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_KEY - name: WORDPRESS_LOGGED_IN_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_KEY - name: WORDPRESS_NONCE_KEY valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_KEY - name: WORDPRESS_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_AUTH_SALT - name: WORDPRESS_SECURE_AUTH_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_SECURE_AUTH_SALT - name: WORDPRESS_LOGGED_IN_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_LOGGED_IN_SALT - name: WORDPRESS_NONCE_SALT valueFrom: secretKeyRef: name: techblog-secret key: WORDPRESS_NONCE_SALT - name: WORDPRESS_CONFIG_EXTRA value: | # MySQLにSSLで接続するための設定を定義する。 define('MYSQL_CLIENT_FLAGS',MYSQLI_CLIENT_SSL); lifecycle: preStop: exec: # https://tech-lab.sios.jp/archives/18730を参照 # 確実にRollingUpdateを行うためにApacheをGracefulにShutdownする。 command: ["sh", "-c", "sleep 3; apachectl -k graceful-stop; sleep 30"] # ヘルスチェック用の定義をする。 livenessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 # Podがサービスインする準備ができているかどうかをチェックする。 readinessProbe: httpsGet: # 自前で作成したヘルスチェック用のPHPを指定する。 path: /wp-content/healthcheck.php port: 80 scheme: HTTP # 何故かMySQLへのSSL接続が安定するまで時間かかるので、ヘルスチェック開始を4分ほど遅らせる。 initialDelaySeconds: 240 timeoutSeconds: 5 periodSeconds: 10 failureThreshold: 5 resources: limits: memory: "500Mi" requests: memory: "500Mi" # NFS Serverで作成したボリュームをマウントする。 volumeMounts: - name: techblog-vlm mountPath: /var/www/html/wp-content # subPathを切って、NFS Serverのボリューム上に作成されたossonazディレクトリをマウントする。 subPath: ossonaz # Azure Container Registryからイメージをpullするためのシークレットを定義する。 imagePullSecrets: - name: techblogacr-credential volumes: - name: techblog-vlm persistentVolumeClaim: claimName: techblog-pvc # env=adminというラベルが付与されたNode(バックエンド用Node)にPodをスケジューリングする。 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: env operator: In values: - admin
作成したマニフェストを適用します。
$ kubectl apply -f deployment-techlab-user.yml $ kubectl apply -f deployment-techlab-admin.yml $ kubectl apply -f deployment-ossonaz-user.yml $ kubectl apply -f deployment-ossonaz-admin.yml
NGINX Ingressの作成
NGINX Ingressを作成します。基本的には「Azure Kubernetes ServiceでNGINX Ingressによる負荷分散」でご紹介したとおりに進めます。
まずAzure Load Balancerに割り当てるパブリックIPアドレスを作成します。
$ az network public-ip create --resource-group [MCから始まるリソースグループ名] \
--name techblogPublicIP --sku Standard --allocation-method static \
--query publicIp.ipAddress -o tsv
次にHelmをインストールします。ワタクシMacな環境なのでMac前提にお話します。バージョン3からTillerがいらなくなりました。やった(^o^)
$ brew install helm
Helmの公式レポジトリを追加します。
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
次にNGINX IngressのPodを格納するNamespaceを作成します。
$ kubectl create namespace techblog-nginx
HelmでNGINX Ingressを作成します。
$ helm install stable/nginx-ingress \ --namespace techblog-nginx \ --set controller.replicaCount=2 \ --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux \ --set controller.service.externalTrafficPolicy=Local \ --set controller.service.loadBalancerIP="[先程取得したPublicIP]" \ --generate-name
–set controller.replicaCount=2は、NGINX IngressのPodを何個作るかを指定します。必ず2個以上として下さい。1個しか作らないと、万が一そのPodが落ちると、サービスがダウンしてしまいます。
Serviceを見てみます。
$ kubectl get service --namespace techblog-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-1577021421-controller LoadBalancer 10.0.186.183 52.155.119.106 80:32390/TCP,443:32752/TCP 18d nginx-ingress-1577021421-default-backend ClusterIP 10.0.246.135 <none> 80/TCP 18d 43h
nginx-ingress-1577021421-controllerは先程の図のAzure Load Balancerのリソースです。もう一つのnginx-nginx-ingress-1577021421-default-backendは、後述する負荷分散ルールを定義するマニフェストに定義したパスのどれにも該当しないときに振られるService(ClusterIP)です。Load BalancerにグローバルIPアドレスが割り当てられているのがわかります。このIPアドレスを外部DNSサービスにAレコードとして登録して下さい。
次にNodePortとして公開します(必要なのはClusterIPだけなので、なぜNodePortが必要なのか不明ですが、公式のマニュアルにもそう書いてあります)。SIOS Tech.lab (https://tech-lab.sios.jp/)のブログページと管理画面、OSS on Azure (https://azure.sios.jp/)のブログページと管理画面の合計4つのNodePortを作成します。以下のマニフェストを作成します。
apiVersion: v1 kind: Service metadata: name: techlab-user-np spec: type: NodePort ports: - name: "https-port" protocol: "TCP" port: 80 targetPort: 80 selector: app: techlab-user --- apiVersion: v1 kind: Service metadata: name: techlab-admin-np spec: type: NodePort ports: - name: "https-port" protocol: "TCP" port: 80 targetPort: 80 selector: app: techlab-admin --- apiVersion: v1 kind: Service metadata: name: ossonaz-user-np spec: type: NodePort ports: - name: "https-port" protocol: "TCP" port: 80 targetPort: 80 selector: app: ossonaz-user --- apiVersion: v1 kind: Service metadata: name: ossonaz-admin-np spec: type: NodePort ports: - name: "https-port" protocol: "TCP" port: 80 targetPort: 80 selector: app: ossonaz-admin
作成したマニフェストを適用します。
$ kubectl apply -f nodeport.yml
IngressでSSL終端するための証明書と秘密鍵を格納します。server.crtを証明書、server.keyを秘密鍵とします。
$ kubectl create secret tls siosjp-tls --key server.key --cert server.crt
以下のマニフェストを作成します。Ingressによる負荷分散ルールを定義するためのものです。ingress.ymlというファイル名で保存します。
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx name: techblog-ingress-nginx spec: rules: - host: tech-lab.sios.jp https: paths: # SIOS Tech.lab (https://tech-lab.sios.jp/)のブログページ向けのリクエストを # それ用に作成したNodePortに振ります。 - path: / backend: serviceName: techlab-user-np servicePort: 80 # SIOS Tech.lab (https://tech-lab.sios.jp/)の管理画面向けのリクエストを # それ用に作成したNodePortに振ります。 - path: /wp-admin backend: serviceName: techlab-admin-np servicePort: 80 - host: azure.sios.jp https: paths: # OSS on Azure (https://azure.sios.jp/)のブログページ向けのリクエストを # それ用に作成したNodePortに振ります。 - path: / backend: serviceName: ossonaz-user-np servicePort: 80 # OSS on Azure (https://azure.sios.jp/)の管理画面向けのリクエストを # それ用に作成したNodePortに振ります。 - path: /wp-admin backend: serviceName: ossonaz-admin-np servicePort: 80 # SSL終端するための証明書が格納されたSecertを定義します。 # この構成では、ワイルドカード証明書で2つのサイトを同じ証明書で終端しています。 tls: - secretName: siosjp-tls hosts: - tech-lab.sios.jp - azure.sios.jp
デプロイします。
$ kubectl apply -f ingress.yml
データ移行
旧WordPressから新WordPressにデータ移行を行う必要があります。本記事の本質ではないので詳細は割愛させていただきますが、以下の2つのデータを移行するのみで基本的にはOKです。
- wp-contentディレクトリ配下のファイル
- MySQLのデータベース
WordPressのバージョンアップも今回行ったので、幾つか動かないプラグインもありましたが、、、。
動作確認
SIOS Tech.lab (https://tech-lab.sios.jp/)、OSS on Azure (https://azure.sios.jp/)にアクセスしたら、きちんと表示されました(^o^)管理画面の動作もバッチリでした。
気になるお値段は?
月額のAzure使用料は以下の通りとなります。
フロントエンド用Node | 9,076円/月 (4,538円/月 × 2) |
バックエンド用Node | 17,856円/月 (8,928円/月 × 2) |
Azure Database for MySQL | 4,337円/月 |
NFS Server on VM | 4,129円/月 |
合計 | 35,398円/月 |
これだけの本格的なクラスターで、たったこれだけのお値段って安いですよね\(^o^)/
まとめ
Azure Kubernetes Serviceすごいですね。これだけの本格的なクラスタを(ほぼ)フルマネージドで構築できるんです。No Azure Kubernetes Service、No Life!!ヮ(゚д゚)ォ!