多くの人がサービスをより快適に使えるようにするために、esaの本番サーバをHeroku (US region) からAWS (Tokyo region) に引っ越しました(※)。また、開発をより快適にするためにCI環境の引っ越しも行いました。
※ 先月後半から調査・検証を開始し、3/19のメンテナンスで移行を行いました。
> 主な変更点主な変更点
BEFORE | AFTER | |
---|---|---|
Web Server / Woker | Heroku (US region) | Docker on ECS(Tokyo region) + ECR |
Cron | Heroku Scheduler | sidekiq-cron |
DB | Heroku Postgres | RDS for PostgreSQL |
DNS | DNSimple | Route 53 |
CI | CircleCI | Shippable + DigitalOcean |
Auto Bundle Update | circleci-bundle-update | deppbot |
以下、ざっくり説明していきたいと思います。
> Web Server/Workerの移行Web Server/Workerの移行
従来はHeroku(US region)にサーバがあったため、日本からのアクセスの場合チューニングをどう頑張っても数百msの遅延がありました。これをAWS(Tokyo region)に移行することで、ページを表示するのに要する時間が1/2 ~ 1/3まで改善されました。
> DockerDocker
移行開始直後は自分が不慣れなこともあり、このタイミングでDockerを採用する気はありませんでした。しかし、実際にECS上でのデプロイを検証したり、Dockerについて学習するうちに移行のイメージが掴めてきたのでDockerを採用することにしました。
もともとHerokuで動いていて The Twelve-Factor App にほぼ沿っていたので、やってみるとDocker移行への障壁はそれほどありませんでした。
コンテナ戦略
シンプルにするために、WebコンテナとWorkerのコンテナは同じものを使っていて、docker run
の時のコマンドで違う動きをさせています。(このあたりはHerokuと同様ですね。)
nginxを別コンテナにするかwebコンテナと同居させるか迷いましたが、最終的にはnginxを使わないという判断をしました。assets系のファイルは基本的にS3+CloudFrontで配信されているためです。今のところこの構成で問題は発生していません。
> ECSECS
「git push heroku master
したらあとはHerokuがよしなにやってくれる」ように、「TaskDefinitionを定義してServiceを更新したらあとはECSがよしなにやってくれる」ところが好きです。
デプロイのときに順番にLBから解除・登録したり、インスタンスの数を役割ごとに一定に保ってくれるので今のところほとんどHerokuの時と同じような運用ができています。
> Cronの移行Cronの移行
「aws lambda scheduled events
とone-off dyno
を組み合わせて...」みたいなことをちょっと考えましたが、複雑になりすぎるのでsidekiq-cron
というsidekiq
の拡張を使うことにしました。もともとそれほど重要な定期処理はなかったので十分でした。
この移行はHeroku => AWS移行の数日前に行いました。
> DBの移行DBの移行
サービスをメンテナンス状態にしてからHeroku Postgres上でバックアップを行い、RDSにリストアしました。可用性を高めるためにmulti AZを有効にし、また暗号化オプションが有効になっています。
> DNSの移行DNSの移行
Herokuで esa.io
等のNaked Domain(Apex Domain)を扱うためにDNSimpleを使っていましたが、AWS移行後は不要になったのでRoute53を使うようにしてあります。
> CIの移行CIの移行
従来CircleCIを使っていましたが、Docker移行後はdocker build
時にキャッシュを上手く扱えない問題があり、buildの時間が10分以上かかるようになってしまったため、Shippableに移行しました。こちらはdocker build時のキャッシュも別のbuildで使うことができます。また自分で用意したdocker imageを使ってCIを行うことができ、さらに自前で用意したホストマシン上でCIを行う事もできます。
試行錯誤の結果、DigitalOcean上のちょっと強いホストマシンとカスタマイズしたdocker imageを組み合わせ、build時のキャッシュを最大限活用することで、テストの実行時間を2分、デプロイを含めても3~5分程でbuildが終わるようになりました。
> デプロイ用のブランチ戦略デプロイ用のブランチ戦略
Herokuを使っていた時はStaging環境はなく、masterにmergeしたら本番環境にデプロイされていました。流石にStaging環境無しで移行するのは難しかったので、以下のようなブランチ戦略をとり、Stagingへのデプロイ等を検証しながら作業を進めました。
branch | action |
---|---|
master |
production/deploy へのalias |
$ENV/deploy |
$ENV 環境へweb, workerコンテナをデプロイ |
$ENV/db-migrate |
$ENV 環境へone-offコンテナをデプロイしてdb:migrate
|
> Auto Bundle Updateの移行Auto Bundle Updateの移行
CircleCIを使用していた時は、 masutaka/circleci-bundle-update-pr を使っていましたが、Shippableに移行してしまったので、deppbot を使うようにしました。
機能的な違いはあまりありませんが、CHANGELOGやrelease noteへのリンクを貼ってくれるので気が利いていますね。
> 参考リンク参考リンク
- Rails アプリの Docker Image ビルドと Amazon EC2 Container Service へのデプロイの自動化 - Atsushi Nagase
- Amazon.co.jp: Docker実践ガイド
- Amazon.co.jp: Dockerエキスパート養成読本
- Amazon.co.jp: プログラマのためのDocker教科書
- WEB+DB PRESS Vol.86|技術評論社
> 所感所感
いかがだったでしょうか。Herokuからの移行を考える場合に少しでもご参考になれば幸いです。
今回書ききれなかった細かい知見や、移行プロジェクトを進める中でのモチベーションの保ち方なども何らかの形でアウトプットしていけたらと思います。
今後も安定した快適なサービスを提供できるように最善を尽くしていく所存ですので、どうぞよろしくお願いいたします。