こんにちは、青木です。
最近Cloud Runが盛り上がっているようですので、実際に触ってみました。
この記事に書いてあること
本記事を通して、最終的に以下を実現できるようになると思います。
- Cloud Runでサービスを稼働させる
- DockerイメージをArtifact Registryで管理する
- Cloud Runの自動デプロイをする
使用するサービス
今回使用するGoogle Cloudのサービスは以下です。
- Cloud Run
- Cloud Source Repositories
- Artifact Registry
- Cloud Build
Cloud Source Repositoriesはソースコードの管理に使用します。
Artifact RegistryはDockerイメージの管理に使用します。
Cloud BuildはDockerイメージのデプロイに使用します。
それぞれサービスの詳細はここでは控えますが気になる方はドキュメントを参照いただけばと思います。
環境変数の作成
本日の作業はコマンドラインで行い、確認はコンソールでやっていきたいと思います。
最初に環境変数をセットしておきます。
IDEはCloud Shellを利用しました。
PROJECT=[project id] REGION=asia-northeast1 REGISTRY_NAME=aoki-images IMAGE_NAME=test SOURCE_REPO=cloud-run-sample TRIGGER_NAME=aoki-test-trigger
Artifact Registryの準備
Dockerイメージを管理するためのArtifact Registryを作っていきたいと思います。
今回はaoki-imagesという名前のRegistryを作ります。
gcloud artifacts repositories create $REGISTRY_NAME --repository-format=docker --location $REGION --description="Docker repository" --project $PROJECT
サービスの有効化を求められた場合は、許可します。
Would you like to enable and retry (this will take a few minutes)? (y/N)? y
無事作成されました。
Cloud Source Repositoriesの準備
ソースコードを管理するためのCloud Source Repositoriesを作っていきたいと思います。
今回はcloud-run-sample という名前のリポジトリを作ります。
gcloud source repos create $SOURCE_REPO --project $PROJECT
無事に作成されました。
ローカルにクローンします。
gcloud source repos clone $SOURCE_REPO --project $PROJECT
クローンしたローカルリポジトリに移動して認証します。
cd cloud-run-sample gcloud init
ローカルリポジトリにファイルを追加します。
- main.py - requirements.txt - .dockerignore - Dockerfile
main.py
import os from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): name = os.environ.get("NAME", "World") return "Hello {}!".format(name) if __name__ == "__main__": app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
requirements.txt
Flask==2.1.0 gunicorn==20.1.0
.dockerignore
Dockerfile README.md *.pyc *.pyo *.pyd __pycache__ .pytest_cache
Dockerfile
FROM python:3.10-slim ENV PYTHONUNBUFFERED True ENV APP_HOME /app WORKDIR $APP_HOME COPY . ./ RUN pip install --no-cache-dir -r requirements.txt CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
リモートリポジトリにファイルをPushしておきます
git add . git commit -m "first commit" git push origin master
リポジトリが更新されたことを確認します。
Cloud Buildにトリガーを仕込む
やっと本題です。
Dockerイメージの自動デプロイを実現するにはリポジトリへのPushイベントを拾う必要があります。
Google CloudではCloud Buildでトリガーさせることができます。
今回は、aoki-test-triggerという名前のトリガーを作っていきたいと思います。
gcloud beta builds triggers create cloud-source-repositories --name=$TRIGGER_NAME --repo=$SOURCE_REPO --branch-pattern="^master$" --dockerfile="Dockerfile" --dockerfile-dir="" --dockerfile-image=asia-northeast1-docker.pkg.dev/$PROJECT/$REGISTRY_NAME/$IMAGE_NAME:latest --project $PROJECT --region $REGION
トリガーの中身ですが、イメージ名に「asia-northeast1-docker.pkg.dev」が入力されてほしいのですが、なぜか「gcr.io」になってしまいます・・・
今回は手で修正しました。
Dockerイメージをビルド
ではDockerイメージをビルドしていきたいと思います。
main.pyを少し編集して(例:Hello Workd→Hello World!!)から、Pushします。
git add . git commit -m "build image test" git push origin master
ビルドの結果を見ると、無事成功しました
成功したらトリガーを消しておきます。
gcloud beta builds triggers delete $TRIGGER_NAME --project $PROJECT --region $REGION
ここまでの課題
ここまでで、ソースコードをPushすることで、Dockerイメージをビルドするところまでいけました。
しかし、実際はDockerイメージをビルドして、Cloud Runで稼働させるところまでいきたいですよね。
Cloud Runへ自動デプロイする
Dockerイメージを実行する環境としてCloud Runを使用してみたいと思います。
Artifact Registryに保管されたコンテナを起動してみる
まずは先程保管したものをCloud Runで起動してみたいと思います。
gcloud run deploy helloworld --image asia-northeast1-docker.pkg.dev/$PROJECT/$REGISTRY_NAME/$IMAGE_NAME:latest --allow-unauthenticated --platform managed --region $REGION --project $PROJECT
Cloud Runが稼働したことを確認します。
Cloud Runのエンドポイント
Build→Push→Deployを続けてやってみる
単純にデプロイするのは上記のとおりですが、自動デプロイは一工夫いります。
自動デプロイされたDockerイメージをCloud Run環境にデプロイするにはCloud Buildのトリガー内容を変更します。
流れの処理を行うために、以下のファイルを作成します。
YAML形式でステップを定義しており、イメージのビルド、プッシュ、最後にデプロイをするように記載しております。
cloudbuild.yaml
steps: # Build the container image - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest', '.'] # Push the container image to Artifact Registry - name: 'gcr.io/cloud-builders/docker' args: ['push', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest'] # Deploy container image to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: ['run', 'deploy', 'helloworld', '--image', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest', '--allow-unauthenticated', '--region', 'asia-northeast1', '--tag', 'blue'] images: - asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest
ファイルを作成したら、以下を実行し、新しくトリガーを作成します。
gcloud beta builds triggers create cloud-source-repositories --name=$TRIGGER_NAME --repo=$SOURCE_REPO --branch-pattern="^master$" --build-config="cloudbuild.yaml" --project $PROJECT --region $REGION
権限の付与
Cloud Runにデプロイにする前に、Cloud Build→Cloud Runでデプロイできるように権限を付与します。
Cloud Run管理者を有効にします。
Let’s 自動デプロイ!
ではちゃんと動くか試したいと思います。
main.pyを少し編集してから、Pushします。
git add . git commit -m "deploy Cloud Run test" git push origin master
セキュリティ対策
続いて、ビルドされたコンテナイメージをスキャンしてセキュリティを高めてみます。
Artifact Registryにはイメージのセキュリティスキャン機能が備わっていますので、今回はそちら利用していきたいと思います。
こちらの操作にはオンデマンド管理者のロールが必要となるので、プロジェクト内のcloudbuild.gserviceaccount.comのサービスアカウントに権限を付与します。
また、APIの有効化が必要ですので以下にアクセスし有効化しておきます。
cloudbuild.yamlを以下のように変更します
steps: # Build the container image - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest', '.'] - id: scan name: gcr.io/google.com/cloudsdktool/cloud-sdk entrypoint: /bin/bash args: - -c - | gcloud artifacts docker images scan asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest \ --format='value(response.scan)' > /workspace/scan_id.txt - id: severity check name: gcr.io/google.com/cloudsdktool/cloud-sdk entrypoint: /bin/bash args: - -c - | gcloud artifacts docker images list-vulnerabilities $(cat /workspace/scan_id.txt) \ --format='value(vulnerability.effectiveSeverity)' | if grep -Fxq $_SEVERITY; \ then echo 'Failed vulnerability check' && exit 1; else exit 0; fi # Push the container image to Container Registry - name: 'gcr.io/cloud-builders/docker' args: ['push', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest'] # Deploy container image to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: ['run', 'deploy', 'helloworld', '--image', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest', '--region', 'asia-northeast1', '--allow-unauthenticated', '--region', 'asia-northeast1', '--tag', 'blue'] images: - asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest
これを実行することで、コンテナイメージの脆弱性検知ができるそうです。
いいですね。
git add . git commit -m "security scan test" git push origin master
SCANは以下のようにscanステップで確認できます。
成功したらトリガーを消しておきます。
gcloud beta builds triggers delete $TRIGGER_NAME --project $PROJECT --region $REGION
承認プロセスを追加
ここまで自動デプロイしてしまいましたが、
本番環境へのデプロイは承認プロセスを追加したいものですね。
以下のように新しいトリガーを作成し、承認プロセスを追加してみたいと思います。
gcloud beta builds triggers create cloud-source-repositories --name=$TRIGGER_NAME --repo=$SOURCE_REPO --branch-pattern="^master$" --build-config="cloudbuild.yaml" --project $PROJECT --require-approval --region $REGION
git add . git commit -m "approval test" git push origin master
承認はCloud Buildのダッシュボードから確認ができます。
Blue/Greenデプロイに変えてみる
さらに、本番環境にデプロイすることを考えると、段階的なデプロイにしてみたいですね。
Cloud Runでの段階的なデプロイにチャレンジしてみたいと思います。
既存バージョンをBlue、新しいバージョンをGreenと前提とし、新しいバージョンをデプロイするために以下のようにcloudbuild.yamlを書き換えます。
steps: # Build the container image - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest', '.'] # Push the container image to Container Registry - name: 'gcr.io/cloud-builders/docker' args: ['push', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest'] # Deploy container image to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: ['run', 'deploy', 'helloworld', '--image', 'asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest', '--allow-unauthenticated', '--region', 'asia-northeast1', '--no-traffic', '--tag', 'green'] images: - asia-northeast1-docker.pkg.dev/[project_name]/aoki-images/test:latest
ポイントは新しいバージョンにタグを追加し、no-trafficオプションを指定しているところです。
これがデプロイされてもトラフィックは転送されません。
ではデプロイしてみます。
git add . git commit -m "blue/green test" git push origin master
新しいバージョンにデプロイできましたね。
しかしこれでは新しいバージョンのテストができないですよね・・・
実は新しいバージョンをテストしたい場合は以下のようなFQDNでアクセスできます。tagname-がFQDNにつくようです。
新しいバージョンが正しく操作することが確認できた際は、少しづつトラフィックを増やしていきたいですね。
新しいバージョンにトラフィックを寄せていく方法は以下です。
gcloud beta run services update-traffic helloworld --to-tags green=10 --region $REGION --project $PROJECT
成功したらトリガーを消しておきます。
gcloud beta builds triggers delete $TRIGGER_NAME --project $PROJECT --region $REGION
リソースの削除
最後に作成したリソースを削除しておきたいと思います。
リポジトリを削除します。
gcloud source repos delete $SOURCE_REPO --project $PROJECT
Artifact Registryを削除します。
gcloud artifacts repositories delete $REGISTRY_NAME --location $REGION --project $PROJECT
Cloud Runのサービスを削除します。
gcloud run services delete helloworld --region $REGION --project $PROJECT
さいごに
今回はCloud Runにリリースする方法を調べてみました。
次回はGKEと絡めてみたいな、と思っています。
ありがとうございました。