メドピアマッスル部上腕二頭筋担当、CTO室 kenzo0107 です。
今回はメドピアの直近のプロジェクトで採用している Rails × ECS Fargate についてです。
直近プロジェクト
直近プロジェクトでは AWS ECS を採用しています。
2018年10月にリリースした スギサポ deli は、メドピアで Fargate 初採用となったプロジェクトです。
スギサポ deli とは?
病気で食事制限が必要な方やシニアの方々、より健康な食生活を目指す方など、誰もが美味しく召し上がれるお食事をお届けするサービスです。
「食事制限」 と聞くと、簡素な食事をイメージされる方もいらっしゃると思いますが
一度見て頂くとお分かりの通り、かなりバラエティに富んだ内容となっており、目にも美味しい品々が並んでおります。
是非一度お試しいただければ幸いです♪
今回お話ししたいこと
以前、 Rails x ECS でオートスケーリング&検証環境の自動構築を執筆しました。
今回は ECS を運用してきてわかった起動タイプ EC2, Fargate の使い所、また、運用時に有用だったことについて話したいと思います。
ECS についておさらい
まずは ECS の起動タイプ Fargate と EC2 について、軽くおさらいです。
起動タイプ Fargate
インフラレイヤーが抽象化されており、EC2 の管理が不要です。
以下の運用コストがなくなることが何よりも有難いです。
- EC2 インスタンスの定期メンテ
- ECS エージェントのバージョン管理
- EC2 オートスケーリング管理
起動タイプ EC2
EC2 を起動し、その上でコンテナを起動しています。
これらの特性により起動タイプ Fargate, EC2 の使い所を検討しました。
検討事項
- コンテナへのアクセスはどうやってするの?
- AutoScaling 速いのどっち?
- お値段はどう?
コンテナへのアクセスはどうやってするの?
起動タイプ EC2
EC2 へ ssh さえできれば、docker ps
でコンテナの起動状態を確認したり、
docker exec
でコンテナにアクセスし、 rails console
を実行することも可能です。
起動タイプ Fargate
インフラレイヤーが抽象化されている為、サーバへ ssh ログインできません。*1
docker exec
でコンテナにアクセスする様なことはできません。
AutoScaling 速いのどっち?
起動タイプ EC2
ECS のバックエンドとして AutoScaling Group で EC2 を起動させ、ECS に紐づけた ALB に EC2 を追加する運用をしています。
その為、 EC2 をスケールアウトさせた後に、タスクをスケールアウトする様にしないと、タスクに偏りが生じる等、正しくタスク配置されない時がありました。
起動タイプ Fargate
タスクのみ考慮すればよいです。
特に、EC2 のスケール分を考慮する必要がないとしても、Fargate のスケールアウトが安定的で速いです。
お値段はどう?
Fargate の価格はタスク数, CPU, Memory に正比例します。Fargate pricing
2019年1月に Fargate の価格が下がったとは言え、タスク数が増えることを考えると、まだ Fargate の方が割高?と思います。
本番・ステージング環境での Fargate, EC2 の使い分け
これまでの起動タイプ Fargate, EC2 の性質を加味して、プロジェクトの性質にも依りますが、以下の様な構成を採用しているケースが多いです。
※ 以下の前提です。
- 一般ユーザがアクセスする方を App、弊社からのみアクセスする管理画面を Admin
- App, Admin 共に同じ Rails プロジェクトがデプロイされている
Point
本番環境 App のみ ECS 起動タイプ Fargate
- ややコストは上がるものの、スケーラビリティに柔軟性がある
その他は ECS 起動タイプ EC2
docker exec
でコンテナに入りデバッグ可能にする- 前回の記事 の様に
qa/*
ブランチ毎のタスクが複数起動している為、タスク数が増えてもコストに影響しない - 本番環境 Admin は、高トラフィックとなる様なことは弊社ではない為、スケーリングを考慮する必要性がない。
- 本番でも
docker exec
しコンテナに入りデバッグしたいという要望があり、Admin を 起動タイプ EC2 にすることで担保
開発時に有用だったこと
デプロイ
以下ブランチにマージすることで自動的に試験→デプロイする様にしています。
- master
- develop
- qa/*
CircleCI で試験をパスすると、 aws codepipeline start-pipeline-execution
を実行し 指定の CodePipeline を開始する様にしています。
CodePipeline
こちらが実質 ECS へのデプロイをしている箇所です。
デプロイ関連の処理は Capistrano でラップしています。
検証環境自動構築
前回記事 検証環境の自動構築 をご参照ください。
ブランチ qa/*
push により以下処理が実行され、検証環境が構築されます。
Rails master.key は?
AWS パラメータストアに登録しており、Rails イメージビルド時に aws ssm get-parameters
で取得しています。
その他、イメージタグ付け( :tag_image
)、ECR へ登録処理( :push_image_to_ecr
)も併記しておきます。
namespace :rails do task :build_image do run_locally do within fetch(:deploy_work_path) do execute 'aws', 'ssm', '--profile', fetch(:profile).to_s, 'get-parameters', '--with-decryption', '--region', 'ap-northeast-1', '--name', "/#{fetch(:application)}/rails/master_key", '--query', '"Parameters[0].Value"', '--output', 'text', '>', 'config/master.key' execute 'docker', 'build', '--no-cache=true', '-t', "#{fetch(:ecr_host)}/#{fetch(:env)}-#{fetch(:application)}-rails:#{fetch(:rails_tag)}", '--build-arg', "RAILS_ENV=#{fetch(:rails_env)}", '-f', 'docker/deploy/rails/Dockerfile', '.' end end end task :tag_image do run_locally do within fetch(:deploy_work_path) do execute 'docker', 'tag', "#{fetch(:ecr_host)}/#{fetch(:env)}-#{fetch(:application)}-rails:#{fetch(:rails_tag)}", "#{fetch(:ecr_host)}/#{fetch(:env)}-#{fetch(:application)}-rails:latest" end end end task :push_image_to_ecr do run_locally do within fetch(:deploy_work_path) do push_image_to_ecr("#{fetch(:ecr_host)}/#{fetch(:env)}-#{fetch(:application)}-rails:#{fetch(:rails_tag)}") push_image_to_ecr("#{fetch(:ecr_host)}/#{fetch(:env)}-#{fetch(:application)}-rails:latest") end end end end def push_image_to_ecr(image) execute 'ecs-cli', 'push', "#{image}", '--aws-profile', fetch(:profile).to_s, '--region', fetch(:region).to_s end
イメージビルド処理短縮
以前は Rails イメージビルド時に asset_sync を利用し、 assets を S3 に同期していましたが、この同期処理に非常に時間が掛かっていました。
ですが、弊社フロントエンドエンジニア 村上 ( @pipopotamasu ) の medpacker により、 Sprockets によるアセットのビルド処理をしないようにした為、デプロイ時間が大幅に短縮されました。*2
是非以下ご一読ください。 tech.medpeer.co.jp
Rails メトリクスを Datadog へ送信
デプロイ後に Rails の以下メトリクスを Datadog に送信する様にしました。*3
- Rails Load Time
- Rails CodeStats
- Gem Dependency Count
post rails metrics to datadog · GitHub
こちらは以前 2018年9月12日 に開催された 『MedBeer -Rails開発での技術的負債との付き合い方-』にて、クックパッド社の 小室 直さん (@hogelog) の発表を参考にさせていただきました。
ありがとうございます!
技術的負債となる指標をプロジェクト初期から意識することで、返済への意識も育まれると思います。(願い)
ロギング
Lambda で LogGroup を S3 に日時バックアップする処理はこちらの Serverless Framework プロジェクトで構築しています。
ログ閲覧
CloudWatch Logs Insight で非常にログの閲覧がスムーズになりました。
以下の様なクエリで、logStream を rails をプリフィックスとしフィルターをかけると、Rails コンテナのログを抽出できます。
fields @timestamp, @message | sort @timestamp desc | limit 20 | filter @logStream like /^rails/
時系列で複数コンテナログを閲覧したい場合は、以下の様にすれば簡単に取得できます。
fields @timestamp, @message, @logStream | sort @timestamp desc | limit 20 | filter @logStream like /^rails|^nginx/
以上からインサイトで検索しやすい様、ECS の Service 単位でコンテナのロググループは統一しています。
まとめ
- 負荷の多い箇所は Fargate がオススメ
- その他は EC2 がコスト的に良い
- デプロイ自動化
- テストは CircleCI、デプロイは CodePipeline と役割分け大事
- Rails config/master.key は AWS パラメータストアで管理
- medpacker で脱 webpacker & デプロイ時間短縮
- Rails メトリクスを Datadog に Post で定点観測
- ログは CloudWatch Logs に一時保存
- 日次で S3 保存し長期保存
- CloudWatch Logs Insight でログ閲覧がスムーズ
- ECS Service 毎にロググループを統一しとくとコンテナ毎の時系列ログが確認しやすい
上記に加えて、開発時に最も有用な、ECS を利用した検証環境自動構築については、またの執筆の機会にと思います。
以上、参考になれば幸いです。
(☝︎ ՞ਊ ՞)☝︎是非読者になってください
メドピアでは一緒に働く仲間を募集しています。 ご応募をお待ちしております!
■募集ポジションはこちら
https://medpeer.co.jp/recruit/entry/
■開発環境はこちら