挨拶
エブリーの内原です。
前回の記事では、主にプロダクション環境をECS移行した話をしました。
今回は、ECS移行における、開発環境、社内環境の変更点についてお話します。
以前の構成について
移行前におけるローカル環境を構築する方法は以下の通りでした。
- Ansibleで下記環境をプロビジョニング
- Vagrant on VirtualBox
- MySQL
- Redis
- golangはローカル環境にインストールが必要
システム構成図(再掲)
旧構成の図です。
以前の構成における問題点
この環境には以下のような問題があると認識していました。
ローカル環境構築が手間
当時はGolangの最新版である1.9ではなく1.7を用いていた(現在は1.9にアップデート済み)関係上、ローカル環境にインストールするGolangも1.7にする必要がありましたが、brewで古いパッケージをインストールするにはひと工夫必要で、若干面倒でした。
個々の開発者専用環境が欲しい
社内向け動作確認用サーバもプロダクション環境と同様の構成であるため、デプロイ手順なども同一です。
しかしそうなると、ちょっとしたAPIの修正を施してとりあえずアプリの挙動を確認したいと思っても、実際にサーバへデプロイするしか確認する手段がありません。
(アプリのAPIリクエスト先をローカルで動作しているapi-serverに向ければその限りではありませんが、その場合DBもローカルを参照するのであまり適当な状態ではない)
つまり、メインラインとなるブランチとは別のコードが、一時的にとは言え反映されることになります。
開発者が1人しかいないような状況ならばそれでも特に問題はなかったでしょうが、複数人で同じことをすると、修正が巻き戻ったり思わぬ挙動をすることがあったりと、社内向けとは言えあまりよろしくない状態です。
個々の環境にデプロイできるよう、Ansible設定ファイルをわざわざ個々分用意するのも面倒です。またポート番号やログファイルなど、他の環境と衝突が発生するものについてはなんらか回避策を導入する必要があります。
新環境
プロダクション環境をECS化した関係で、ローカル環境や社内環境についても変化がありました。
新システム構成図(再掲)
Docker composeの利用
ローカル環境の構築にはdocker-composeを利用することにしました。
これなら個々のコンテナはDockerfile、全体の構成はdocker-compose.ymlを参照すれば内容を把握できます。
api server Makefile
今回の対応に必須というわけではありませんでしたが、様々なコマンドラインを毎回打つのは面倒だったのでMakefileにまとめました。
これにより、各種パッケージをインストールするにはmake bundle
、DBマイグレーションはmake migrate
、api-serverプロセス起動はmake run
といったコマンドを叩くだけでよくなりますし、そういったコマンドの追加削除についてレビューすることも可能になります。
さらに、ローカルにgolangにインストールしなくても使えるよう、golangコンテナ経由でgo
コマンドを実行できるようにしています。また環境変数により、ローカルにインストールされているgo
コマンドを用いることも可能です。
その場合はGO=go make run
のように指定します。
dkr_run=docker run -it --rm \
--env GO_ENV=$(GO_ENV) \
--volume $(PWD):/go/src/github.com/everytv/delish-server \
--workdir /go/src/github.com/everytv/delish-server \
--network delishserver_default \
--user `id -u`:`id -g`
dkr_image=golang:1.9.2-alpine
ifeq ($(GO),)
go=$(dkr_run) $(dkr_image) go
else
go=$(GO)
endif
run:
$(dkr_run) -p1323:1323 $(dkr_image) go run main.go
test:
$(go) test *.go -v -timeout 60m
bundle: glide
glide install
migrate: goose
goose -env development up
migrate_test: goose
goose -env test up
glide: $(GOPATH)/bin/glide
$(GOPATH)/bin/glide:
curl https://glide.sh/get | sh
goose: $(GOPATH)/bin/goose
$(GOPATH)/bin/goose:
docker run -u `id -u`:`id -g` --rm -v $(GOPATH)/bin:/go/bin golang:latest go get bitbucket.org/liamstask/goose/cmd/goose
deploy:
./ops/deploy-ecs.sh
ローカル環境用 docker-compose.yml
version: "2"
services:
db:
image: mysql:5.7
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
redis:
image: redis:4.0
ports:
- "6379:6379"
volumes:
db_data:
driver: local
開発者用api-server
個々の開発者専用となるapi-serverも併せて構築します。
ポイントは以下の点で、こうすることで他のコンテナとリソースが衝突してしまうことを防いでいます。
- ポート番号の動的割当を可能に
- ログはコンテナ内にファイルで出力(fluentdは用いない)
前者に関しては、開発者用api-serverはプロダクション環境にて発生したCLB縛りの制約を受けなかったことで実現可能になりました。
よって、開発者用サービス専用のALBが別途必要ということになります。
これにより、1つのインスタンス上に複数のサービスを稼働させることができるようになり、複数人で開発する場合にもインスタンス数を増やす必要はなくなりました。
後者に関しては、開発者用api-serverは開発者個人が一時的に確認する目的で起動するため、ログはfluentdに転送されるより、コンテナ内にファイルとして出力されているほうが確認作業が容易になるためこうしています。
開発者用api-server task definition
差分のみ。環境変数DK_LOG_STDOUT
が0であることで、ログは標準出力ではなくコンテナ内のファイルに出力されます。
{
"containerDefinitions": [
{
"portMappings": [
{
"hostPort": 0,
"protocol": "tcp",
"containerPort": 1323
}
],
"environment": [
{
"name": "DK_LOG_STDOUT",
"value": "0"
}
]
}
]
}
開発者用api-server service
前述の通り、開発者用に1つALBを作成します。
その上で、開発者1名につきそれぞれ、
- リスナーポート
- ターゲットグループ
- service
を作成します。
例えば以下のようにします。当然、リスナーポートにアクセスが通るよう、セキュリティグループのインバウンド設定はしておきます。
- リスナーポート
- 10443
- ターゲットグループ
- ポート
- トラフィックポート
- service
- dev-uchihara-delish-server
- 上記task definitionのリビジョンを指定
この状態で前述のデプロイスクリプトを動作させると、開発者用serviceを指定してデプロイが開始されます。
そこで構築されるイメージは以下のようになり、他の環境のものと衝突することはありません。
1234567890.dkr.ecr.ap-northeast-1.amazonaws.com/delish-server:uchihara-YYYYMMDD-hhmmss
dev-uchihara-delish-server serviceに対し、このイメージを用いるようデプロイが行われます。
開発者専用環境構成図
結局、当初の問題は解決したか?
以下の通り、当初問題とされていた項目をそれぞれ解消することができました。
ローカル環境構築が手間問題
基本的にはdocker-compose up -d
で必要なコンポーネントがすべて起動するようになりました。
更に、make run
でDockerコンテナとしてapi-serverプロセスが起動するようにしました。
ローカルにgolangのインストールすら不要です。(インストールしたものを使うことも可能です)
個々の開発者専用環境が欲しい問題
ECSでいったん開発者用サービス定義をしておけば、あとは通常と同じく、デプロイスクリプトを実行するだけでデプロイが完了します。
各コンテナは他のコンテナとは干渉しないため、自分専用の環境として扱うことが可能です。