Cloud Runを使ってRailsアプリを公開する【公式チュートリアルをなぞるよ!】
GCPのCloud RunでRailsアプリを立ち上げるチュートリアルをベースにRailsアプリを立ち上げを実践していってみます。
Cloud Runのデプロイ設定ができればコンテナの設定だけすればWebアプリの外部公開がだいぶ手軽になると思うのでまとめてみます。
今回はGUIのコンソールを使わずgcloudコマンドを使って各種サービスのインスタンスを作成したりしていきます。
サンプルアプリケーション
デプロイするサンプルアプリケーションを用意しました。
最初にDockerfileやdocker-compose.ymlなどの設定は実施されていることを前提としていきます。
Cloud SQLの準備
インスタンスの作成
今回はMySQLのインスタンスを作りたいのでチュートリアルのコマンドとは --database-version
の設定は MYSQL_8_0
を使用したいと思います。
リージョンは asia-northeast1
、インスタンス名は cloudrun-app-sample-db-instance
とします。
インスタンス名は任意の好きな値にしましょう。
gcloud sql instances create cloudrun-app-sample-db-instance \ --database-version MYSQL_8_0 \ --tier db-f1-micro \ --region asia-northeast1
データベースの作成
次は作成したインスタンスにデータベースを作成します。
cloudrun-app-sample-production
はデータベース名なので任意の名前を記載します。
また --instance
はインスタンスの作成で作成したインスタンス名を設定しましょう。
gcloud sql databases create cloudrun-app-sample-production --instance cloudrun-app-sample-db-instance
※ 認証関連でエラーが出るかもしれませんが、GCPのコンソールでCloudSQLにインスタンスが作成されれば問題なくインスタンス作成はされています。
ユーザーの作成
データベースを作成したら、データベースにアクセスするためのユーザーを作成します。
system_user
はユーザー名なので任意の名前を記載します。
データベースの作成と同様に --instance
は作成したインスタンスを指定します。
--password
はパスワードジェネレータなどでパスワードを作成して任意の値を設定します。
gcloud sql users create system_user \ --instance=cloudrun-app-sample-db-instance --password=hogehoge
ここまででCloudSQLの準備は完了です。
RailsプロジェクトでDBパスワードを暗号化する
ユーザー作成時に設定したパスワードをRailsのcredentials.yml.secを使って暗号化してプロジェクトに設定をしておきます。
docker compose run --rm app ash
docker-composeでアプリをコンテナで立ち上げられる前提で、docker compose runでappコンテナを起動しashでアクセスします。
EDITOR="vi" bin/rails credentials:edit
コンテナ内でcredentialを編集するコマンドを実行します。
viでエディタが起動するので以下を追記します
gcp: db_password: mysqlのユーザー作成時に設定したパスワード
追記したら保存してconfig/database.ymlのproductionの設定を更新します。
production: <<: *default database: cloudrun-app-sample-production # 作成したDBの名前 username: system_user # 作成したユーザーの名前 password: <%= Rails.application.credentials.gcp[:db_passsword] %> # socket: 後ほど追加する
ここまでできたらDBに関する設定は一旦終了です。
ちなみにsocketの部分はPostgreSQLではhostで指定するのですが、MySQLの場合はsocketとなるので注意が必要です。
Secret Managerでmaster.keyを管理
パスワードなどの秘匿情報を管理するためにSecret Managerを使います。
シークレットの作成
今回はRailsのcredentials.yml.secを利用するためmaster.keyをSecret Managerにて管理します。
gcloud secrets create sample-app-rails-master-key --data-file config/master.key
今回シークレットの名前はサンプルアプリのmaster.keyでわかるように sample-app-rails-master-key
という名前にしました。(こちらも任意の名前でOKです)
--data-file
でconfig/master.keyを指定することでmaster.keyに書かれている暗号鍵をシークレットに登録できます。
※ このコマンドは作成したRailsアプリのプロジェクト直下で実行しています。
作成したシークレットの確認
以下のコマンドで登録されたシークレットの値を確認することができます。
gcloud secrets versions access latest --secret sample-app-rails-master-key
--secret
に記載する値は作成したシークレットの名前を記載します。
Cloud Build, Cloud Runにアクセス権をつける
Cloud BuildとCloud Runからシークレットにアクセスできるようにアクセス権を付与します。
Cloud Runへのアクセス権付与はこちら
gcloud secrets add-iam-policy-binding sample-app-rails-master-key \ --member serviceAccount:PROJECTNUM-compute@developer.gserviceaccount.com \ --role roles/secretmanager.secretAccessor
Cloud Buildへのアクセス権付与はこちら
gcloud secrets add-iam-policy-binding sample-app-rails-master-key \ --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \ --role roles/secretmanager.secretAccessor
sample-app-rails-master-key
と PROJECTNUM
については自分のこれまでの作業などに合わせた値に設定してください。
PROJECT_NUM
については以下コマンドで取得できます。
gcloud projects describe PROJECT_ID --format='value(projectNumber)'
このコマンド打たなくてもGCPコンソールのダッシュボードのプロジェクト情報の欄に記載してあるのでお好きな方法でプロジェクト番号を取得すると良さそうです。
Cloud Buildを設定
DBとシークレットが用意できたのでアプリケーションをビルドしていきます。
ビルドにはCloud Buildを利用します。
Cloud Buildを利用するために cloudbuild.yaml
を作成し、以下を記載します。
steps: - id: "build image" name: "gcr.io/cloud-builders/docker" entrypoint: "bash" args: [ "-c", "docker build . \ -t gcr.io/${PROJECT_ID}/${_SERVICE_NAME} \ --build-arg RAILS_ENV=production \ --build-arg RAILS_MASTER_KEY=$$RAILS_KEY \ --build-arg GOOGLE_PROJECT_ID=${PROJECT_ID} \ --build-arg CLOUD_SQL_CONNECTION_NAME='${PROJECT_ID}:${_REGION}:${_INSTANCE_NAME}'", ] secretEnv: ["RAILS_KEY"] - id: "push image" name: "gcr.io/cloud-builders/docker" args: ["push", "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"] - 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 RAILS_MASTER_KEY=$$RAILS_KEY -- bundle exec rails db:migrate", ] secretEnv: ["RAILS_KEY"] substitutions: _REGION: asia-northeast1 _SERVICE_NAME: cloud-run-app-sample _INSTANCE_NAME: cloudrun-app-sample-db-instance _SECRET_NAME: sample-app-rails-master-key availableSecrets: secretManager: - versionName: projects/${PROJECT_ID}/secrets/${_SECRET_NAME}/versions/latest env: RAILS_KEY images: - "gcr.io/${PROJECT_ID}/${_SERVICE_NAME}"
設定ファイルは基本的にGCPのサンプルアプリに記載されている内容をそのまま使っています。
ここで _SERVICE_NAME
の名前は英数字か -
しか使えないので注意です。
このSEVICE_NAMEがContainer Registryに登録されるイメージの名前になります。
チュートリアルと異なる点としては環境変数周りを .env
を使って設定するのではなくdocker build時に --build-arg
で渡している点です。
--build-arg
で渡した値をイメージビルド時に活用できるようにDockerfileに以下を追記します
ARG RAILS_ENV ARG RAILS_MASTER_KEY ARG CLOUD_SQL_CONNECTION_NAME ARG GOOGLE_PROJECT_ID ENV RAILS_ENV=${RAILS_ENV} ENV RAILS_MASTER_KEY=${RAILS_MASTER_KEY} ENV CLOUD_SQL_CONNECTION_NAME=${CLOUD_SQL_CONNECTION_NAME} ENV GOOGLE_PROJECT_ID=${GOOGLE_PROJECT_ID}
こうすることでdocker build時に設定したい環境変数の値をARGとして渡して、コンテナの環境変数に設定することができます。
データベース作成時点では設定していなかったconfig/database.ymlのsocketも設定します。
Cloud SQL proxyはホストで繋ぐというよりソケット通信でDBと接続するためhostではなくsocketを設定する必要があります。
production: ~ socket: "<%= ENV.fetch("DB_SOCKET_DIR") { '/cloudsql' } %>/<%= ENV["CLOUD_SQL_CONNECTION_NAME"] %>"
Cloud BuildからCloud SQLにアクセスできるようにロールを追加しておきます。
gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:PROJECTNUM@cloudbuild.gserviceaccount.com \ --role roles/cloudsql.client
PROJECTNUM
はシークレットでアクセス権を設定した際に用いたものと同様です。PROJECT_IDは自分のGCPプロジェクトのIDを設定してください。
ここまで設定できたらいよいよCloud Buildを実行してみます。
gcloud builds submit --config cloudbuild.yaml
チュートリアルでは --substitutions
を指定していますが、cloudbuild.yamlに必要な内容は書いているので指定しなくても問題ありません。
gcloud buildsが完了すればDockerイメージがContainer Repositoryに登録され、Cloud SQLへのmigrateが完了した状態になります。
あとはCloud Runへのデプロイが完了すればWebアプリケーションが立ち上がります。
Cloud Runへのデプロイ実行
Cloud Runへのデプロイはコマンド一つで完了します。
gcloud run deploy cloud-run-app-sample \ --platform managed \ --region asia-northeast1 \ --image gcr.io/PROJECT_ID/cloud-run-app-sample --add-cloudsql-instances=CONNECTION_NAME --allow-unauthenticated
PROJECT_ID
は自身のGCPプロジェクトのID、 cloud-run-app-sample
の部分はcloudbuild.ymlで _SERVICE_NAME
で設定した値を当てはめてください。
CONNECTION_NAME
はCloudSQLのコンソールから取得できます。( PROJECT_ID:REGION:DBインスタンス名
のやつです)
※ --add-cloudsql-instances
オプションを付けないとアプリケーションアクセス時にCloud SQLに接続できずにConnection Errorとなるので注意が必要です。(私はこれを忘れて無駄にハマりました...チュートリアルにもちゃんとかいてあるのに...)
コマンド実行が完了したら最後に表示されるURLにアクセスすることでアプリケーションを表示することができます。
まとめ
Cloud Runへのデプロイができることでコンテナの設定だけしておけば簡単に外部公開できるアプリケーションができてしまいます。
チュートリアルだと.envで環境変数を設定していたり、PostgrSQLだったりとちょっと工夫したくなるところがあって微妙にハマりましたが、一回型ができてしまえばあとは無限に公開環境が作れてしまいますね!