🌱

strapi-starter-gridsome-blogをCloud Runにデプロイしてみる

13 min read

前回のstrapi-starter-gridsome-blogを試してみたで作成したstrapiのプロジェクトをCloud Runにデプロイしてみます。

https://zenn.dev/mseto/articles/strapi-starter-blog

事前準備

  • VSCode
  • VSCodeの拡張機能 Remote - Containers
  • Google Cloud Platformへの登録
    こちらのインストールや登録についての説明は省略します。

Google Cloud Platformで使用するサービス

サービス 説明
Cloud Stroage strapiのメディアライブラリのアップロード先に使用します。
Cloud SQL strapiのデータベースに使用します。
Cloud Build strapiのコンテナをビルドして登録するのに使用します。
Container Registry ビルドしたコンテナイメージの保存先に使用します。
Cloud Run strapiのコンテナを起動するのに使用します。

strapiでGoogle Cloud Storageを使用するための準備

strapi-starter-gridcome-blog/strapi-blogをVSCodeで開きRemote-Containers: Reopen in Containerを実行してコンテナに入ります。

下記コマンドを実行してプラグインのstrapi-provider-upload-google-cloud-storageをインストールします。

$ cd backend
$ yarn add strapi-provider-upload-google-cloud-storage

続けて本番(production)環境の環境設定ファイルを配置するためのディレクトリを作成します。

 $ mkdir -p ./config/env/production

ここに下記プラグイン設定ファイルを作成します。

/backend/config/env/production/plugins.js
module.exports = ({ env }) => ({
  upload: {
    provider: 'google-cloud-storage',
    providerOptions: {
      bucketName: env('GCS_BUCKET_NAME'),
      uniform: true,
      baseUrl: 'https://storage.googleapis.com/{bucket-name}',
    },
  },
});

ここではstrapiで使うGoogle Cloud Storageのバケット名の環境変数名をGCS_BUCKET_NAMEにしました。

本番(production)環境用のDB設定ファイルの作成

今回はDBにMySQLを使用します。
本番(production)環境でCloud SQLに接続するための設定ファイルを作成します。

/backend/config/env/production/database.js
module.exports = function ({ env }) {
  return {
    defaultConnection: 'default',
    connections: {
      default: {
        connector: 'bookshelf',
        settings: {
          client: 'mysql',
          socketPath: env('DATABASE_HOST'),
          database: env('DATABASE_NAME'),
          username: env('DATABASE_USERNAME'),
          password: env('DATABASE_PASSWORD'),
        },
        options: {
          "pool": {
            "min": 0,
            "max": 50,
            "createTimeoutMillis": 30000,
            "acquireTimeoutMillis": 30000,
            "idleTimeoutMillis": 30000,
            "reapIntervalMillis": 1000,
            "createRetryIntervalMillis": 100,
          }
        }
      }
    }
  }
};

環境変数名はそれぞれ下記の様にしました。

環境変数名 説明
DATABASE_HOST Cloud SQLのソケットパス
DATABASE_NAME データベース名
DATABASE_USERNAME ユーザ名
DATABASE_PASSWORD パスワード

PostgreSQLの場合はCloud SQLのソケットパスをhostに設定するのですが、MySQLの場合socketPathに設定することに気づかずしばらくハマりました。

参考:

https://cloud.google.com/sql/docs/mysql/samples/cloud-sql-mysql-mysql-create-socket?hl=ja
https://cloud.google.com/sql/docs/postgres/samples/cloud-sql-postgres-knex-create-socket?hl=ja

strapiをCloud Runで動かすためのコンテナを設定

Cloud Runで使用するDockerfileを作成します。

/Dockerfile
FROM node:14-slim
WORKDIR /usr/src/app

COPY ./backend/package.json ./
COPY ./backend/yarn.lock ./

RUN yarn install

COPY ./backend .

ENV NODE_ENV production

RUN yarn build

EXPOSE 1337

CMD ["yarn", "start"]

デプロイ対象外のファイルを設定

デプロイするコンテナに含めないファイルを設定します。

/.gcloudignore
.gcloudignore
.git
.gitignore
node_modules/
#!include:.gitignore

ここまで設定したらstrapi-starter-gridcome-blog/strapi-blogのリモート接続を終了します。

Google Cloud Platformでプロジェクトを作成

下記のプロジェクト作成画面から新しいプロジェクトを作成します。

https://console.cloud.google.com/projectcreate

新しいプロジェクト

ここではプロジェクト名をstrapi-gridsome-blogにしました。

Google Cloud SDKの準備

ローカル環境にインストールすることもできますが、極力ローカルにはインストールしたくない、なんでもVSCodeとDockerで済ませたいと思い、こちらもVSCodeのリモートコンテナを使うことにしました。

ローカル環境にインストールする場合は下記に手順があります。

https://cloud.google.com/sdk/docs/install

Google Cloud SDKのプロジェクトを設置するディレクトリはどこでも問題ないと思いますが、ここでは下記の様な構成にしました。

.
├ strapi-starter-gridcome-blog/
│ ├ strapi-blog/         # strapiのプロジェクト
│ └ gridsome-blog/       # Gridsomeのプロジェクト
└ gcloud/                 # Google Cloud SDK

VSCodeでgcloudディレクトリを開き、下記のファイルを作成します。

.devcontainer/devcontainer.json
{
  "name": "gcloud",
  "dockerComposeFile": "docker-compose.yml",
  "service": "gcloud",
  "workspaceFolder": "/src",
}

.devcontainer/docker-compose.yml
version: '3'

services:
  gcloud:
    build: .
    volumes:
      - ${PROJECT_ROOT}:/src
.devcontainer/Dockerfile
FROM google/cloud-sdk:latest

RUN mkdir -p /src

WORKDIR /src
devcontainer/.env
PROJECT_ROOT=strapi-starter-gridcome-blogディレクトリのフルパス

PROJECT_ROOTにはstrapi-starter-gridcome-blogディレクトリまでのフルパスを設定します。

ファイルが作成できたらRemote-Containers: Reopen in Containerを実行してコンテナに入ります。

コンテナが起動したらターミナルから下記コマンドを実行し、Google Cloud Platformへのログイン及びプロジェクトにstrapi-gridsome-blogを選択します。

$ gcloud init

環境変数ファイルの作成

gcloudコマンドで使用する環境変数を予め設定します。
尚、下記はここでの設定値になっていますが、PROJECT_NUMBERDATABASE_PASSWORDについては適宜変更して使用しています。

.env
PROJECT_NAME=strapi-gridsome-blog
PROJECT_ID=strapi-gridsome-blog
PROJECT_NUMBER=000000000000
REGION=asia-northeast1
CLOUD_SQL_NAME=strapi-gridsome-blog
CLOUD_SQL_MACHINE_TYPE=db-f1-micro
DATABASE_HOST=/cloudsql/strapi-gridsome-blog:asia-northeast1:strapi-gridsome-blog
DATABASE_NAME=strapi-gridsome-blog
DATABASE_USERNAME=strapi-gridsome-blog
DATABASE_PASSWORD=xxxxxxxxxxx
GCS_BUCKET_NAME=strapi-gridsome-blog
STRAPI_IMAGE_NAME=strapi-blog
GRIDSOME_IMAGE_NAME=gridsome-blog
STRAPI_CLOUD_RUN_NAME=strapi-blog
GRIDSOME_CLOUD_RUN_NAME=gridsome-blog
環境変数名 説明
PROJECT_NAME Google Cloud Platformで作成したプロジェクト名
PROJECT_ID 作成したプロジェクトのプロジェクトID
PROJECT_NUMBER 作成したプロジェクトのプロジェクト番号
REGION 使用するリージョン
CLOUD_SQL_NAME 作成するCloud SQLのインスタンス名
CLOUD_SQL_MACHINE_TYPE 作成するCloud SQLのマシンタイプ
DATABASE_HOST /cloudsql/INSTANCE_CONNECTION_NAMEを設定
DATABASE_NAME この後作成するDB名
DATABASE_USERNAME 作成するDBのユーザ名
DATABASE_PASSWORD 作成するDBのパスワード
GCS_BUCKET_NAME 作成するGoogle Cloud Storageのバケット名
STRAPI_IMAGE_NAME 作成するstrapiコンテナのイメージ名
GRIDSOME_IMAGE_NAME 作成するGridsomeコンテナのイメージ名
STRAPI_CLOUD_RUN_NAME strapiのCloud Runのインスタンス名
GRIDSOME_CLOUD_RUN_NAME GridsomeのCloud Runのインスタンス名

INSTANCE_CONNECTION_NAMEは下記形式になります。
Cloud SQLインスタンスの作成後はCloud SQLの概要ページの接続名で確認できます。

プロジェクトID:Cloud SQLのリージョン:Cloud SQLのインスタンス名

.envを作成したら、ターミナルから下記コマンドで環境変数をシェルに反映させます。

$ source .env

環境変数がシェルに反映されたか確認します。

$ echo $PROJECT_NAME
strapi-gridsome-blog

使用するサービスの有効化

下記コマンドで使用するサービスを有効化します。

$ gcloud services enable run.googleapis.com sql-component.googleapis.com sqladmin.googleapis.com cloudbuild.googleapis.com

Cloud SQLのインスタンスを作成

下記コマンドでCloud SQLのインスタンスを作成します。

$ gcloud sql instances create $CLOUD_SQL_NAME --project $PROJECT_ID --database-version MYSQL_5_7 --tier $CLOUD_SQL_MACHINE_TYPE --region $REGION

DBの作成

作成したCloud SQLのインスタンスにDBを作成します。

$ gcloud sql databases create $DATABASE_NAME --instance $CLOUD_SQL_NAME

DBユーザの作成

作成したCloud SQLのインスタンスにDBユーザを作成します。

$ gcloud sql users create $DATABASE_USERNAME --instance $CLOUD_SQL_NAME --password $DATABASE_PASSWORD

サービスアカウントにCloud SQL クライアントのロールを追加

サービスアカウントCloud SQL クライアントのロールを加します。

$ gcloud projects add-iam-policy-binding $PROJECT_ID --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com --role roles/cloudsql.client

Cloud Storageにバケットを作成

Cloud Storageにバケットを作成します。

$ gsutil mb -l $REGION gs://$GCS_BUCKET_NAME

Cloud Storageのバケットに書き込み権限を追加

Google Cloud PlatformのCloud Strageのページからバケットへの書き込み権限を追加します。
一覧からバケット名をクリックします。
Cloud Strageでバケットを選択

"権限"をクリックします。
権限をクリック

権限の横にある"追加"をクリックします。
権限の横にある追加をクリック

"新しいメンバー"にサービスアカウント名(プロジェクト番号-compute@developer.gserviceaccount.com)を入力して"ロールを選択"をクリックします。
新しいメンバーの追加

"Cloud Strage レガシー"を選択し、"Storage レガシーバケット書き込み"を選択します。
ロールの選択

保存をクリックして書き込み権限を追加します。

ブログからアップロードした画像を参照できるようにする為、同様に"権限"の"追加"から"新しいメンバー"にallUsersを入力し、"ロールを選択"で"Cloud Strage" > "Storage オブジェクト閲覧者"を選択し、保存をクリックします。

下記が表示されるので"一般公開アクセスを許可"をクリックします。
一般公開を許可

strapiのコンテナイメージをビルドして登録

VSCodeのターミナルから下記コマンドを実行してコンテナイメージをビルドし、Container Registryに登録します。
ビルドには大体10分程度かかりました。

$ cd strapi-blog
$ gcloud builds submit --tag gcr.io/$PROJECT_ID/$STRAPI_IMAGE_NAME --timeout=1200

デフォルトの600秒だとタイムアウトすることがあったので--timeout=1200オプションを付けています。

strapiをCloud Runにデプロイ

下記コマンドを実行してCloud Runにデプロイします。
コマンドが成功すると"Service URL:"に表示されたURLにstrapiがデプロイされています。

$ gcloud run deploy --memory 512 $STRAPI_CLOUD_RUN_NAME --platform managed --region $REGION --image gcr.io/$PROJECT_ID/$STRAPI_IMAGE_NAME:latest --allow-unauthenticated --set-env-vars "DATABASE_NAME=$DATABASE_NAME" --set-env-vars "DATABASE_USERNAME=$DATABASE_USERNAME" --set-env-vars "DATABASE_PASSWORD=$DATABASE_PASSWORD" --set-env-vars "DATABASE_HOST=$DATABASE_HOST" --set-env-vars "GCS_BUCKET_NAME=$GCS_BUCKET_NAME" --add-cloudsql-instances $PROJECT_NAME:$REGION:$CLOUD_SQL_NAME

一般公開する必要がない場合は--allow-unauthenticatedオプションを外してください。

下記の様なメモリ不足のエラーが出たので--memory 512オプションを付けています。

Memory limit of 256M exceeded with 278M used. Consider increasing the memory limit, see https://cloud.google.com/run/docs/configuring/memory-limits 

Google Cloud Strageのプラグイン設定が間違っていたりするとパッケージインストールの問題じゃないのに下記のようなエラーメッセージがでます。

error Error: The provider package isn't installed. Please run `npm install strapi-provider-upload-google-cloud-storage`

デプロイコマンドに失敗すると下記エラーメッセージがでますが、ポートの問題ではなく、ビルドが失敗してコンテナが立ち上がらなかったためです。

ERROR: (gcloud.run.deploy) Cloud Run error: Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Logs for this revision might contain more information.

"Logs URL:"に表示されたアドレスに行き、ログをよく確認して原因を調べましょう。

"Service URL:"に表示されたURLにアクセスすると下記ページが表示されます。
Cloud RunにデプロイしたStrapi

URLに/adminを追加してアクセスすると管理者登録画面が表示されるので、必要な情報を入力してREADY TO STARTボタンをクリックすると管理画面にログインすることができます。

GridsomeをCloud Runにデプロイする準備

デプロイするコンテナに含めないファイルを設定します。

/gridsome-blog/.gcloudignore
.gcloudignore
.git
.gitignore
.env
node_modules/
dist/
#!include:.gitignore

GridsomeをCloud Runで動かすためのコンテナを設定

Cloud Runで使用するDockerfileを作成します。
GRIDSOME_STRAPI_URLにはCloud RunにデプロイしたstrapiのURLを設定します。

/gridsome-blog/Dockerfile
FROM nginx:latest
WORKDIR /usr/src/app

RUN curl -sL https://deb.nodesource.com/setup_current.x | bash - && \
    apt-get install -y nodejs && \
    npm install -g npm@latest && \
    npm install -g yarn

COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf

COPY ./frontend/package.json ./
COPY ./frontend/yarn.lock ./

ENV GRIDSOME_STRAPI_URL=strapiのURL

RUN yarn install

COPY ./frontend .

RUN yarn build

EXPOSE 8080

nginxの設定ファイルを作成

Dockerfileで使用するnginxの設定ファイルを作成します。

/gridsome-blog/nginx/default.conf
server {
    listen 8080;
    server_tokens off;

    location / {
      include /etc/nginx/mime.types;
      autoindex off;
      root  /usr/src/app/dist;
      index  index.html index.htm;
      try_files $uri $uri/ /index.html;
    }
}

Gridsomeのコンテナイメージをビルドして登録

下記のコマンドでGridsomeのコンテナをビルドしてContainer Registryに登録します。

$ cd /src/gridsome-blog
$ gcloud builds submit --tag gcr.io/$PROJECT_ID/$GRIDSOME_IMAGE_NAME --timeout=1200

GridsomeをCloud Runにデプロイ

下記コマンドを実行してCloud Runにデプロイします。
コマンドが成功すると"Service URL:"に表示されたURLにGridsomeがデプロイされています。

$ gcloud run deploy --memory 512 $GRIDSOME_CLOUD_RUN_NAME --platform managed --region $REGION --image gcr.io/$PROJECT_ID/$GRIDSOME_IMAGE_NAME:latest --allow-unauthenticated

一般公開する必要がない場合は--allow-unauthenticatedオプションを外してください。

まとめ

いくつかハマった点がありましたが、strapiとGridsomeをCloud Runにデプロイすることができました。
次回はGithubにプッシュでstrapiをビルド及びデプロイできるようにしたいと思います。

次回

https://zenn.dev/mseto/articles/strapi-starter-blog-cd

Discussion

ログインするとコメントできます