CodeBuild を使って AMI 作成の時間を大幅に短縮した

Posted on

freee では「会計 freee」に始まり、「給与計算 freee」や「会社設立 freee」など全部で 5 つのサービスを提供しています。また、サービス間で共通している機能はマイクロサービス化されているので、インターナルなサービスも含めると数多くのサーバが動いています。

サービスの特性に合わせてミドルウェアやプログラミング言語を選んでいるので AMI を共通化することが難しく、サービスの成長に伴って AMI の数も増えていました(起動時に Cloud-init でゼロからセットアップするやり方だと時間がかかりすぎるため採用できません)。

AMI の数が増えると管理コストがバカになりません。特に、Linux カーネルなどに脆弱性が見つかるとすべての AMI を作り直す必要があります。 freee では Packer と Ansible を使っているので構築自体は自動化されていますが、それでも全部の AMI を作り直すにはそれなりの時間がかかります。

何より AMI の作成は単純作業の繰り返しなので、その作業自体にあまり価値はありません。そこで CodeBuild を使って AMI 作成を並列化して大幅に時間短縮してみました。

AMI Builder with AWS CodeBuild

大本のアイデアは AWS DevOps Blog に投稿された CodeBuild の記事です。

CodeBuild を使って AMI を作成するやり方が紹介されています。 CodeBuild がこういう用途に使えるとは思っていなかったので目から鱗でした。ただ、記事で紹介されているのはひとつの AMI を作るだけなので、AMI の数が多いと結局時間がかかります。

ラッパースクリプトを書いて並列化

CodeBuild のビルド環境はそれぞれ独立したコンテナが起動するため、お互いに影響しあうことなく並列化できます。また、ビルド時に環境変数が追加できるので、環境ごとの差異を吸収することもできます。

ということで AWS SDK for Ruby を使って薄いラッパースクリプトを書いて、AMI の数だけ同時にビルド実行するようにしました。具体的には AMI の種類を YAML で定義しておいて、ループで回しながら start_build のメソッドを呼ぶだけです。

イメージとしてはこんな感じになります。右側のコンテナ部分は AMI の数だけ同時に起動します。

AMI Builder

実行すればあとは CodeBuild がよしなにやってくれるので、エンジニアがやるのはラッパースクリプトを叩くだけになりました!

最後に注意点ですが、CodeBuild のアクティブなビルドは 20 に制限されています。

Cannot have more than 20 active builds for the account (Aws::CodeBuild::Errors::AccountLimitExceededException)

このエラーになったときは AWS に上限緩和申請を出してください。

まとめ

とにかく面倒で時間のかかる作業を完全に自動化できたので、普段の運用がさらに楽になりそうです。

CodeBuild ははじめて触りましたが、CodeBuild のコンテナが VPC の中で起動すると活躍するシーンがもっと増えそうです。今後のアップデートに期待です。