はじめに
皆さんCI/CDしてますか?
今回はGoogle Cloudのマネージドサービスのみを使ってCI/CDパイプラインを構築し、アプリをCloud Runにデプロイしてみたいと思います。使うサービスは下記イラストの通りです。
※2024年3月時点での画面や機能となっており、プレビュー機能に関する記述も含みます
無料枠でCloud Buildを使用する場合は、以下のリージョンでしか使用できません。記事内では東京リージョンで作成していますが、台湾リージョンで作り直しています。
- us-central1
- us-west2
- europe-west1
- asia-east1
- australia-southeast1
- southamerica-east1
Google Cloudサービスの設定
Artifact Registry
まずはArtifact Registry APIを有効にしましょう
APIを有効にしてコンソール画面にアクセスすると、このような画面が表示されるはずです。オプションを有効にするとイメージあたり$0.26で脆弱性スキャンをしてくれます。今回は省略しますが、必要に応じて有効化してよいでしょう。
「+リポジトリを作成」ボタンを押下し、今回は以下のように設定し、画面左下部の「+作成」ボタンを押下してリポジトリの作成をしていきます。
項目 | 設定値 |
---|---|
名前 | 任意の名前 |
形式 | Docker |
モード | 標準 |
リージョン | 任意のリージョン |
暗号化 | Google が管理する暗号鍵 |
不変のイメージタグ
このオプションを有効にすると、タグ付きイメージを削除したり、タグをイメージから削除するといったことができなくなります。今回は不要な設定なのでオフにします。
クリーンアップポリシー
このオプションを有効にすると、アーティファクトバージョンを削除するポリシーを設定することができます。例えば、アップロードから30日経過したアーティファクトバージョンを自動的に削除するといったことができるようになります。今回は特に設定しません。
これでリポジトリの作成は完了です。
Cloud Source Repositories
コンソール上部から「Cloud Source Repositories」と検索して画面遷移すると、見慣れたコンソール画面とは少し違う画面に遷移します。早速「開始」>「リポジトリを作成」という順に押していきます。
「新しいリポジトリを作成」を選択し、「続行」を押下します。
任意のリポジトリ名とプロジェクトIDを設定し、「作成」を押下します。
今回はクローンを作成する手順で、認証方法はGoogle Cloud SDKで進めていきます。
Google Cloud SDKを使用して認証を行った後、画面のコマンドに従って操作していきます。pushが完了したらブラウザを再起動してみます。
適当にpushしたREADME.mdのコミットが反映されていることが分かります。
次にCloud Buildの設定に移ります。
Cloud Build
Artifact Registryと同じようにCloud Build APIを有効にします。
次にCloud Buildのトリガーを作成していきます。
「+トリガーを作成」を押下します。
以下のように設定をして画面左下の「作成」を押下します。
項目 | 設定値 |
---|---|
名前 | 任意の名前 |
リージョン | 任意のリージョン |
イベント | ブランチにpushする |
ソース | 第1世代 |
リポジトリ | 作成したリポジトリを選択 |
ブランチ | ^main$ |
構成 | Cloud Build 構成ファイル(yaml または json) |
ロケーション | 作成したリポジトリを選択 |
Cloud Build 構成ファイルの場所 | cloudbuild.yaml |
※Cloud Source Repositories からリポジトリを接続できるのは、Cloud Build リポジトリ(第1世代)
のみです。
権限設定
Cloud Buildトリガーを使用してCloud Runにデプロイするためには、Cloud Buildのサービスアカウント権限からCloud Run 管理者
とサービス アカウント ユーザー
を有効にする必要があります。
この設定をしないと、トリガーを使用したデプロイ時に以下のようなエラーが出てデプロイすることができません。
ERROR: (gcloud.run.deploy) PERMISSION_DENIED: Permission 'run.services.get' denied on resource 'namespaces/{project名}/services/{service名}' (or resource may not exist).
cloudbuild.yamlの作成
今回作成したファイルは以下です。
substitutionsを変更するだけでそのまま使えると思います。
--allow-unauthenticated
を設定すると、未認証の呼び出しが許可できます。今回は簡単のために設定します。
steps:
# コンテナイメージのビルド
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', '${_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_REPOSITORY}/${_IMAGE_NAME}:$COMMIT_SHA', '.']
# コンテナイメージをArtifact Registryにプッシュ
- name: 'gcr.io/cloud-builders/docker'
args: ['push', '${_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_REPOSITORY}/${_IMAGE_NAME}:$COMMIT_SHA']
# コンテナイメージをCloud Runにデプロイ
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args:
- 'run'
- 'deploy'
- '${_SERVICE_NAME}'
- '--image'
- '${_REGION}-docker.pkg.dev/${_PROJECT_ID}/${_REPOSITORY}/${_IMAGE_NAME}:$COMMIT_SHA'
- '--region'
- '${_REGION}'
- '--allow-unauthenticated'
substitutions:
_REGION: {リージョン}
_PROJECT_ID: {プロジェクトID}
_REPOSITORY: {ArtifactRegistryのリポジトリ}
_IMAGE_NAME: {イメージ名}
_SERVICE_NAME: {CloudRunサービス名}
サンプルアプリ作成
簡単なHTTPサーバーを作成し、ルートパスにアクセスすると"Hello, World!"と表示するGoアプリケーションをデプロイしたいと思います。
.
├── cloudbuild.yaml
├── Dockerfile
├── main.go
├── go.mod
└── README.md
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello, World!")
})
fmt.Println("Server started on http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
FROM golang:1.21
WORKDIR /app
COPY go.mod ./
RUN go mod download
COPY . .
RUN go build -o main
EXPOSE 8080
CMD ["./main"]
いざ実行
Cloud Source Repositoriesにpushします😎
git push origin main
Cloud Buildの履歴画面を見ると、作成したCloud Buildトリガーによってビルドが行われています👏
ArtifactRegistryにもイメージが格納されていますね!
Cloud Runの画面を見に行くと、たしかにデプロイされています💪
デプロイしたサービス名を押下し、URLをコピーしてcurlを叩くと...
❯ curl https://matsuidev-service-hello-2vpsyoh4ca-de.a.run.app/
Hello, World!
無事に表示されました👏👏👏
おわりに
いかがでしたでしょうか。
今回はGoogleCloudのマネージドサービスである「Artifact Registry」「Cloud Source Repositories」「Cloud Build」を組み合わせ、mainブランチにpushするとCloud RunへのデプロイまでしてくれるCI/CDパイプラインを作成してみました。
今回はCloud Runにデプロイしましたが、cloudbuild.yaml
を書き換えることで GKE や Cloud Functions などにもデプロイすることが可能です!
最後まで読んでいただきありがとうございました😸