GAE/GoをCircleCI2.0経由でdeploy

timakin
9 min readNov 3, 2017

--

概要

GAE/GoでAPI書いていると、必ずデプロイフローの問題にぶつかると思います。

CircleCIがDockerコンテナベースでのビルドなので、それと合わせてGAEのデプロイを成功させるにはどうすればいいのか、設定ファイルと合わせて共有します。

CircleCIとAppEngine

AppEngineにdeployするとき、必ずGoogle Cloud SDKをインストールしたり、deploy権限を持ったユーザーでのログインなどが問題になります。

なので、まずGoogle Cloud SDKが入ったdocker imageを用意する必要があります。

ローカルから各プロジェクトへのデプロイをする場合には、手元のCLIでauth loginすればいいのですが、CircleCIのdocker container上からは別の方法を取ることになります。

mercari/docker-appengine-go

自作でGAEにdeployするためのdockerイメージのDockerfileを書こうとしたこともあったのですが、ややだるかったので、ぼーっとしていたところ、メルカリさん(というか作者の@_zchee_ さんおよび@sotanard さん)が作ってくれていたようで、それを使うと簡単にdeployフローが構築できます。

サービスアカウント

デプロイに際して、デプロイ権限を持ったサービスアカウントのJSONを書き出す必要があります。

サービスアカウントの発行方法は、以下の記事に書いてありますので、ご確認ください。

ビルド用の環境変数の設定

サービスアカウントを用いたGAEへのデプロイで必要なパラメーターとして、「サービスアカウントのemail」と「アカウントのJSON」の2つを用意しなければいけません。

今回は試しにdevサーバーにdeployするためのフローを作るために、「DEV_SERVICE_ACCOUNT_CLIENT_EMAIL」と「DEV_SERVICE_ACCOUNT_KEY」という値を用意してみましょう。

例としては、

DEV_SERVICE_ACCOUNT_CLIENT_EMAIL: {PROJECT名}@appspot.gserviceaccount.com
DEV_SERVICE_ACCOUNT_KEY: サービスアカウントのJSON十数行の改行を無くして1行にまとめたもの

を、CircleCIの Environment Variables から設定します。

circle.yml

circle.yml全文は下記になります。

version: 2.0
references:
container_config: &container_config
docker:
- image: mercari/appengine-go:1.8
environment:
PROJECT_ROOT: /go/src/github.com/timakin/sample_api
APP_NAME: sample_api
VENDORING_CACHE_PATH: /go/src/github.com/timakin/sample_api/vendor
working_directory: /go/src/github.com/timakin/sample_api

workspace_root: &workspace_root
/tmp/workspace

attach_workspace: &attach_workspace
attach_workspace:
at: *workspace_root

save_workspace: &save_workspace
run:
name: load code from temporary directory
command: |
mkdir -p /tmp/workspace/sample_api
mv * .[!.]* /tmp/workspace/sample_api/

load_code: &load_code
run:
name: load code from temporary directory
command: |
# Move all files and dotfiles to current directory
mv /tmp/workspace/sample_api/* /tmp/workspace/sample_api/.[!.]* .

go_vendoring_cache_params: &go_vendoring_cache_params
key: go-vendoring-{{ .Branch }}-{{ checksum "Gopkg.lock" }}
paths:
- /go/src/github.com/timakin/sample_api/vendor

dep_ensure: &dep_ensure
run:
name: Vendoring
command: |
if [ ! -e ${VENDORING_CACHE_PATH} ]; then
go get -u github.com/golang/dep/cmd/dep
dep ensure -v
fi

deploy_to_dev: &deploy_to_dev
run:
name: Hook an event of deployment
command: |
if [ "${CIRCLE_BRANCH}" == "develop" ]; then
echo $DEV_SERVICE_ACCOUNT_KEY > /tmp/secret.json
gcloud auth activate-service-account $DEV_SERVICE_ACCOUNT_CLIENT_EMAIL --key-file /tmp/secret.json
appcfg.py --oauth2_access_token $(gcloud auth print-access-token) update ./services/api/appengine/dev.yaml
fi

vet_and_test: &vet_and_test
run:
name: Validate go source
command: |
go vet $(go list ./... | grep -v /vendor/)
go test -race $(go list ./... | grep -v /vendor/)

jobs:
checkout_code:
<<: *container_config
steps:
- checkout
- *save_workspace
- persist_to_workspace:
root: *workspace_root
paths:
- sample_api
vendoring:
<<: *container_config
steps:
- *attach_workspace
- *load_code
- restore_cache:
<<: *go_vendoring_cache_params
- *dep_ensure
- save_cache:
name: Saving Cache - vendor
<<: *go_vendoring_cache_params
- *save_workspace
- persist_to_workspace:
root: *workspace_root
paths:
- sample_api
deployment:
<<: *container_config
steps:
- *attach_workspace
- *load_code
- *vet_and_test
- *deploy_to_dev

workflows:
version: 2
build_and_test:
jobs:
- checkout_code
- vendoring:
requires:
- checkout_code
- deployment:
requires:
- vendoring

重要なところだけピックアップしますと、下記がdeployを実行する箇所です

echo $DEV_SERVICE_ACCOUNT_KEY > /tmp/secret.json
gcloud auth activate-service-account $DEV_SERVICE_ACCOUNT_CLIENT_EMAIL --key-file /tmp/secret.json
appcfg.py --oauth2_access_token $(gcloud auth print-access-token) update ./services/api/appengine/dev.yaml

これは何をしているかというと、

  1. /tmp/secret.json に一時的に環境変数から取り出したサービスアカウントのJSONを格納しておく
  2. JSONを使ってサービスアカウントを有効にする
  3. 有効にしたサービスアカウントを元に、指定したAppEngineサービスをデプロイする

という流れで、デプロイを行なっています。

まとめ

AppEngineのDockerコンテナからのdeployは多少工夫が必要ですが、適切なdocker imageさえ選んでおけば、あとはサービスアカウントの有効化さえすれば済みます。

上記で誤りがあれば、ご指摘ください。

--

--