はじめに
今担当しているウェブシステムをGithubから社内のGitlabに移行しています。この移行に伴い、ビルドやデプロイを自動化するためCI/CDを導入しようと思っています。
導入するには、GitlabのCIやGCPのCloud buildを利用しようと思っているので、この間今週からGitlabのCIやGCPのCloud build、Cloud Runなどを触ってみました。
事前準備
- GCPのプロジェクトを作成する
- Gitlabリポジトリを作成して、サンプルコードや
Dockerfile
を用意する
今回はgo
言語で非常に簡単なウエブアプリを作りました。
ディレクトリ構成は以下のようです。
my_sample_project
│ Dockerfile
│ go.mod
| cloudbuild.yml
| main.go
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
const serverPort = 8080
func handler(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"message": "Welcome to Linkbal Advent Calendar 2020"})
}
func main() {
fmt.Printf("Starting server on port %d.....\n", serverPort)
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", serverPort), nil))
}
FROM golang:1.14.13-buster as builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
# Build the binary
RUN go build -mod=readonly -v -o server
FROM debian:buster-slim
RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
# Copy the binary to the production image from the builder stage.
COPY --from=builder /app/server /app/server
CMD ["/app/server"]
- cloudbuild.yml: Cloud Buildの構成ファイルです。後で説明します。
自動ビルド
まず、Gitlabから自動的にCloud Buildでコンテナーイメージをビルドできるようにします。
これを実現するには、以下の2つ方法あります。
1. GitlabのCIを使用しない方法
- まず、GitlabのリポジトリをGCPの
Cloud Source Repositories
にミラーリング(Mirroring)する
このGCPの公式ガイドに沿って簡単にミラーリングを設定できます。
- Cloud Buildのトリガーを使って、ソースコードを変更するたびに、自動のビルドを設定する
GCP管理画面でCloud Buildの新規トリガーを作成する
- イベント: トリガーを発火するリポジトリの3つイベントという選択肢がありますが、最後は「Githubアプリのみ」ですので、最初2つ選択肢しか選択できません。
- ブランチにpushする: 特定のブランチに対してcommitが行われたときにビルドを開始するトリガーを設定します。
- 新しいタグをpushする: 特定のタグを含むCommitが行われたときにビルドを開始するトリガーを設定します。
本番環境へのデプロイの時のみ使う場合、ブランチにpushするを選択して、masterブランチにプッシュするたびにビルドを開始するという設定でいいですが、テスト環境へのデプロイでも使いたい場合、新しいタグをpushするの方がいいですね。開発中にコードをPushするたびに、ビルド・デプロイが必要ないだから。
- リポジトリ: 上のステップにGitlabからミラーリング済みのリポジトリです。
- タグ:
.*
:全てのタグ - ビルドの構成: リポジトリ内にCloud Build 構成ファイルを指定する
Cloud Buildの構成ファイル
steps:
# コンテナーイメージをビルド
- name: "gcr.io/cloud-builders/docker"
args: [ "build", "-t", "asia.gcr.io/$PROJECT_ID/trantan_ci_example:${TAG_NAME}", "." ]
# コンテナーイメージをプッシュ
- name: 'gcr.io/cloud-builders/docker'
args: [ 'push', 'asia.gcr.io/$PROJECT_ID/trantan_ci_example:${TAG_NAME}']
images:
- "asia.gcr.io/$PROJECT_ID/trantan_ci_example:${TAG_NAME}"
logsBucket: 'gs://trantan_ci_example_cloudbuild_logs'
上のトリガーの設定でブランチにpushするを選択した場合、${TAG_NAME}
(タグ名)の代わりに、${COMMIT_SHA}
を使ってください。
この方法で、自動のビルドだけではなく、CloudFunctionsの自動デプロイでも実現できそうですね。
2. GitlabのCIを使用する方法
GCP側で設定する
まず、GCP管理画面で以下の必要な設定をします。
-
Cloud Build APIを有効にする
-
- 「Cloud Build サービス エージェント」権限ロールを付与する
- 作成したサービスアカウントに対するJSONキーを作成する
GitlabのレポジトリのCI/CDを設定する
- リポジトリにCIのRunnerを追加する:
Settings > CI/CD > Runners
- GCPの情報を保存するためのレポジトリの変数を作成する:
Settings > CI/CD > Variables
GCP_PROJECT_ID: GCPのプロジェクトID
GCP_SERVICE_KEY: 上のステップで作成したサービスアカウントのJSONキー
GitlabのリポジトリにCIを追加する
プロジェクトディレクトリーに.gitlab-ci.yml
を追加する
stages:
- test
- build
# コードフォーマット、テスト
test:
stage: test
# Lintチェックやユニットテスト実行など追加する
# ビルド
cloud_build:
stage: build
image: google/cloud-sdk
before_script:
- echo $GCP_SERVICE_KEY > gcloud-service-key.json # Google Cloud service accounts
script:
- gcloud auth activate-service-account --key-file gcloud-service-key.json
- gcloud config set project $GCP_PROJECT_ID
- gcloud builds submit . --config=cloudbuild.yml --substitutions=TAG_NAME="$CI_COMMIT_TAG"
# タグ付きコミットをプッシュした際に、行われる
# コミットをプッシュするたびに、行われる場合、このオプジョンが要らない
only:
- tags
これでタグを付けて、コミットをプッシュした際に、自動的にビルドできます。
CIのJobのログは以下の通りです。
自動デプロイ
最後、Cloud Buildでビルドしたコンテナーイメージを使用して、Cloud Runサービスを自動的にデプロイする方法を説明したいと思います。
GCPの設定を変更する
GCP管理画面で、Cloud Build > 設定
ページを開いて、サービスアカウント権限でCloud Runにデプロイできるように、Cloud Run
権限を有効にする
Cloud Buildの構成ファイルを変更する
Cloud Buildでビルドした後に、Cloud Runにビルドしたコンテナーイメージを使ってデプロイするように、以下のステップをcloudbuild.yml
ファイルのsteps
に追加する
steps:
# cloud runにデプロイ
- name: "gcr.io/cloud-builders/gcloud"
args: ['run', 'deploy', 'trantan-ci-example-app', '--image', 'asia.gcr.io/$PROJECT_ID/trantan_ci_example:${TAG_NAME}', '--region', 'asia-northeast1', '--platform', 'managed', '--allow-unauthenticated']
trantan-ci-example-app
: サービス名
結果は以下の通りです。
このサンプルのアプリはCloud Runにデプロイしましたが、ビルドしたコンテナーイメージを使って、他のサービスにもデプロイできます。例えば、僕が担当しているサービスは今GKE(Google Kubernetes Engine)上で動いてるので、CIのdeploy
ステージやジョブを追加して、gcloud
コマンドでデプロイできそうです。
おわりに
今回は検証のため、GitlabやGCPのドキュメントに参考しながらCloud BuildやCloud Runを触って、非常に簡単なサンプルのアプリだけど、自動的にビルド・デプロイを実現できました。
これから実際のサービスに導入してみようと思いますので、都合が良いときに、これに関する記事をまた書こうと思います。