【超シンプル版】Rails アプリを Cloud Run で動かしてみようで Cloud Run を使って Rails アプリを動かしてみました。
今回はもう少し実践で使えるようにデータベース、環境変数の設定、ログの収集、ビルドの自動化を構築していきたいと思います。
前提
追加で利用するプロダクト
- Cloud SQL
- Cloud Logging
- Secret Manager
構築の流れ
- Rails アプリ作成
- Cloud SQL と接続する
- Secret Manager を利用する
- Cloud Logging を利用する
- 手動でビルド & デプロイ
- Cloud Build と GitHub を連携する
Rails アプリ作成
ここは前回とほぼ同じなので、説明は割愛します。
# Rails アプリ作成. データベースは MySQL にする
$ rails new sample-app -d mysql
$ cd sample-app
# scaffold でページ作成
$ bin/rails g scaffold Post title:string content:text
Dockerfileを作ります。
master.keyを外部から注入できるようにしておきます。
$ touch Dockerfile
FROM ruby:3.1.2
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp
ARG MASTER_KEY
ENV RAILS_MASTER_KEY=${MASTER_KEY}
# Cloud Run はデフォルトポート8080で起動
EXPOSE 8080
CMD ["bin/rails", "server", "-b", "0.0.0.0", "-p", "8080"]
Cloud Build の設定ファイル cloudbuild.yaml を作成します。
今回はBuildのタイミングでdb:migrate
も行います。
また Cloud Run へのデプロイも設定します。
$ touch cloudbuild.yaml
steps:
# Cloud Build でビルド
- id: "build image"
name: "gcr.io/cloud-builders/docker"
entrypoint: 'bash'
args:
- -c
- |
docker build \
-t gcr.io/${PROJECT_ID}/${_SERVICE_NAME} \
. \
--build-arg MASTER_KEY=$$MASTER_KEY
secretEnv:
- MASTER_KEY
# Container Registry にアップロード
- id: "push image"
name: "gcr.io/cloud-builders/docker"
args:
- push
- gcr.io/${PROJECT_ID}/${_SERVICE_NAME}
# db:migrate
- id: "apply migrations"
name: "gcr.io/google-appengine/exec-wrapper"
entrypoint: "bash"
args:
- -c
- |
/buildstep/execute.sh \
-i gcr.io/${PROJECT_ID}/${_SERVICE_NAME}\
-s ${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME} \
-e MASTER_KEY=$$MASTER_KEY \
-- bundle exec rails db:migrate
# Cloud Run デプロイ
- id: 'deploy'
name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: 'bash'
args:
- -c
- |
gcloud run deploy $_SERVICE_NAME \
--image gcr.io/${PROJECT_ID}/${_SERVICE_NAME} \
--region asia-northeast1 \
--add-cloudsql-instances ${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME} \
--allow-unauthenticated
substitutions:
_SERVICE_NAME: sample-app-service
_REGION: asia-northeast1
_INSTANCE_NAME: sample-app-db-instance
availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/MASTER_KEY/versions/latest
env: MASTER_KEY
images:
- "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"
timeout: 600s
Cloud SQL と接続する
Cloud SQL を構築していきます。
まずインスタンス、データベース、ユーザーの作成をします。
# DBのインスタンス作成
$ gcloud sql instances create sample-app-db-instance \
--database-version MYSQL_5_7 \
--tier db-f1-micro \
--region asia-northeast1
# データベース作成
$ gcloud sql databases create sample-app-db \
--instance sample-app-db-instance
# ユーザー作成
$ gcloud sql users create app_user \
--instance=sample-app-db-instance --password=password
ビルド時に db:migrate
を実行するため、Cloud Build のサービスアカウントに Cloud SQL に接続するためのロールを設定します。
Cloud Build はデフォルトでサービスアカウントが作られていますので、WebコンソールのIAMと管理
ページを見てサービスアカウント名([XXXXXXXXXX]@cloudbuild.gserviceaccount.com
)を確認してください。
# サービスアカウントにロール追加
$ gcloud projects add-iam-policy-binding [PROJECT_ID] \
--member serviceAccount:[XXXXXXXXXX]@cloudbuild.gserviceaccount.com \
--role roles/cloudsql.client
Cloud Run のデプロイもできるようにロール設定します。
Cloud Run もデフォルトのサービスアカウントがあるため、WebコンソールのIAMと管理
ページを見てサービスアカウント名([XXXXXXXXXX]-compute@developer.gserviceaccount.com
)を確認してください。
# cloud build -> cloud run
gcloud projects add-iam-policy-binding [PROJECT_ID] \
--member serviceAccount:[XXXXXXXXXX]@cloudbuild.gserviceaccount.com \
--role roles/run.developer
# cloud build -> cloud run
gcloud projects add-iam-policy-binding [PROJECT_ID] \
--member serviceAccount:[XXXXXXXXXX]-compute@developer.gserviceaccount.com \
--role roles/iam.serviceAccountUser
最後にアプリ側のデータベース設定をします。
先ほど作成したユーザー、パスワード、データベースを設定します。
socket名もデフォルトでは決まっています( /cloudsql/[PROJECT_ID]/[REGION]/[INSTANCE_NAME]
)
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: app_user
password: password
host: localhost
socket: /cloudsql/[PROJECT_ID]:asia-northeast1:sample-app-db-instance
development:
<<: *default
database: sample-app-db
...
Secret Manager を利用する
環境変数に設定するような秘匿情報を Secret Manager で管理します。
Cloud Build, Cloud Run どちらからもアクセスが可能です。
特に Cloud Run の Railsアプリからアクセスするときは、コードを変更することなく ENV('xxx')
で参照することができます。
master.key
のシークレットを作成します。
# シークレットを作成
$ gcloud secrets create MASTER_KEY \
--data-file config/master.key
Cloud Buildからアクセスできるようにロールを設定します。
# サービスアカウントにロール追加
$ gcloud projects add-iam-policy-binding [PROJECT_ID] \
--member serviceAccount:[XXXXXXXXXX]-compute@developer.gserviceaccount.com \
--role roles/secretmanager.secretAccessor
Cloud Run からアクセスできるようにロールを設定します。
# サービスアカウントにロール追加
$ gcloud projects add-iam-policy-binding [PROJECT_ID] \
--member serviceAccount:[XXXXXXXXXX]@cloudbuild.gserviceaccount.com \
--role roles/secretmanager.secretAccessor
Cloud Logging を利用する
Cloud Run でアプリを動かすとデフォルトで Cloud Logging にログを出力するようになっています。そのため、特に設定することはないです(便利)
Google Cloud のWebコンソールから Cloud Logging のページを見て、ログが出力されていることを確認してください。
ビルド & デプロイ
ここまでを手動でビルド & デプロイして実行を動作を確認します。
# ビルド、アップロード、デプロイ
$ gcloud builds submit .
Cloud Build と GitHub を連携する
最後に GitHub に pushした タイミングでビルド & デプロイを実行するようにします。
Cloud Build のトリガー機能を使えば簡単に実現できます。
Cloud Build GitHub アプリを選択して、GitHub アカウントを選べばリポジトリが連携されます。
あとはイベントを設定して、ブランチに push したときに、Cloud Build が実行されれば設定完了です。
まとめ
今回は以下の構成で構築しました。
小さなアプリであれば、十分運用できると思います。
他にも画像ファイルの保存先に Cloud Storage を使ったり、複数のアプリサーバーを使うために Cloud Load Balancing を使ったりできるので、他の構成も試していきたいと思います。