DELISH KITCHENをECS移行した話(後編)

挨拶

エブリーの内原です。
前回の記事では、主にプロダクション環境を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でいったん開発者用サービス定義をしておけば、あとは通常と同じく、デプロイスクリプトを実行するだけでデプロイが完了します。
各コンテナは他のコンテナとは干渉しないため、自分専用の環境として扱うことが可能です。

株式会社エブリー's job postings
Anonymous
2af47bc7 498b 4fcc b5c8 4b8e0253a0aa?1541761389
E55fedea 9f92 419f 9e1f bae289b2049b
10952422 4960548269444 7757607271975999857 n
22552621 1177225069088645 5449462543199310911 n
Be94b080 8f95 44a4 84ca 307ba1959841
6 Likes
Anonymous
2af47bc7 498b 4fcc b5c8 4b8e0253a0aa?1541761389
E55fedea 9f92 419f 9e1f bae289b2049b
10952422 4960548269444 7757607271975999857 n
22552621 1177225069088645 5449462543199310911 n
Be94b080 8f95 44a4 84ca 307ba1959841
6 Likes

Weekly ranking

Show other rankings

Page top icon