ブログを Docker 化して AWS ECS で運用するようにした。
なぜ Docker 化したか
- 仕事で Docker を使う機会が増え知見がたまってきた
- 仕事では Production 投入はできていないので個人ブログで Production 投入して知見を得ておきたかった
どうやったか
ローカルセットアップ編
-
Dockerfile & docker-compose.yml を作成した
- Alpine Linux を使ってなるべくイメージを小さくする
-
Gem::LoadError
問題- Lokka の Gemfile には動的な読み込みを行っている部分があるため、 Dockerfile で単純に COPY するだけでは
Gem::LoadError
になってしまう。- Lokka のプラグインは Gem 化されておらずリポジトリ内に含める形式
- プラグイン側で必要な gem はプラグイン内に Gemfile を配置して宣言する形式
- Lokka 本体の Gemfile には
Dir["public/plugin/lokka-*/Gemfile"].each {|path| eval(open(path) {|f| f.read }) }
のようなコードがあって強引に eval で内容を取り込んでいる
- 対策
- Gemfile.docker を用意する
- Gemfile.docker を生成するためのシェルスクリプトを用意して実行する
- Dockerfile の COPY は以下のようにする
COPY Gemfile.docker /app/Gemfile
- Lokka の Gemfile には動的な読み込みを行っている部分があるため、 Dockerfile で単純に COPY するだけでは
- 他、 MySQL のコンテナを追加して手元でアプリが起動するところまでは確認済み
Production セットアップ編
- ECR にリポジトリを作成し image を push (公式のチュートリアル通りにやればできる)
- ECS にサービスやターゲットグループ、タスクの作成なども指示通りに行う
- 土台となる EC2 インスタンスは手動で作るのではなく、 ECS の画面でポチポチやると勝手に作られる
- 詳細コンテナ設定でエントリポイントを入力する欄に、 Dockerfile と同じように文字列で書いていたらコンテナが起動せずハマった
- カンマ区切りで書かないといけないらしい
- puma を起動したかったら
bundle exec puma
ではなく、bundle,exec,puma
というように書かないといけない
- 諸々設定を済ませたらロードバランサー( ALB )を EC2 のパネルで作成してターゲットに Docker コンテナが動いている EC2 インスタンスを指定する
- ECS の用語やサービス構成に慣れるのに時間がかかるが、歯を食いしばってがんばるしかない
- DB に関しては RDS を使うことにした
- 稼働中の VPS サーバーで
mysqldump -ufoo -p db_name | mysql -ubar -p db_name -h foo.bar.ap-northeast-1.rds.amazonaws.com
みたいな感じで雑に流し込んで移行する
- 稼働中の VPS サーバーで
- ECS は VPC でしか使えないので、 VPC に慣れてない人は VPC に慣れるところから頑張るしかない
- セキュリティグループの設定なども必要になるので頑張って下さい
- Nginx を利用しないので SSL の復号を ALB で行う必要がある
- ACM で無料で証明書を発行できるのを知らず、 Let's Encrypt の証明書を取り込んで使う
- ここまでで一旦公開
運用して気づいた問題点
- サイトが 503 や 504 になる
- Docker コンテナがすぐ死ぬ
- ALB から切り離されることしばしば
- VPS 時代は Nginx に静的ファイルの配信をまかせていたが、 Nginx を挟まなくなったので puma が担当することになりアプリの負荷が高まったのではと推察
- CloudFront を挟んでいい感じにキャッシュしてもらい、静的ファイルの配信は CloudFront にまかせることに
CloudFront 導入編
- ALB で使っているのとは別に SSL 証明書を取得する必要がある
- CloudFront <-> ALB 間の通信を HTTPS で行うため
- Route53 で ALB に割り当てている A レコードをサブドメイン付きの別のものに変更
- ALB 用にはワイルドカード証明書を使う(無料で証明書取得できる ACM 最高)
- Let's Encrypt の証明書を使うのはやめ、ルートドメインの証明書も ACM で取得して CloudFront に設定
- 動的コンテンツ( HTML など)はキャッシュしないようにしないといけない
- 当初、設定がうまくいっておらず、以下のような問題が発生
- POST, PUT, DELETE できない
- Cookie が origin に転送されずセッションが維持できない
- クエリストリングが無視されてしまい、ページ検索などができない
- 当初、設定がうまくいっておらず、以下のような問題が発生
所感
- 体感的にサイトの読み込みがチョッパヤになった
- CloudFront 導入したが、まだ 503 にはなる
- そもそもインスタンスを良いやつに変えないとダメなのかもしれない
- タスク数を増やしてクラスタリングするなどいろいろ試してみる
- クラスタリングするためには Cookie セッションではなく Redis や Memcached などをセッションストレージに使う必要が出てくる…
- Deploy だるい問題
- cap deploy しなくなり、イメージをビルドして push する感じになる
- Alpine Linux でもそこそこイメージサイズはでかくなるので貧弱な回線では docker push にめっちゃ時間かかる
- ECS 側でもサービスを更新するなどの作業が発生
- Blue / Green Deployment できるがポチポチ作業が発生するのがだるい
- Rails を運用する場合は migration なども発生するのでうまいことやる必要あり
- git commit しなくても作りかけのコードの状態で docker-compose build してしまいがちになり、リポジトリのコードと動いてるコンテナイメージの間に差分が発生してしまいそう
- ちゃんと CircleCI などを導入してイメージのビルドとプッシュは CI サービスでやる、というような運用にしないと破綻しそう
- cap deploy しなくなり、イメージをビルドして push する感じになる
- 手順書問題
- こんな風にブログを書いて雑な手順書を作成するようではいけない。 Terraform 化しないと破滅する。
- Lokka は CMS for Cloud です
-
git push heroku master
するだけで使えることが売りの Lokka を AWS のガチな構成で運用するという皮肉
-
- お金高い
- 毎月 3000 円くらいかかる感じになりそう。 VPS は年払いで 16000 円くらいなのでだいぶ高い。払えなくなったら VPS に戻しそう。
謝辞
r7kamura さんの amakan Docker 化の一連の記事と Classmethod 社の ECS 関連の記事には大変お世話になりました。