WordPress で学ぶ Cloud Run のストレージとデータベース

## はじめに

アイレットメンバー主催の Advent Calendar 7日目の記事です！  
今日は Google Cloud の日、Serverless のお話です。

サーバーレスの環境には、いくつかのパターンがあります。

- Cloud Functions のような FaaS (Funtion as a Service) 環境  
- Google Kubernetes Engine のような KaaS (Kubernetes as a Service) 環境  
- Cloud Run のような CaaS (Container as a Service) 環境

今回の記事にある Cloud Run は CaaS (Container as a Service) 環境です。  
Docker image を用意し、Artifact Registry などに配置することで、Cloud Run の実行イメージとして実行可能となります。

Cloud Run の実行形態は、一度きりの処理を実行する Job と、恒常的な処理を実施する Service に分かれますが、WordPress のような HTTP Server として動作させる場合、Service として実行することができます。

今回の記事では、WordPress を題材として、Cloud Run のストレージ機能と、データベース連携について解説を行います。

![image7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/3864bb96-3596-cc91-5e0e-dd2d69226d52.png)


## コンテナの特徴

最初に、コンテナの特徴についておさらいします。

Linux などの環境では、サーバーごとに永続的に管理されるストレージがあり、データベース・サーバーは同一のセグメントに存在しています。  
スケールアウト (同一環境を複数用意する負荷分散) を実施する場合、それぞれのインスタンス毎でストレージが管理されるのが一般的です。

Cloud Run などの CaaS 環境は、異なる特徴を有しています。

実行環境は、負荷に応じてスケールし、自動的にスケールアウト・スケールインします。  
それらの環境は一時的な環境のため、ストレージはネットワーク経由で利用できる別領域を必要とします。  
データベースなどは、コンテナの処理から分離され、Cloud SQL など完全に別環境で管理されます。

### Cloud Run とデータ管理の課題

Cloud Run は、Google 側で環境が管理される Managed Service です。  
ユーザーが有する VPC 内ではなく、グローバルで動作します。

それに対し、Cloud SQL は、ユーザーの VPC 内で動作します。  
基本的には、Local IP Address のみの利用が推奨され、Global IP Address は推奨されません。

Cloud Run の接続のため、Serverless VPC Access を利用することも可能です。  
しかし、Serverless VPC Access Connector のインスタンス単位で課金が発生するため、オンデマンドでスケールするサーバーレスサービスを利用するコストメリットは薄くなります。

これは、ストレージに対しても同様です。  
Cloud Run のストレージとして、 Filestore を利用することが可能です。  
しかし、Filestore もインスタンス単位に課金が発生します。

定常的なアクセスが発生する用途には適切ですが、Web サイトのような負荷が変動するサイトへの適用は難しいです。

## 低頻度アクセスのための Cloud Run 構成

今回の構成は、低頻度アクセスのためにオンデマンドで増減する構成とします。

そのため、以下のような構成を行いました。

- ワークロードのための Cloud Run  
- ストレージのための Google Cloud Storage  
- データベースのための Cloud SQL

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/84db1959-6537-5c6a-46f6-f0d7259f5747.png)

信頼性のため、データベース層のみ Cloud SQL を利用しますが、それ以外のサービスはオンデマンド利用が可能なものです。

Cloud Run は、最低インスタンス数を 0 に設定することが可能です。  
この設定により、普段アクセスが発生しないような通信に対してはコストを最小化することが可能です。  
(この場合、コールドブートとなるため、起動時のラグは発生します)

また、Cloud Run は、スケールアウトが可能なため、負荷が高くなった際には自動的にインスタンス数が増加します。

Google Cloud Storage も同様に、容量および、都度のアクセス数に対して課金が発生します。  
そのため、普段のアクセス数が低い場合には最適な選択肢です。

今回の構成では、Serverless VPC Access や Filestore などの定常的にコストが発生するサービスを利用しません。

### Cloud Storage FUSE

Google Cloud Storage は、[2023年 6月 26日の Update](https://cloud.google.com/storage/docs/release-notes#June_26_2023) で FUSE (Filesystem in Userspace) というモードが追加されました。

これは、通常のファイルシステムのように Google Cloud Storage を活用することが可能となるモードです。  
通常の Cloud Storage は、いわゆる KVS (KeyValue Store) であり、名前に対するオブジェクトを返す動作をします。

Cloud Storage FUSE は、通常のファイルシステムのように `/` を区切り文字と解釈し、階層型のファイルシステムを提供することが可能となります。

この機能により、Cloud Storage を Cloud Run のストレージレイヤーとして活用することが可能となりました。

### サイドカーコンテナ

サイドカーコンテナとは、メインのコンテナとともに動作して、メインコンテナをサポートするユーティリティです。

Cloud Run では、[2023年 12月 15日の Update](https://cloud.google.com/run/docs/release-notes#December_15_2023) でサイドカーコンテナの実行がサポートされました。

Cloud SQL は、Global IP を有する Instance に対して安全に接続を行うため、Cloud SQL Auth Proxy という機能を有しています。

今まで、この機能を利用するためにはメインのコンテナに導入する必要があり、プログラムの動作がデータベースに依存する問題がありました。

サイドカーコンテナとして Cloud SQL Auth Proxy を動作させることで、ワークロードの処理をデータベースから分離し、グローバルで動作する Cloud Run と、Cloud SQL を安全に連携することが可能となりました。

![image8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/3f4091ac-7542-83cc-2571-877d58b0ee2f.png)

## 構成

### ストレージの準備

WordPress を利用するうえで、一般的に 2つの用途でストレージの準備が必要です。

- 利用者ごとのカスタマイズである `themes` や `plugins` フォルダ  
- 画像を格納する `uploads` フォルダ

ディレクトリ構造上は、ともに `wp-content` 内にありますが、特性が異なります。

`themes` や `plugins` は通常の利用で静的であり、高速なアクセスが必要です。  
そのため、Container 起動時に内部ストレージにコピーし、ユーザーエクスペリエンスを向上させることが求められます。

`uploads` は大容量かつ動的であり、比較的低速なアクセスで問題ありません。  
そのため、リクエストの都度 Google Cloud Storage を参照し、コンテナ内のリソースを節約することが求められます。

`wordpress` Docker Image は、この構成をサポートします。

このニーズを実現するため、Google Cloud Storage は以下の構成を行います。

- Google Cloud Storage  
  - `wp-content` バケット  
    - `themes` や `plugins` 格納のため  
  - `uploads` バケット  
    - `uploads` 格納のため

2024年 12月 1日時点で、Cloud Run の GCS マウントはバケットのみ対象とします。  
そのため、後述する Mount のため、2 つのバケットを用意します。

Cloud Storage FUSE は、構築する際にここのチェックボックスを有効にします。

![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/7326a632-719d-db07-e957-a8fedf1e716d.png)

### Cloud SQL の準備

WordPress のデータを格納するため、Cloud SQL を構成します。

ここでは、Cloud Run から Cloud SQL Auth Proxy  経由で接続するため Global IP Address を有効に設定します。  
`承認済みネットワーク` は、Cloud SQL Auth Proxy 経由の場合、追加は必要ありません。  

![image5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/09050db3-ab7f-8551-990a-4fc8472fc3c9.png)

#### データベースの構成

Cloud SQL 構成後は、WordPress 用のユーザーや、Database を作成します。

これらは、通常の手順で問題ありません。

### Service Account の準備

Cloud Run の実行ユーザーとして、Service Account を新たに作成します。

Cloud Run では、デフォルトでは Google Compute Engine 用のデフォルト Service Account を使用します。  
しかし、Google Cloud Storage や Cloud SQL に対する権限のみ付与することが推奨されるため、新たな Service Account を作成し、権限を付与します。

#### 権限の付与

作成した Service Account には、以下の権限を付与します。

- Google Cloud Storage  
  - `Storage オブジェクト ユーザー`  
  - `ストレージ フォルダ管理者`  
- Cloud SQL  
  - `Cloud SQL クライアント`

この権限により、先に作成した Bucket や Cloud SQL に接続が可能となります。

### Cloud Run の準備

Cloud Run には、ボリューム、コンテナとして設定を追加していきます。

#### ボリューム

ボリュームでは、Cloud Storage を Cloud Run で利用するための設定を行います。

今回は、2つのボリュームをマウントします。  
これらを利用する形で、コンテナを準備します。

| ボリュームのタイプ | ボリューム名 | バケット | 読み取り専用 |
| :---- | :---- | :---- | :---- |
| Cloud Storage バケット | wp-content | (参照) | True (読み取り専用) |
| Cloud Storage バケット | uploads | (参照) | False (書き込み可能) |

#### WordPress コンテナ

コンテナとしては、DockerHub にあるイメージを利用します。

| 名前 | 値 |
| :---- | :---- |
| イメージのURL | wordpress |
| コンテナポート | 80 |

##### ボリューム

ボリュームのマウントとして、以下を設定します。

| 名前 | マウントパス |
| :---- | :---- |
| wp-content | /usr/src/wordpress/wp-content |
| uploads | /var/www/html/wp-content/uploads |

この設定により、wp-content は起動時にコピーされ、高速にアクセスすることが可能となります。  
uploads は html フォルダに直接マウントすることで、Cloud Run のメモリ容量 (インメモリディスクとして動作するため) を削減できます。

##### 変数とシークレット

変数とシークレットは以下のとおりです。  
今回、サイドカーコンテナ経由で Cloud SQL にアクセスするため、DB\_HOST の値は `127.0.0.1` になります。

| 名前 | 値 |
| :---- | :---- |
| WORDPRESS\_DB\_HOST | 127.0.0.1 |
| WORDPRESS\_DB\_USER | (Cloud SQL の設定値) |
| WORDPRESS\_DB\_PASSWORD | (Cloud SQL の設定値) |
| WORDPRESS\_DB\_NAME | wordpress |

#### Cloud SQL Auth Proxy コンテナ

Cloud SQL に Cloud Run 経由で安全にアクセスするため、Cloud SQL Auth Proxy コンテナを動作させます。

Auth Proxy は、コンテナとして用意されているため、それを利用します。

| 名前 | 値 |
| :---- | :---- |
| イメージのURL | gcr.io/cloud-sql-connectors/cloud-sql-proxy |

##### 設定

Cloud SQL Auth Proxy の設定は、コンテナ引数として渡す必要があるため、設定を行います。

| 名前 | 値 |
| :---- | :---- |
| コンテナの引数 | `--port=3306`  (接続名) |

この設定により、サイドカーコンテナとして動作し、Cloud SQL への接続が可能となります。

#### その他の設定

必要に応じて、セキュリティ、他の設定を実施してください。  
詳細は、省略します。

### WordPress の動作

これまでの設定により、Cloud Run 上で WordPress を動作させることが可能となります。

静的な設定は、コンテナ内で高速に処理されるため、サーバーは実用十分な速度でユーザーにレスポンスを返します。

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/df84a6a1-6035-d9b4-0225-d1b3befac6f3.png)

今回の構成では、Waiting for server response は `466ms` であり、十分に高速に動作します。

また、Cloud Run で問題となるような画像のアップロードは、マウントした Google Cloud Storage 側に保管され、コンテナ間で共有されます。

画像は Bucket 側で保管されるため、このように画像の表示も問題ありません。  

![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/20c17f0b-1e07-bb4b-a55a-39f007a1959e.png)
![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240771/ea406ee2-e105-c233-6d83-30cdc5a08d7b.png)


## まとめ

Cloud Run は、低頻度アクセスのサービスとしても十分な機能を有しています。

ストレージのための Cloud Storage FUSE と Cloud Storage バックエンド。  
SQL Proxy を可能とする サイドカーコンテナ。  
そして、Cloud Run 自体の特徴である Full managed CaaS 機能です。

小さく初めて、大きく成長できる Cloud の特性を体現する Cloud Run を活用し、新しいビジネスをスタートアップしてください。