3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Google Cloudによる安全な継続的デプロイ

Posted at

継続的デプロイに挑戦した背景

こんにちは。Papillon6814といいます。

GCP のような大型クラウドベンダーでサービスをホスティングしている人の中で、ベンダーの提供しているサービスでできるだけ一元的にインフラ環境を整えたいと考えている人の数はそう少なくないと思います。そこには人それぞれ様々な背景や動機があると思いますが、僕は「自分が今利用しているベンダーにできるだけ詳しくなりたい」という動機から、今回 Google Cloud で継続的デプロイの設定に挑戦しました。
継続的デプロイを設定したことのない人や、Google Cloud の環境整備に興味のある人にとって役立つような記事になればいいなと思っています。

Cloud BuildArtifact Registryなどの様々なサービスを扱う際、Google Cloud サポートの Lai さんに大変お世話になりました。たくさんの粗末な質問にご丁寧にお答えしていただいてありがとうございました。

使用技術

サーバーサイド開発

  • Elixir 1.13.4
  • Phoenix 1.6.6

書いていて楽しい、最強の言語とそのフレームワークです。

インフラ(Google Cloud Platform)

App Engine

Dockerfileを用意して簡単にホスティングすることができるので選びましたが、機会があれば Cloud Run に乗り換えようと思っています。Elixir の環境を整備するためにフレキシブル環境を選択しています。

Cloud SQL

本番環境の PostgreSQL のために用意しています。

Cloud Build

Github の main ブランチへの push をトリガーにして継続的デプロイを実行する、今回の要となるサービスです。

Artifact Registry

Docker のイメージを管理するためのレジストリです。Google Cloud はもともと Container Registry というサービスを提供していましたが、新しく Artifact Registry というサービスを提供し始めたのでこちらを利用しています。

Secret Manager

GCP で機密情報を扱うためのサービスです。

その他色々な細かいサービスを使っていますが、割愛させていただきます。

注意事項

デプロイの際にDockerfilecloudbuild.ymlを使用しているのですが、事情があってDockerfileは中身全体を公開していません。
せっかく記事にしているのと、Elixirのプロジェクトを Google Cloud にデプロイしているサンプルがインターネット上に多くないことから、本当はできるだけ多くの情報を公開したいのですが、すみません。

では、ここから本題に入ろうと思います。

継続的デプロイの際、シークレット変数の管理をどうするか

シークレット変数を Dockerfile で管理する

サービスのデプロイを行う際、僕たちは本番環境用データベースへの認証情報や URL など、公開したくない情報を扱わなければならないことがあります。そういった情報は git のリモートリポジトリにも上げずに、自分たちで

例えば僕はApp Engineでサービスを運用していて、継続的デプロイを設定する前は次のように機密情報を管理していました。

  • プログラム内で機密情報を記述しなければならない箇所には、System.fetch_env!/1(環境変数を取得する関数です)を用いる。
  • 本番環境用の環境変数をDockerfileに記載する。
  • Dockerfile.gitignoreに登録しておき、リモートリポジトリに環境変数のデータが入らないようにする。

複雑でない方法なのでとっつきやすく、さらにデプロイの際はgcloud app deployコマンドを使って手動で行っていたので、この管理方法でも問題なく運用することができていました。

Dockerfile での管理に行き詰まりを感じる

そう短くない間上記の方式で運用をしていましたが、サービスのユーザーが増え始めると要望の数も増え、同じくエンジニアの負担も増大していきました。なのでできるだけエンジニアの負担を軽減するために、僕たちはデプロイのような自動化できる手続きを自動化することを意識し始めました。すると機密情報の管理方式は、この方法のままだと自動化の導入に行き詰まってしまうことがわかりました。

App Engine のフレキシブル環境のデプロイを自動で実行するためには、デプロイを実施するサービス(Google Cloud でいう Cloud Build です)にDockerfileを自動で与えてあげられるようにしなければなりません。したがって、Dockerfileをリモートリポジトリに上げる必要がありました。しかし先述の通り、Dockerfile には機密情報が含まれています。この管理方法のままでは継続的デプロイの設定をすることができないので、僕たちは新しい管理方法を見つける必要がありました。

継続的デプロイの処理の手順

ではここで一度、継続的デプロイの処理が具体的にどのような手順で実行されていくかを整理してみます。
image.png

  1. Github の main ブランチへの push をトリガーとして Cloud Build が起動します。Cloud Build はcloudbuild.ymlに記載されたステップを実行してくれます。
  2. Cloud Build が Dockerfile の内容を元にイメージのビルドを開始します。
  3. ビルドしたイメージを Artifact Registry にアップロードします。
  4. Artifact Registry にアップロードしたイメージを使用してgcloud app deployを Cloud Build 上で実行します。

そして、これらのステップで使用する環境変数は Secret Manager を使って読み込みます。以上の流れをcloudbuild.ymlで記述すると次のようになります。

cloudbuild.yml
steps:
  - id: "build the container image (latest)"
    name: "gcr.io/cloud-builders/docker"
    entrypoint: 'bash'
    args: ['-c', 'docker build -t asia-northeast1-docker.pkg.dev/${PROJECT_ID}/prof/proj:latest --build-arg CLOUD_SQL_HOST="$$CLOUD_SQL_HOST" --build-arg CLOUD_SQL_PASSWORD="$$CLOUD_SQL_PASSWORD" --build-arg DATABASE_URL="$$DATABASE_URL" --build-arg SECRET_KEY_BASE="$$SECRET_KEY_BASE" --build-arg SERVICE_JSON="$$SERVICE_JSON" .']
    secretEnv: ['CLOUD_SQL_HOST', 'CLOUD_SQL_PASSWORD', 'DATABASE_URL', 'SECRET_KEY_BASE', 'SERVICE_JSON']

  - id: "build the container image (commit sha)"
    name: "gcr.io/cloud-builders/docker"
    entrypoint: 'bash'
    args: ['-c', 'docker build -t asia-northeast1-docker.pkg.dev/${PROJECT_ID}/proj/proj:${COMMIT_SHA} --build-arg CLOUD_SQL_HOST="$$CLOUD_SQL_HOST" --build-arg CLOUD_SQL_PASSWORD="$$CLOUD_SQL_PASSWORD" --build-arg DATABASE_URL="$$DATABASE_URL" --build-arg SECRET_KEY_BASE="$$SECRET_KEY_BASE" --build-arg SERVICE_JSON="$$SERVICE_JSON" .']
    secretEnv: ['CLOUD_SQL_HOST', 'CLOUD_SQL_PASSWORD', 'DATABASE_URL', 'SECRET_KEY_BASE', 'SERVICE_JSON']

  - id: "push container image (latest)"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "asia-northeast1-docker.pkg.dev/${PROJECT_ID}/proj/proj:latest"]

  - id: "push container image (commit sha)"
    name: "gcr.io/cloud-builders/docker"
    args: ["push", "asia-northeast1-docker.pkg.dev/${PROJECT_ID}/proj/proj:${COMMIT_SHA}"]

  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'bash'
    args:
    - '-eEuo'
    - 'pipefail'
    - '-c'
    - 'gcloud config set app/cloud_build_timeout 1600 && gcloud app deploy --image-url=asia-northeast1-docker.pkg.dev/${PROJECT_ID}/proj/proj:latest'
timeout: 3600s

availableSecrets:
  secretManager:
  - versionName: projects/xxx/secrets/CLOUD_SQL_HOST/versions/1
    env: 'CLOUD_SQL_HOST'
  - versionName: projects/xxx/secrets/CLOUD_SQL_PASSWORD/versions/1
    env: 'CLOUD_SQL_PASSWORD'
  - versionName: projects/xxx/secrets/DATABASE_URL/versions/1
    env: 'DATABASE_URL'
  - versionName: projects/xxx/secrets/SECRET_KEY_BASE/versions/1
    env: 'SECRET_KEY_BASE'
  - versionName: projects/xxx/secrets/E_SERVER_SERVICE_JSON/versions/2
    env: 'SERVICE_JSON'

これらの手順を踏まえて、GCP のセットアップをしていきましょう。

Google Cloud の準備

主に Cloud Build 関連の準備を行います。

Secret Manager

Cloud Build が扱う環境変数を設定するために Secret Manager に環境変数を登録していきます。
シークレットを作成を押します。

本番環境で使用するシークレット変数を登録します。直感的に登録することができるようになっています。

Cloud Build

次に Cloud Build でトリガーを設定します。
トリガーは main ブランチへの push イベントで起こるようにし、リポジトリなどの設定もしていきます。

Dockerfile と cloudbuild.yml の準備

デプロイのためのDockerfilecloudbuild.ymlを用意します。Dockerfileでは環境変数をそのまま書かずに、次のようにします。

ARG CLOUD_SQL_HOST
ARG CLOUD_SQL_PASSWORD
ENV CLOUD_SQL_HOST=$CLOUD_SQL_HOST
ENV CLOUD_SQL_PASSWORD=$CLOUD_SQL_PASSWORD

また、シークレット変数に JSON を登録している場合は次のような処理を入れて、JSON ファイルを書き出すようにします。

ARG SERVICE_JSON
ENV SERVICE_JSON=$SERVICE_JSON
...
echo $SERVICE_JSON >> /app/service_account.json

これで Dockerfile 側のシークレット変数の準備は OK です。
cloudbuild.ymlは上に記載した通りです。

GCP での設定は以上です。

main ブランチに push してデプロイ

これで継続的デプロイの設定が完了しました。
プルリクエストをマージすると Cloud Build でデプロイが走るようになっています。また、Artifact Registry にイメージが自動で push されるようにも設定しています。
ビルドの履歴は Cloud Build で閲覧することができます。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?