GAE/Goの開発環境について
2019.03.19
GAE/Goの開発を進めていくための環境構築について考えてみました。
前回はGAE/GoとFirebaseで認証付きAPIを実装するコードについて書きましたが、今回はこのコードを踏まえてGAE/GoとFirebaseで開発するための環境構築についてまとめてみます。
ローカル開発環境
GAE向けのコードは dev_appserver.py
というコマンドを使うことでローカル環境で実行することができます。
デプロイするためには認証が必要ですが、ローカル環境で動かすだけであれば不要です。
また、GAE/Goの環境と合わせるためGoのバージョンは1.11としています。
このあたりの開発環境の設定は各自よしなにでもいいのですが、複数人で開発するときは各自の環境には多かれ少なかれ差異がありますし、なにか変更があった場合なども都度やりとりが発生するのは面倒なので、基本的にはDockerを使って開発環境を統一できるようにしています。
パッケージ管理について
Goのパッケージ管理については当初depを使うものと思っていたのですが、GAEのデプロイ時にハマるという情報があったのと(実際ハマった)過渡期ではあるものModulesというのが使えるようになるとのことで、Modulesを使うことにしました。
GAE/Go向けのDocker環境
必要なのはGo 1.11で最低限必要なコマンド類が実行可能な環境なので、 golang:1.11.6
をベースイメージに、 gcloud
と golangci-lint
をインストールするだけのDockerfileを用意しました。
# Dockerfile
FROM golang:1.11.6
RUN apt-get update -y && \
apt-get install lsb-release -y
RUN export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \
echo "deb http://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && \
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
apt-get update -y && \
apt-get install google-cloud-sdk google-cloud-sdk-app-engine-python google-cloud-sdk-app-engine-go google-cloud-sdk-datastore-emulator -y
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.15.0
WORKDIR /go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO
/YOUR_VCS/YOUR_NAME/YOUR_REPO
は以下ご自身の環境に読み替えてください。
.env
に必要な環境変数を記述し、 docker-compose.yml
を以下のようにしました。
GO111MODULE
は上記のModulesを使えるようにするため、 GOOGLE_APPLICATION_CREDENTIALS
はFirebaseの認証情報をJSONから読み込むために設定します。
# .env
GO111MODULE=on
GOOGLE_APPLICATION_CREDENTIALS=/go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO/app/serviceAccountKey.json
# docker-compose.yml
version: '3'
services:
go:
build: dockerfiles/go
env_file:
- .env
volumes:
- .:/go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO
ports:
- 8080:8080
- 8000:8000
restart: 'no'
command: make serve
docker-compose.yml
でコマンドを make serve
としていますが、これは Makefile
に以下のように記述しています。
# Makefile
serve:
dev_appserver.py app.yaml --host=0.0.0.0 --admin_host=0.0.0.0 --support_datastore_emulator=False
この時点でディレクトリ構成は以下のようになっています。 serviceAccountKey.json
はFirebaseのコンソールからダウンロードしてあります。( .gitignore
には追加済み)
.
├── .env
├── .gitignore
├── Makefile
├── README.md
├── app
│ ├── main.go
│ └── serviceAccountKey.json
├── app.yaml
├── docker-compose.yml
├── dockerfiles
│ └── go
│ └── Dockerfile
├── go.mod
└── go.sum
app.yamlはとりあえず最低限。
# app.yaml
runtime: go111
main: app
handlers:
- url: /.*
script: auto
secure: always
以上で docker-compose
で開発環境を立ち上げる準備ができました。
$ docker-compose up
# localhost:8080, localhost:8000にアクセスできる
dev_appserver.py
はコードの変更を検知してビルドしてくれて、ビルドが走るとModulesも勝手に必要な分を引っ張ってきてくれるので、あとは好きなエディタでコードを書いていけばOK、という環境ができました。
(とはいえエディターでフォーマットなどの支援ツールを使えるようにするには各自でよしなにという感じですが)
GAEへのデプロイ
上記の状態で gcloud
コマンドで認証などのセットアップを済ませていれば、デプロイはコマンド一発で簡単にできます。
$ gcloud app deploy app.yaml
お手軽過ぎる。
CircleCIの活用
コードをPushしたときにCircleCIで色々済ませたかったので、とりあえず以下のような設定ファイルを用意しました。
# .circleci/config.yml
version: 2
jobs:
build:
docker:
- image: golang:1.11.6
environment:
GO111MODULE: 'on'
working_directory: /go/src/YOUR_VCS/YOUR_NAME/YOUR_REPO
steps:
- checkout
- restore_cache:
key: modules-{{ checksum "go.mod" }}
- run:
name: install modules
command: go mod tidy
- save_cache:
key: modules-{{ checksum "go.mod" }}
paths:
- /go/pkg/mod
- run:
name: lint
command: |
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.15.0
golangci-lint run --verbose
- run:
name: build
command: go build app/main.go
デフォルト設定の golangci-lint
のLinterに引っかからないこと、コードをビルドできることをチェックしているだけなので、あとはここにテストやデプロイを組み込んでいこうと考えています。
Modulesのキャッシュについて
CircleCIではModulesをキャッシュできるようにしていて、 /go/pkg/mod
以下にダウンロードされたModulesを go.mod
のchecksumをキーに保存しています。
これについて、Modulesを使うと go.mod
と go.sum
が生成されるので、なんとなく他のパッケージマネージャーの感覚で go.sum
が所謂lockファイルなのかなと思いましたが、どうやらそうではないようです。
Wikiによると go.sum
はlockファイルではなく、 go.mod
のみで再現性のあるビルドが可能だそうなので key: modules-{{ checksum "go.mod" }}
としました。
以上でローカルでの開発、デプロイからCIまでの環境が構築できました。
GAEもGoも移り変わりが激しそうですし、情報をキャッチアップしながら少しずつ改良していこうと思っています。