CI/CDパイプライン - GitHub, CircleCIの連携とGCP(GCR)へのプッシュ
下記の技術を使い、CI/CDパイプラインを構築中です。
- Docker
- GitHub
- CircleCI
- GCR(Google Container Registry)
- GKE(Google Kubernetes Engine)
- Spinnaker
コンテナ化したGoアプリのソースコードをGitHubにプッシュし、CircleCIでジョブを実行し、GCRにdockerのイメージをプッシュ。Spinnkerでイメージの更新を検知し、最後にGKEへデプロイするというフローで構築しています。
この記事ではGitHubとCircleCI、GCPの連携までをまとめます。
ディレクトリ構成
下記のようなディレクトリ構成で試しました。
.
├── .circleci
│ └── config.yml
├── code
│ └── cmd
│ └── web
│ └── main.go
├── df-go.dockerfile
└── docker-compose.yml
.circleci/config.yml
CircleCIのジョブを実行するためのファイルです。CircleCIとGitHubを連携したのち、GitHubへプッシュすると、ここで設定したジョブが実行されます。
version: 3
jobs:
build:
docker:
- image: circleci/golang:1.13
working_directory: /go/src/github.com/hodanov/ci-cd-test
steps:
- checkout
- run: go get -v -t -d ./...
# テストコードを書いていれば`go test`でテストが実行され、エラーが出ればジョブが失敗する。
- run: go test -v ./...
main.go
Goのソースコードです。簡易なWebサーバーが起動します。
package main
import (
"fmt"
"net/http"
)
func hoge(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hogehoge")
}
func top(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello")
}
func main() {
http.HandleFunc("/", top)
http.HandleFunc("/hoge", hoge)
http.ListenAndServe(":8080", nil)
}
df-go.dockerfile
dockerファイルです。 /go/src/go-web-server
というディレクトリにGoのソースコードをコピーし、ビルドを実行後、 CMD
でアプリケーションを実行させます。
FROM golang:1.13-alpine
WORKDIR /go/src/go-web-server
COPY ./code .
RUN go get -d -v ./... \
&& go install -v ./... \
&& go build -o go-web-server ./cmd/web
CMD ["./go-web-server"]
docker-compose.yml
ローカルPCで挙動を確認するために用意しました。デプロイでは使いません。
version: '3'
services:
go:
container_name: go-ci-cd-test
build:
context: .
dockerfile: df-go.dockerfile
tty: true
ports:
- 8080:8080
GitHubリポジトリの作成
リポジトリを作成し、プッシュします。この段階では特に変わった設定必要ないです。
GCPの設定
gloud
コマンドを使い、CLIで設定を進めます。
Cloud SDKのセットアップ
Google Cloud SDKはGCPのリソースを管理するためのツール。手元のPCにインストールすることで、GCPをCLIで操作できます。
↓下記ドキュメントでインストールし、 gcloud auth list
や gcloud config list
コマンドで設定が確認できればOK。
https://cloud.google.com/sdk/docs/
途中でプロジェクトを選択する必要があるので、GCPのプロジェクトがない場合は下記コマンドで作成します。
gcloud projects create your-gcp-project-id
# your-gcp-project-idは自分で決めた適当なプロジェクトIDに置き換える
プロジェクトとゾーンをデフォルトに設定
gcloud
コマンドを実行する際のプロジェクトとゾーンを設定します。
gcloud config set project your-gcp-project-id
gcloud config set compute/zone asia-northeast1-b
# asia-northeast1-bは東京リージョン
gcloud config list
で設定を確認できます。
プロジェクトの課金設定とAPIの有効化
操作するリソースに対してAPIを有効にするため、GCPの課金設定をします。
https://cloud.google.com/billing/docs/how-to/manage-billing-account?hl=ja
課金設定後、下記コマンドでAPIを有効にし、請求先アカウントとプロジェクトを紐付けます。
# APIを有効化
gcloud compute zones list
# APIを有効後、下記コマンドで課金設定が有効化どうかを確認
gcloud beta billing accounts list
# 請求先アカウントとGCPプロジェクトの紐づけ
gcloud beta billing projects link your-gcp-project-id --billing-account xxxxx-yyyyy-zzzzz
GitHubとCircleCIの連携
CircleCI へGitHubのアカウントでログイン。前項で作成したGitHubのリポジトリを選んで Set Up Project
を選択、その後 Start build
し、表記にしたがって設定を進めます。
設定が完了するとリポジトリへのpushをトリガーにジョブが実行されるようになります。
GitHub上でプルリクを出すと下図のようにCircleCIのチェックが確認できます。
CircleCIとGCRの連携
CircleCIからGCRへdockerイメージをプッシュできるようにします。
Cloud SDKの認証
CircleCIからGCRやGKEを操作する際にCloud SDKを使います。
google/cloud-sdk
GCPのCloudIAMというサービスで提供されている サービスアカウント
という認証方式を使います。
GCPのCloudIAMとサービスアカウント
CloudIAMはGCPで提供されている権限管理の仕組み。サービスアカウントはCloudIAMが提供する認証方式で、GCP上にホストされているリソース同士のアクセスや外部サービスからのアクセスの権限管理に利用するアカウント
サービスアカウントの作成
↓サービスアカウントの作成
# サービスアカウントの作成
gcloud iam service-accounts create circleci --display-name circleci
# サービスアカウントのリストを確認
gcloud iam service-accounts list
ロールの付与
作成したサービスアカウントに対しGCRへプッシュする権限を付与します。
Container Registry の操作に必要な権限と役割
# roles/strage.adminを付与
gcloud projects add-iam-policy-binding your-gcp-project-id --member serviceAccount:circleci@your-gcp-project.iam.gserviceaccount.com --role roles/storage.admin
# IAMポリシーの確認
gcloud projects get-iam-policy your-gcp-project-id
CircleCIにサービスアカウントを登録
次に、CircleCIにGCPのサービスアカウントを登録します。下記コマンドで秘密鍵を生成し、CircleCIに環境変数として設定します。
# ↓circleci.jsonという名前で秘密鍵の情報が作成されます。
gcloud iam service-accounts keys create --iam-account circleci@your-gcp-project.iam.gserviceaccount.com ./circleci.json
↓CircleCIの環境変数登録画面。Project Settingsを開いて、上で生成したjsonを登録。ここで登録した環境変数は、CircleCIのジョブで参照することができます。
GCRへプッシュするジョブの登録と実行
CircleCIからGCRへdockerイメージをpushするためにGCRのAPIを有効にします。
# GCRのAPIを有効化
gcloud services enable containerregistry.googleapis.com
# 設定の確認
gcloud services list --enabled
.circleci/config.yml
を下記に上書きします。GCRへプッシュするための設定をし、イメージをビルド→GCRへプッシュするジョブです。
version: 2
jobs:
build:
working_directory: /go/src/github.com/hodanov/ci-cd-test
docker:
- image: google/cloud-sdk
steps:
- checkout
# ↓CircleCI上でdocker、docker-composeコマンドを利用するための設定
- setup_remote_docker:
version: 18.06.0-ce
- run:
name: Setup CLOUD SDK
command: |
# CircleCIの環境変数に登録したサービスアカウントの値を`echo`して`gcloud auth`に渡す。
# `gcloud auth ... --key-file=-`はCLOUD SDKの認証にサービスアカウントを利用するための設定
echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
gcloud --quiet config set project your-gcp-project-id
gcloud --quiet config set compute/zone asia-east1-b
# ↓dockerのCredential helpersを利用。GCRなどのDocker Registry向けの認証を`docker login`コマンドなしで提供できるようにする設定
gcloud --quiet auth configure-docker
- run:
name: Push docker image
command: |
docker image build -t go-web-server .
TAG=gcr.io/your-gcp-project-id/go-web-server:pushed-`date +%!Y(MISSING)%!m(MISSING)%!d(MISSING)%!H(MISSING)%!M(MISSING)%!S(MISSING)`
docker image tag go-web-server $TAG
docker image push $TAG
LATEST_TAG=grc.io/your-gcp-project-id/go-web-server:latest
docker image tag go-web-server $LATEST_TAG
docker image push $LATEST_TAG
config.ymlを更新したらGitHubへプッシュして、GCRへイメージがプッシュされることを確認します。
# プッシュされたdockerイメージのリスト
gcloud container images list
# 指定したイメージのタグを確認
gcloud container images list-tags gcr.io/your-gcp-project-id/go-web-server
まとめ
何回かの失敗の末、ジョブの実行が成功し、GCRへプッシュできました。
次はGCR→spinnaker→GKEの連携を試します。