📕

Cloud Run を本番運用するための準備

に公開

はじめに

  • 新規サービスを開発・公開する
  • 小規模サービスなので、コストは最小限にしたい
  • そもそも管理するサーバーを増やしたくない
  • サーバーレス開発を試してみたい

ということが重なったので、Google Cloud Run のRails環境を利用して、新規サービスの開発をしました。
基本的には、GoogleCloudの公式ドキュメントに沿って構築をしましたが、運用をするにあたって準備したことを備忘を込めてまとめたいと思います。

環境ごとに設定ファイルを用意

開発、テスト、公開環境を想定して、公式ドキュメントに付随するサンプルコードをもとに設定ファイルをそれぞれ作成します。

  • docker-compose.yml
  • Dockerfile.dev
  • Dockerfile.test
  • Dockerfile.prod

Dockerイメージを作成するためのファイル。
docker-compose.yml内では、開発環境用のDockerfile(Dockerfile.dev)を読み込むようにして開発環境を構築します。
Dockerfile.testとDockerfile.prodは、サンプルコードのDockerfileを基にして、RAILS_ENVの値のみ環境に合わせて変更して使いました。

  • cloudbuild.yaml.test
  • cloudbuild.yaml.prod

Cloud Build でコンテナイメージをビルドする際につかうファイル。
サンプルコードのcloudbuild.yamlからは、dockerをビルドする際に仕様するDockerfileを設定するように書き換えました。

cloudbuild.yaml.XXX
- args: ["-c", "docker build --build-arg MASTER_KEY=$$RAILS_KEY -t gcr.io/${PROJECT_ID}/${_SERVICE_NAME} . "]
+ args: ["-c", "docker build -f ./Dockerfile.xxx --build-arg MASTER_KEY=$$RAILS_KEY -t gcr.io/${PROJECT_ID}/${_SERVICE_NAME} . "]
  • config/environments/test.rb

環境設定ファイルを本番環境(config/environments/production.rb)に合わせます。
ログ出力の設定を標準出力に設定することで、Cloud Runと連携しているCloud Loggingにログを出力できるようになります。

config/environments/test.rb
  # config.action_view.annotate_rendered_view_with_filenames = true
+
+  # Include generic and useful information about system operation, but avoid logging too much
+  # information to avoid inadvertent exposure of personally identifiable information (PII).
+  config.log_level = :debug
+
+  # Prepend all log lines with the following tags.
+  config.log_tags = [:request_id]
+
+  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+  # the I18n.default_locale when a translation cannot be found).
+  config.i18n.fallbacks = true
+
+  # Send deprecation notices to registered listeners.
+  config.active_support.deprecation = :notify
+
+  # Log disallowed deprecations.
+  config.active_support.disallowed_deprecation = :log
+
+  # Tell Active Support which deprecation messages to disallow.
+  config.active_support.disallowed_deprecation_warnings = []
+
+  # Use default logging formatter so that PID and timestamp are not suppressed.
+  config.log_formatter = ::Logger::Formatter.new
+
+  # Use a different logger for distributed setups.
+  # require "syslog/logger"
+  # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
+
+  if ENV["RAILS_LOG_TO_STDOUT"].present?
+    logger           = ActiveSupport::Logger.new $stdout
+    logger.formatter = config.log_formatter
+    config.logger    = ActiveSupport::TaggedLogging.new logger
+  end
end

ビルド時の注意

gitignoreに登録しているディレクトリ・ファイルは Cloud Build時にも除外されるようです。
.envファイルをgitignoreに登録している場合は、ビルド前にコメントアウトします。

mysqlを使う場合

サンプルコードのdatabase.yamlはPostgreSQL用になっているので、MySQL使う場合は、socketとhostを修正します。

database.yaml
production:
  <<: *default
  database: <%= ENV["PRODUCTION_DB_NAME"] %>
  username: <%= ENV["PRODUCTION_DB_USERNAME"] %>
  password: <%= Rails.application.credentials.gcp[:db_password] %>
-  host: "<%= ENV.fetch("DB_SOCKET_DIR") { '/cloudsql' } %>/<%= ENV["CLOUD_SQL_CONNECTION_NAME"] %>"
+  socket: <%= ENV["CLOUD_SQL_CONNECTION_NAME_PROD"] %>
+  host: localhost

ベーシック認証の設定

ベーシック認証の設定は、Rails側で設定しました。

application_controller.rb
class ApplicationController < ActionController::Base
+  http_basic_authenticate_with name: ENV['BASIC_AUTH_USERNAME'], password: Rails.application.credentials.basic_auth[:password] unless Rails.env.production?

パスワードは、config/credentials.yml.encに保存します。

sudo docker-compose run app rails credentials:edit

コールドスタート対策

処理するリクエストがなければ、Cloud Run はしばらくしてから未使用のコンテナを終了します。これはつまり、コールドスタートが発生する可能性があるということです。

公式ブログにもあるように、リクエストがないときは、インスタンス数が0までスケールインして、コールドスタートが発生します。コールドスタート時は表示までに20−30秒掛かります。

最小インスタンス数を1以上に設定して常時ウォーム状態にすることもできますが、サーバーレスサービスのコストメリットを受けるため、コールドスタートにならないようにcloud schedulerを使って定期的に(15分に1度)リクエストを送ります。

Discussion