こんにちは、エムスリーエンジニアの園田です。
エムスリーでは医療・ヘルスケアサイト向けのコンテンツ配信システムであるChuoi
というサービスを運用しています。
以前このブログでも紹介しましたが、このサービスは Elixir/Phoenix で実装されていて、ElasticBeanstalk のCustom Platformを使って運用していました。
2018/07/04 に AWS Fargate が東京リージョンでローンチされたので、ElasticBeanstalk から Fargate での運用に切り替えました (2018/07/13 切り替え完了)。その際の手順やTipsを書きたいと思います。
今回は構成の説明のみで、実際のコードなどは別のポストで解説していきます。
2018/07/30 追記 実装編の記事を書きました。 www.m3tech.blog
構成変更の動機
以前の構成はこうになっていました。
ElasticBeanstalk を利用しているため、アプリケーションのデプロイはawsebcli
のeb
コマンドをメインとしたデプロイでした。
この構成では、Elixirおよび弊社特有の以下の課題が発生しました。
課題1. Custom Platformのビルドに相当な時間がかかる。
ElasticBeanstalkでは、Packer によるCustom Platform AMIを作成するための機能があり、ElixirやNodeがインストールされたAMIを作成していたのですが、Erlangのビルドに相当な時間がかかっていました。
rpm化も検討しましたが、障害切り分けが困難になるため実装はしたものの利用しませんでした。
GitHub - sonodar/erlang-rpm: Erlang rpm build
こういった背景によりちょっとしたサーバの変更が行いづらく、サーバの細かい修正(fluentdのプラグイン追加など)はebextensions
で済ませてしまうことが多々ありました。*1
これが問題で、ebextensions
はアプリケーションのデプロイ時に実行されるため、ただアプリケーションのソースを変更しただけなのに、全然関係のないfluentd
のプラグインインストールでエラーになったりして、アプリのデプロイが失敗するといったことが頻発しました。
あと、AWSのバグなのかわかりませんが、Custom Platform Builderの機能がビルドの完了を検知してくれずにずっとビルド状態のまま、という事象が起きていました。そのため、Custom PlatformのビルドはGitlabからでもCodeBuildからでもなく、ローカル端末でebp
コマンドを叩いていました。
せっかく構築したCodeBuildのパイプラインは、1回使っただけでお役御免となりました。
課題2. Gitlab CIのIAMユーザに強権限が必要
構成図にあるように、弊社ではCI/CDにオンプレのGitlabを利用しています。そのため、デプロイなどのトリガもGitlab CIで行うことが今はメインになっています。
GitlabからElasticBeanstalkにアプリケーションをデプロイするためには、Gitlab CI上にAWSのシークレットキーなどを保存してeb deploy
コマンドを実行する必要があります。
これはElasticBeanstalkのダメなところですが、eb deploy
コマンドを実行するIAMには、リソースの削除権限を含むかなり強い権限が必要です。*2
オンプレのGitlabとはいえ、強い権限を持つIAMユーザを作成すること自体、AWSのプラクティスから外れています。
課題3. TerraformがCustom Platformに対応していない
弊社では(というより私は)AWSのプロビジョニングにTerraformを利用することが多く、このChuoi
というサービスもTerraformでAWS環境を管理しています。
ElasticBeanstalkのCustom Platformを環境に適用するためには、aws_elastic_beanstalk_environment
リソースにplatform_arn
というパラメータが必要なのですが、今だにこのパラメータはTerraformでサポートされていません。
AWS: aws_elastic_beanstalk_environment - Terraform by HashiCorp
そのため、platform_arn
パラメータを追加してビルドしなおしたterraformの実行バイナリを使っていました。
ただ、本体にプルリクエストを送るほどちゃんとした作りにはしておらず、terraformのバージョンがあがるたびに差分を適用するという地味に面倒な作業を行う必要がありました。
上記3つの課題以外にも小さい不満がたくさんあり、いっそのことEC2にしてしまおうかとも思っていましたが、AWS SummitでFargateが東京に来るというのを聞いたとき、Chuoi
はFargateにしてしまおう!と思った次第であります。
Fargate化のためにやったこと
さて、前置きが非常に長くなりましたが、今回Fargate対応をするにあたり以下のことを実施しました。
- Elixir/PhoenixアプリのDocker化
- Docker化したアプリのFargate動作確認
- 社内GitlabからのCI/CDパイプライン構築
- Terraformテンプレート作成
詳しいことは別の機会に書きますが、個人的な感想としては、かなり大変でした。
変更後の構成
変更後の構成はFargate構成としてわりと普通な形になりました。
デプロイ周りは以下のような構成です。
図に書き忘れたのですが、CloudWatch Event で CodePipeline の状態変更を検知し、Slackにデプロイの進捗を通知する仕組みも実装しました。
デプロイ構成については、検討を行う上で別の選択肢もありました。
DockerイメージのビルドとECRへのプッシュはGitlab上で行い、デプロイのみCodeDeployに実行させる。
Gitlab CIからCodeCommitにプッシュしてパイプラインを開始する
Gitlab CIからecs-cliでデプロイする
メリット
- Gitlab CIだけでパイプラインが完結する。
デメリット
- Gitlab CI上で利用するIAMユーザの権限が強くなる。
- パイプラインの構成管理ができない、もしくはしづらい。
どの手段も、メリットがデメリットを上回らないため、S3へアップロードする方式にしました。
今回の手法のメリット、デメリットは以下です。
メリット
デメリット
デプロイの時間については、今のところ5〜6分で完了するため問題ありませんでした。ソースの分散については課題です。buildspec.yml
のパスにS3のパスが指定できるようになればいいのですが。
構成変更前の課題について
Docker化したことによって、インフラ構成のビルド時間が大幅に削減できました。イメージのビルド自体には2分程度しかかかりません。もともと1時間以上かかっていたので、3000%改善されました!
Gitlab CI上のIAMユーザはS3バケットの
PutObject
権限のみを持つようになり、安心してアクセスキーをGitlabに登録できます。すべての構成をTerraformでコード化できました。
今回はここまでです。この構成をどう実装したかはまた別の機会に解説します。
2018/07/30 追記 実装編の記事を書きました。 www.m3tech.blog
一緒に開発してくれる仲間を募集中です!
エムスリーでは AWS だけでなく、GCP や Rancher が適材適所で利用されています。実装言語も Elixir だけでなく、Java、Ruby、Kotlin、Scala などが大活躍してます。
一緒に開発する仲間を絶賛募集中です!メンバーとカジュアルに話す場も設けてますので是非気軽にお問い合わせください!
*1:ebextensionsはElasticBeanstalkのEC2内ファイルやデプロイフックを管理する仕組みです。https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/ebextensions.html
*2:現在ではCodeDeployがElasticBeanstalkに対応したため、デプロイの入り口をCodeDeployにすることで権限を絞ることが可能