Magento2 on GKE チュートリアル

Meet Magento Japan 2019 で発表した Magento2 on GKE のワークフローを体験できるよう、簡易構成のチュートリアルを用意しました。GKE でどの様にコンテナをホストするかの全体像が理解できます。

## スタートの前に
前提としてローカルから GCP リソースを操作する、gclou コマンドと kubectl コマンドを用意します。以下の GKE 公式クイックスタートの「[gcloud ツールのデフォルトの設定を構成する](https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja#defaults)」まで実施してください。

[クイックスタート  |  Kubernetes Engine のドキュメント  |  Google Cloud](https://cloud.google.com/kubernetes-engine/docs/quickstart?hl=ja)

その後、以下のチュートリアル用リポジトリと、Docker コンテナリポジトリを clone してください。

[kzkick2nd/magento2-gke-tutorial](https://github.com/kzkick2nd/magento2-gke-tutorial)
[kzkick2nd/magento2-on-docker: The simple Magento2 docker-compose kit](https://github.com/kzkick2nd/magento2-on-docker)

## 概要
以下の手順で、役割を分担した Magento2 構成を GKE にデプロイします。長い手順となりますが、一つずつクリアしていきましょう。

- Docker イメージのビルドと GCR へのプッシュ
- GKE クラスタの用意
- GKE 用の Volume 作成
- Helm を利用した NFS と Redis Pod 立ち上げ
- 初期化 Pod の立ち上げ
- Front Pod のデプロイ
- Admin Pod のデプロイ
- Cron Pod のデプロイ

## Docker イメージのビルドと GCR へのプッシュ
まずはホスティングするコンテナをビルドします。GCP には Code Build というビルドサービスがありますが、ここでは簡易に行うため、ローカルでビルドし、Google Container Registory にプッシュしてコンテナを用意します。

[IMAGE_ID] はビルドした Docker イメージのID
[PROJECT] は「GKE クイックスタート」で作成した project-id に書き換えてください。

```bash
$ gcloud auth configure-docker

# clone した [magento2-on-docker](https://github.com/kzkick2nd/magento2-on-docker)リポジトリに移動
$ docker-compose build
$ docker tag [IMAGE_ID] asia.gcr.io/[PROJECT]/magento:1
$ docker push asia.gcr.io/[PROJECT]/magento:1
```

## GKE クラスタの用意
複数の Pod を起動するため、余裕を持ったリソースで GKE クラスタを立ち上げます。n1-standard-1 を 3 ノードほどあれば大丈夫でしょう。

![スクリーンショット 2019-12-26 03.12.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752/469a1c78-cf7c-a7d3-5e24-ef9a247e66c1.png)

作成後、クラスタの認証情報をローカルに同期します。

		$ gcloud container clusters get-credentials [CLUSTER_NAME] 

## CloudSQL インスタンスとデータベースの作成
CloudSQL インスタンスは WEB コンソールから作成します。インスタンス名は「magento-sql」とします。クラスタサイズは任意です。

![スクリーンショット 2019-12-26 03.16.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752/758023ac-88d2-9a0e-3c9b-6b4b7ef56cad.png)

この際、「設定オプション」で「プライベートIP」を有効化します。

![スクリーンショット 2019-12-26 03.16.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752/7a3ac648-9be0-0fe7-7815-9219234bc0d5.png)

起動後、しばらく待つと「プライベートIP」が割り当てられます。これをチュートリアルリポジトリの「app-config.yaml」に書き込みます。今後「app-config.yaml」と「app-secret.yaml」に環境情報を集約していきます。

```app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: magento-config
data:
  URL: "http://[ここに magento-front ロードバランサーIP]/"
  DB_HOST: [ここに DB インスタンスのプライベートIP]
  DB_NAME: magento
  DB_USER: magento
  ADMIN_USER: admin
  ADMIN_EMAIL: [ここに管理メールアドレス]
```

最後にデータベースを作成します。以下の [DB_PASS] は任意のパスワードに置き換えてください。

```bash
$ gcloud sql databases create magento -i magento-sql --charset=utf8mb4
$ gcloud sql users create magento --host=% -i magento-sql --password=[DB_PASSWORD]
```

データベース構築に使った、[DB_NAME],[DB_USER],[DB_PASSWORD]を、app-config.yaml, app-secret.yaml に書き込みます。

以上でデータベースの用意は完了です。

## Storage クラスの追加
永続化のための NFS や Redis を起動する前に、SSD を利用した高速 StorageClass を用意します。

```bash
$ kubectl apply -f storage-class-faster.yaml
```

## Helm を利用した NFS と Redis コンテナ立ち上げ
NFS や Redis は CNDF 公式でメンテナンスされている Helm Chart を利用して立ち上げます。

```bash
# Helm redis の初期化
$ helm install --name redis -f helm-redis-values.yaml stable/redis

# 以下で得られた Base64 パスワードを app-secret.yaml 「redis-password:」に追記します
$ kubectl get secret redis -o jsonpath="{.data.redis-password}"

# Helm NFS の初期化
$ helm install stable/nfs-server-provisioner --name nfs -f helm-nfs-values.yaml
$ kubectl apply -f nfs-pvc.yaml
```

これで Redis と NFS の準備が完了です。

## ロードバランサの作成
静的 IP を払い出すため、事前に Pod 用をインターネットに公開するロードバランサを作成します

```bash
$ kubectl apply -f app-lb.yaml
```

払い出された magento-front-lb のエンドポイント（IP）を「app-config.yaml」に記載します。

<img width="1013" alt="スクリーンショット 2019-12-28 21.07.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752/745a847b-9810-28d0-29c2-385674d755f1.png">

## 環境設定の適用
ここまでに追記した「app-config.yaml」と「app-secret.yaml」をクラスターの環境変数に適用します。

まだ書き加えていない項目は書き加えます。「app-secret.yaml」では全ての項目がBase64エンコードされている必要があります。`echo -n 'hoge' | base64` 等で変換して記載します。

```bash
$ kubectl apply -f app-config.yaml
$ kubectl apply -f app-secret.yaml
```

これで環境変数が読み込まれました。

## 初期化 Magento2 Pod の立ち上げと初期化ファイルのデプロイ
ステートフルな初期化を行う専用の init Pod を立ち上げます。

まず「app-init.yaml」の指定コンテナ名の[PROJECT]を冒頭の「クイックスタート」で作成したproject-idに変更します。

```app-init.yaml
containers:
  - image: asia.gcr.io/[PROJECT]/magento:1
```

その後 Deployment を適用します。Pod 起動時に postStart command で Magento2 の初期化を実行しますので、起動後は削除します。

```bash
$ kubectl apply -f app-init.yaml
$ kubectl delete -f app-init.yaml
```

## Front Pod と Admin Pod のデプロイ
初期化 Pod から NFS と CloudSQL に初期化ファイルがデプロイされたので、次はストアフロント Pod を立ち上げます。すでに NFS と CloudSQL でステートの永続化はできていますので、Front Pod は停止や再起動、スケールアウトが自在になります。

「app-init.yaml」と同様に、「app-front-deploy.yaml」「app-admin-deploy.yaml」指定コンテナ名の[PROJECT]を冒頭の「クイックスタート」で作成したproject-idに変更します。

```app-admin-deploy.yaml
containers:
  - image: asia.gcr.io/[PROJECT]/magento:1
```

Deployment を適用します。

```bash
$ kubectl apply -f app-front-deploy.yaml
$ kubectl apply -f app-admin-deploy.yaml
```

起動後に app-lb.yaml で起動したロードバランサーのエンドポイントを開き、起動したMagento2 にアクセスできることを確認します。

## 管理画面 IP の分離
管理画面を専用 Pod に分けるため、Magento2 の管理画面ドメイン変更機能を利用します。

「店舗」> 「高度な設定」>「管理者」> 「管理ページベースURL」
<img width="1436" alt="スクリーンショット 2019-12-28 23.29.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/752/19abbee1-aa6f-4e76-2ef1-e22449c08e56.png">

## Cron Pod のデプロイ
Front と Admin Pod は Magento2 のサーバーの機能だけに利用していますので、このままでは crontab によるタスク実行ができません。そこで Cron 実行専用の Pod を起動します。

Kubernetes には Jobs という機能があり cron のようなスケジュールされたタスク実行を管理でき、crontab ではなく Jobs を利用するのが適切です。しかしMagento2 コンテナの都度起動の安定化はそれだけで相当な説明内容となりますので、ここでは常時起動 Pod の中で cron プロセスを起動します。

他の Deployment と同様に、「app-cron.yaml」指定コンテナ名の[PROJECT]を冒頭の「クイックスタート」で作成したproject-idに変更します。

```app-cron.yaml
containers:
  - image: asia.gcr.io/[PROJECT]/magento:1
```

その後、Deployment を適用します

```bash
$ kubectl apply -f app-cron.yaml
```

## クラスター削除を忘れずに
以上で Magento2 on GKE の起動完了です。

起動した状態からローカルで Docker イメージを更新し、GCR に Push、Deployment のイメージタグを変更して Apply すると自動でコンテナがローリングアップデートされます。

手動のイメージビルドデプロイは Cloud Build 等を利用し自動化できますし、ファイヤーウォールや CDN も、GCP の機能を利用して組み込んでいくことが可能です。

なかなかステップ数の多い手順でしたが、複数 Pod 構成が可能な Magento2 on GKE の起動はこれにて完了です。費用を使いすぎない様に、不必要なときは GKE クラスタを削除するのを忘れない様に注意しましょう。