【Docker+Cloud Run勉強会】3. Cloud RunにWordPressをデプロイする

# この記事
先日Docker及びCloud Runについての勉強会を開催しました。
本記事は、その時用意した資料となります。

- [1. Dockerとは？](https://qiita.com/r-dohara/items/403ac95e1f51026e96f1)
- [2. DockerでWordPressをデプロイする](https://qiita.com/r-dohara/items/c159d258fc4b0b3c09a2)

[YouTube](https://www.youtube.com/watch?v=SO-82Mqh6sw)

# 目的
改めて、コンテナとは？というところから説明しつつ

- 代表的なコンテナエンジンであるDocker
- Google CloudのコンテナデプロイサービスであるCloud Run

について学んでもらえたらと考えています

# Google Cloud (GC)における、コンテナサービス
「[Everything at Google runs in a container](https://speakerdeck.com/jbeda/containers-at-scale?slide=2)」
Googleにとってコンテナは核となる技術です
コンテナ関連のソフトウェアとして有名なKubernetesも、元々はGoogleが設計したシステムです

勿論GCにおいても、様々なコンテナサービスが展開されています

- Cloud Run
- App Engine
- Google Kubernetes Engine
- Artifact Registry
- Cloud Build
- Binary Authorization

# Cloud RunでWordPressを構築する
ではWordPressをコンテナとしてGC上に構築してみましょう

[Cloud Run](https://cloud.google.com/run?hl=ja)というサービスを用いてコンテナをデプロイし、また[Cloud SQL](https://cloud.google.com/sql?hl=ja)との連携も行います

![Docker+Cloud Run-cloud run.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/d7a708b2-f995-f24c-d1c3-1e1a59955575.png)

## Cloud Run
Cloud Runは、主にWebアプリケーションをコンテナとして構築できるサーバレスサービスです
特徴としては以下のような点が挙げられます

- コンテナ数の自動スケーリング（0～1,000個）
- 簡単なトラフィック管理
    - 複数のリビジョンを作成でき、各リビジョンにどのくらいの割合でトラフィックを流すかの設定が可能
- 従量課金制 : 使用したリソース（CPU、メモリ）に対して課金

GCのDockerレジストリサービスである[Artifact Registry](https://cloud.google.com/artifact-registry?hl=ja)または[Container Registry](https://cloud.google.com/container-registry?hl=ja)からイメージを取得しデプロイします
また[Cloud Build](https://cloud.google.com/build?hl=ja)を用いた継続的デプロイ（Continuous Deployment）を行うことも可能です

また、コンテナなので基本的にはステートレスですが、

- [Cloud Storage](https://cloud.google.com/storage?hl=ja) (GCS) (≒ AWSのS3)や[Filestore](https://cloud.google.com/filestore?hl=ja) (≒ AWSのEFS)との統合
- Cloud SQLへの接続

などが可能です

全ての場合において使えるというわけではないですが、ホストの管理に気をかけることなく、簡単にコンテナアプリをデプロイできる便利なサービスです

ただ、ちょっとネックな点として以下のようなものがあったりします

- Cloud Runは「サービス」という単位で管理を行うのですが、1サービスにデプロイできるのは1コンテナのみです
- Docker Execのように、コンテナへ直接コマンドを叩くような機能がありません

## Cloud SQL
Cloud SQLは、GCにおけるリレーショナルデータベースのフルマネージドサービスです
立ち位置としてはAWSのRDS（非Aurora）に近いと思います

データベースエンジンとしては

- MySQL
- PostgreSQL
- SQL Server

に対応しています


- 複数ゾーンへのデプロイ（フェイルオーバー可能）
- リードレプリカの作成

など、RDSと似たような機能もあります

一方ネットワーク構成は、RDSとはだいぶ異なるものとなっています
ユーザ管理のVPC内ではなく、GC管理のネットワークである[サービスプロデューサーネットワーク](https://cloud.google.com/vpc/docs/private-services-access?hl=ja#service_producer_network)上にデプロイされます
簡単に言うとGoogleがユーザにサービスを提供するために使用するVPCです（ユーザは管理しない）

## ステップ1 : Artifact RegistryにWordPress用DockerイメージをPushする
では環境構築のステップ1として、Artifact RegistryにWordPress用DockerイメージをPushしましょう

そのためにまずはリポジトリを作成します
Artifact Registroyのコンソール画面にて、「リポジトリを作成」を押下してください

![リポジトリ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/f9ba7d83-4a40-16b1-e237-05a635c3d234.png)

次に、gcloudを用いて、Dockerに対してArtifact Registryのリポジトリへアクセスする権限を付与します（[ドキュメント](https://cloud.google.com/artifact-registry/docs/docker/authentication?hl=ja#gcloud-helper)）
コマンドとしては以下となります（gcloudは承認済みである前提）

```
gcloud auth configure-docker asia-northeast1-docker.pkg.dev
```

`asia-northeast1-docker.pkg.dev`はリージョンによって異なります
こちらは東京リージョンに存在するArtifact Registryのリポジトリへのアクセスを許可する形となります

Dockerの認証設定ができたので、DockerイメージをPushしましょう
Dockerイメージ名は「HOST-NAME/PROJECT-ID/REPOSITORY/IMAGE」となるようにします
なので今回の場合だと以下のようなコマンドとなります

```
# Dockerイメージを作成
docker build -t asia-northeast1-docker.pkg.dev/${GCプロジェクトのID}/my-repo/my-wp:test .
# DockerイメージをPush
docker push asia-northeast1-docker.pkg.dev/${GCプロジェクトのID}/my-repo/my-wp:test
```

## ステップ2 : Cloud Runにて、WordPressを起動する
では、ステップ1でPushしたDockerイメージからCloud Runサービスを作成しましょう

Cloud Runのコンソール画面にて、「サービスの作成」を押下してください
設定画面にて以下のような設定をしてください
以下に無いものはデフォルトのままで大丈夫です
（長いのでコンソール画面は無し）

一般設定

- 「既存のコンテナ イメージから 1 つのリビジョンをデプロイする」
    - 「選択」を押下したあと、「ARTIFACT REGISTRY」を選択し、Dockerイメージを選択してください
- 「サービス名」 : 好きなものを記入してください
    - ただしこの値が、作成したサービスのデフォルトドメインに使われます
- 「リージョン」 : asia-northeast1
- 「未認証の呼び出しを許可」にチェック

コンテナ

- 「コンテナポート」 : 80
    - 「ユーザ→Cloud Runサービス」のポート番号ではなく、「Cloud Runサービス→コンテナ」のポート番号を指定します

変数とシークレット

- 「変数を追加」から、次の環境変数を追加
    - WORDPRESS_DB_HOST : 「localhost:/cloudsql/${Cloud SQLインスタンスの接続名}」
    - WORDPRESS_DB_USER : 「root」
    - WORDPRESS_DB_PASSWORD : 「${Cloud SQLインスタンスのrootユーザのパスワード}」
        - 本来はシークレットのほうが良いと思います
    - WORDPRESS_DB_NAME : 「wordpress」

接続

- 「Cloud SQL 接続」にて「接続を追加」から、Cloud SQLインスタンスを選択

※ ${Cloud SQLインスタンスの接続名} : コンソール画面から確認することができます

![接続名.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/939bb9f8-33c5-453a-df21-9f963ac7bd09.png)

上記設定後、「作成」を押下すると、サービスの作成が始まります
緑色のチェックが付いたらデプロイ成功です
例えば設定画面で指定したコンテナポートと、コンテナが実際にLISTENしているポートが異なる場合はいつまでもチェックが付かないはずです

正しくデプロイが完了したあと、表示されるURLにアクセスすると無事WordPressの初期設定画面が表示されるはずです

## Dockerfileから一発でCloud Runサービスを作成するコマンド
ここまではコンソールベースでCloud Runサービスの作成を行いましたが、
それらを一発で完了させるコマンドを紹介します

ずばり、以下のようなコマンドとなります

```
gcloud run deploy my-wp2 \
--port 80 \
--set-env-vars WORDPRESS_DB_HOST=localhost:/cloudsql/${Cloud SQLインスタンスの接続名} \
--set-env-vars WORDPRESS_DB_USER=root \
--set-env-vars 'WORDPRESS_DB_PASSWORD=${Cloud SQLインスタンスのrootユーザのパスワード}' \
--set-env-vars WORDPRESS_DB_NAME=wordpress \
--add-cloudsql-instances ${Cloud SQLインスタンスの接続名} \
--region asia-northeast1 --source .
```

（オプションが多いのでちょっと長いですね・・・）

こちら実行するといくつか質問されますが全て「y (yes)」で返答すれば大丈夫です
質問は以下のことを聞いてきてます

- ビルドしたコンテナをArtifact Registryに保存したいんだけど、名前とリージョンはこれでいい？
- Cloud Runサービスに誰でもアクセスできるけど大丈夫？
    - オプション`--allow-unauthenticated`をつけたらこの質問は省略できます

```
$ gcloud run deploy my-wp2 \
> --port 80 \
> --set-env-vars WORDPRESS_DB_HOST=localhost:/cloudsql/xxx:asia-northeast1:mysql57-wp \
> --set-env-vars WORDPRESS_DB_USER=root \
> --set-env-vars 'WORDPRESS_DB_PASSWORD=xxx' \
> --set-env-vars WORDPRESS_DB_NAME=wordpress \
> --add-cloudsql-instances xxx:asia-northeast1:mysql57-wp \
> --region asia-northeast1 --source .
Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [asia-northeast1]
will be created.

Do you want to continue (Y/n)?  y

This command is equivalent to running `gcloud builds submit --tag [IMAGE] .` and `gcloud run deploy my-wp2 --image [IMAGE]`

Allow unauthenticated invocations to [my-wp2] (y/N)?  y

Building using Dockerfile and deploying container to Cloud Run service [my-wp2] in project [xxx] region [asia-northeast1]
✓ Building and deploying new service... Done.
  ✓ Creating Container Repository...
  ✓ Uploading sources...
  ✓ Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds/13bc6ad6-3dbd-466a-9c9b-87aec9369a81?project=486218677059].
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [my-wp2] revision [my-wp2-00001-dib] has been deployed and is serving 100 percent of traffic.
Service URL: https://my-wp2-fwc5acbgkq-an.a.run.app
```

（一部伏せ字）

このコマンドを実行することで、以下のことが一発で行われます

1. ソースファイルを圧縮し、GCSに保存する
2. GCSに保存したソースファイルから、Cloud Buildを用いてDockerイメージを作成する
    - 作成したDockerイメージはArtifact Registryに保存される
3. 作成したDockerイメージからCloud Runサービスを作成する

![Docker+Cloud Run-gcloud run deploy.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/0b7eab78-059c-4c22-17c6-da13353bedf2.png)

# Cloud Runのトラフィック管理機能
特徴にも挙げましたが、Cloud Runでは複数のリビジョンを作成し、それらに対してのトラッフィク管理を簡単に行うことができます

例えば次のような設定にすると、「my-httpd-00001-nic」及び「my-httpd-00002-xoh」に対して50%ずつの割合でトラフィックを分散させることができます

![リビジョン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/37f1f4d0-fd72-7268-c893-816e6e74b9e1.png)

この状態で、「my-httpd-00001-nic」は以下のhtmlを出力するようなWebサーバ

```
This page is <b>Version 1</b>
```

「my-httpd-00002-xoh」は以下のhtmlを出力するようなWebサーバ

```
This page is <b>Version 2</b>
```

などと設定しておくと、URLにアクセスするたびに表示が切り替わることが確認できます
（必ず「Version 1」→「Version 2」→「Version 1」→「Version 2」→・・・と交互になるというわけではないようですが）

![v1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/1d969206-be54-6b10-f6cf-2cea5f7a6d6b.png)
![v2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2697194/d19d3925-3e65-8239-deca-d0afd52f03d9.png)

カナリアリリースやA/Bテスト等に役立つのではないでしょうか

# 参考
- [Containers At Scale](https://speakerdeck.com/jbeda/containers-at-scale)
- [Cloud Run](https://cloud.google.com/run?hl=ja)
- [Cloud SQL](https://cloud.google.com/sql?hl=ja)
- [Artifact Registry](https://cloud.google.com/artifact-registry?hl=ja)
- [Container Registry](https://cloud.google.com/container-registry?hl=ja)
- [Cloud Build](https://cloud.google.com/build?hl=ja)
- [Cloud Storage](https://cloud.google.com/storage?hl=ja)
- [Filestore](https://cloud.google.com/filestore?hl=ja)
- [プライベート サービス アクセス](https://cloud.google.com/vpc/docs/private-services-access?hl=ja)
- [Docker に対する認証の設定](https://cloud.google.com/artifact-registry/docs/docker/authentication?hl=ja)