Amazon Web Services ブログ

Bottlerocket ECS Updater に Deep Diveする

この記事は A deep dive into Bottlerocket ECS Updater を翻訳したものです。

先月 (2021 年7 月)、Amazon Elastic Container Service (Amazon ECS) に最適化された Bottlerocket AMI の一般提供を発表しました。この記事では、Bottlerocket ECS Updater に焦点を当ててみたいと思います。Bottlerocket ECS Updater は ECS クラスターにインストールできるサービスで、Bottlerocket のコンテナインスタンスを最新の状態に保つことができます。

サービスの仕組みを詳しく説明する前に、Bottlerocket でアップデートがどのように適用されるかを説明する必要があります (Bottlerocket の GitHub リポジトリ に 詳細が記載されていますのでご参照ください)。Bottlerocket のアップデートは、一般的なオペレーティングシステムで慣れ親しんだものとはかなり異なっています。一般的なオペレーティングシステムでは、個々のソフトウェアコンポーネントを 1 つずつアップデートすることができますが、Bottlerocket はオペレーティングシステム全体を一度にアップデートします。

すべてのインスタンスとそのオペレーティングシステムで一貫性を維持するのは難しいことです。オペレーティングシステムをパッケージ単位でアップデートすると (例えば Amazon Linux 2 で yum install -y <パッケージ名> を実行すると)、オペレーティングシステムのバージョンが元からずれてしまい、追随できるベースラインのオペレーティングシステムのバージョンがなくなってしまいます。Bottlerocket は、イメージベースの方法を使用して、アップデートのたびにオペレーティングシステム全体を特定のバージョン番号に置き換えることで、この問題を解決します。

Bottlerocket が The Update Framework (TUF) リポジトリからアップデートをダウンロードし、インストールの準備が整うと、アップデートがセカンダリパーティションに書き込まれます。Bottlerocket は最新のパーティションをプライマリパーティションとしてマークします。次に、新しいバージョンの Bottlerocket が保存されたパーティションを、新しいプライマリパーティションとして再起動し、古いバージョンのイメージはセカンダリの (アクティブでは無い) パーティションとして利用できるようにします。また Bottlerocket には、コンテナイメージやボリュームなどの永続的なユーザーデータ用に設計された、書き込み可能な別のファイルシステムのパーティションが備わっています。これにより、アップデートがより予測可能なものになり、問題が発生した場合に迅速にロールバックするための標準化されたメカニズムを使用することができます。

Bottlerocket では waves を利用してインスタンス群のデプロイのタイミングをずらすことができます。Waves は、Bottlerocket がアップデートのバグによる潜在的な影響を軽減するために使用するメカニズムです。デフォルトでは、Bottlerocket のアップデートは時間の経過とともに徐々に多くのホストに現れていくため、バグが一度にクラスター全体に影響を与えるリスクを軽減します。

これらのアクションは以下の apiclient コマンドを実行することで、自動化されたプロセスの一部として実行されます (この点についてはすぐに説明します)。

  • apiclient update check
  • apiclient update apply
  • apiclient reboot

以下の図は、そのプロセスを説明したものです。

  1. apiclient を使用して、TUF から新しいバージョンを pull します。
  2. 新しい OS バージョンをセカンダリパーティションに書き込みます。
  3. 再起動します。
  4. 新しいバージョンから起動するようにパーティションが swap します。

アップデートには再起動が必要であるため、実行中のアプリケーションに支障をきたす可能性があります。そのためお客様から Bottlerocket と Amazon ECS の統合を強化してほしいという要望が寄せられていました。特に Amazon ECS の「Bottlerocket 対応」や、コンテナインスタンスのドレインを利用するオプションです。この Bottlerocket と Amazon ECS の統合を強化は、OS のアップデート時にダウンタイムを発生させることなく、アプリケーションの最大の可用性を維持することを可能にします。また、必要に応じて基礎となるオペレーティングシステムの定期的なメンテナンスを行うことができます。

Bottlerocket ECS Updater は、AWS CloudFormation テンプレートとして展開できるアプリケーションです。テンプレートを展開すると、AWS アカウント内に以下のリソースが作成されます。

  • Bottlerocket ECS Updater の ECS Fargate タスク定義
  • Bottlerocket ECS Updater を実行するための CloudWatch Events のスケジュールルール
  • Bottlerocket ECS Updater タスク用の IAM ロール、および Fargate と CloudWatch Events 用の IAM ロール
  • Bottlerocket インスタンスのアップデートをクエリおよび実行するための SSM ドキュメント

Bottlerocket ECS Updater は ECS API に問い合わせし、bottlerocket.variant 属性を読み取ることで Bottlerocket インスタンスのフィルタリングを行い、クラスター内のすべてのコンテナインスタンスを検出します。検出された各 Bottlerocket インスタンスに対して、Bottlerocket ECS Updater はインスタンス上で SSM ドキュメントを実行し、apiclient update check コマンドを使用して利用可能なアップデートをチェックします。アップデートが利用可能な場合、Bottlerocket ECS Updater は、コンテナインスタンス上で現在実行されているタスクがサービス内で動作し、置き換えの対象となるかどうかを確認します。すべてのタスクがサービス内で動作する場合、Bottlerocket ECS Updater はコンテナインスタンスを DRAINING の状態としてのマークし、タスクが正常に終了するのを待ちます。コンテナインスタンスがアクティブになると、クラスター内の次のコンテナインスタンスに作業を移します。

  1. AWS の Fargate タスク が定期的に実行されています。
  2. タスクはインスタンス上で SSM ドキュメントとして実行されます。
  3. Bottlerocket ECS Updater は ECS API を実行して、bottlerocket.variant 属性を持つすべてのインスタンスを確認します。
  4. Bottlerocket ECS Updater は各インスタンス上で SSM を実行し、apiclient を使用してアップデートをチェックします。
  5. Bottlerocket ECS Updater は実行中のコンテナが ECS サービス内で動作している場合、インスタンスを DRAININGとしてマークします。
  6. Bottlerocket ECS Updater は、各インスタンス上で SSM ドキュメントを実行して、アップデートをダウンロードし、適用して、インスタンスを再起動します。その後、ノードをアクティブとしてマークし、クラスター内の次のインスタンスに移動します。
  7. すべての操作は Amazon CloudWatch に記録されます。

実際にこれがどのように行われているか見てみましょう。

前提条件

  • 適切なクレデンシャルを設定した AWS CLI
  • ECS クラスター
  • ECS クラスター内で Bottolerocket を実行している EC2 インスタンス (1.1.1 などの古いバージョンの Bottleroket を利用しているもの)
  • Bottlerocket ECS Updater 用の CloudWatch ロググループ
  • Bottlerocket ECS Updater タスクが実行できるためのインターネットアクセスを設定したサブネット

ECS クラスターに Bottlerocket v1.1.1 を実行している EC2 インスタンスがデプロイされている状態からスタートします。Bottlerocket の使用開始方法に関するガイダンスが必要な場合は、こちらから見つけることができます。

bottlerocket-ecs-updater.yaml ファイルをローカルマシンにダウンロードします。

Bottlerocket ECS Updater スタックのデプロイに必要な必須パラメータは以下になります。

  • Bottlerocket コンテナインスタンスが動作する ECS クラスターの名前
  • Bottlerocket ECS Updater のログ送信先となる CloudWatch Logs のロググループの名前
  • インターネットにアクセスできる最低 1 つのサブネット ID (このサブネットは ECS クラスター内の他の機能と共有する必要はありません)

この記事の場合、ECS クラスターの名前は maishsk-bottlerocket、CloudWatch Logs のロググループの名前は bottlerocket-test、Fargate タスクのインターネットアクセスを持つサブネットは subnet-bc8993e6 です。

aws cloudformation deploy \
--stack-name "bottlerocket-ecs-updater" \
--template-file "./bottlerocket-ecs-updater.yaml" \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
ClusterName="maishsk-bottlerocket" \
Subnets="subnet-bc8993e6" \
LogGroupName="bottlerocket-test"

スタックが AWS CloudFormation にデプロイされた後の様子は次のとおりです。

ここでは、ECS クラスターに 3 つの EC2 インスタンスがあり、それぞれが 2 つの ECS タスクを実行していることがわかります。

EC2 インスタンスの Bottlerocket のバージョンを確認するには、インスタンスの中に移動する必要があります。AWS マネジメントコンソールで EC2 に移動し、いずれかのインスタンスを選択し → 「アクション」 → 「接続」と選択します。

次のコマンド apiclient -u /os | jq を実行すると、OS のバージョンがわかりやすく出力されます。

また必要に応じて、複数のホストに対してapiclient -u /os を実行する SSM ドキュメントを、1 台ずつではなく同時に実行することもできます。

デフォルトでは、Bottlerocket ECS Updater は 12 時間ごとに 1 回実行されます。

タスクがトリガーされたときに何が起こるのか、ログを見てみましょう。ログは CloudFormation スタックの作成時に指定した Amazon CloudWatch Logs のロググループに入ります。

Bottlerocket ECS Updater は ECS クラスター内のインスタンスをリストアップし、これらのインスタンスをフィルタリングして Bottlerocket を実行しているものだけを探しますが、今回は 3 つ見つかりました。

それぞれのインスタンスで SSM ドキュメントを実行してアップデートをチェックし、ECS API にインスタンスからコンテナをドレインするように指示します。

インスタンスのタスクがドレインされると、アップデートが始まります。

インスタンス上で SSM ドキュメントが実行され、アップグレードプロセスが開始されます。アップデートが適用された後、インスタンスが再起動します。

インスタンスの再起動が完了すると ECS クラスターに追加され、タスクを受けられる状態になります。インスタンスが ECS クラスターに復帰し、正常であることが確認されると、Bottlerocket ECS Updater はインスタンスに適用されているバージョンが実際に正しい新バージョンであるかどうかを確認します。そしてアップデートが完了したことを示します。

必要であれば、AWS マネジメントコンソールの EC2 から、再度インスタンスに接続して確認することができます。

このプロセスは、ECS クラスター内のすべてのノードが更新されるまで続きます。

この記事で学んだことを振り返ると、

  • Bottlerocket での OS アップデートの仕組みを確認しました。
  • Bottlerocket ECS Updater がどのように動作するかを詳しく説明しました。
  • 既存の ECS クラスターに、新しく Bottlerocket ECS Updater の CloudFormation スタックをデプロイしました。
  • CloudWatch Logs のイベントを見て、プロセス中のアクションがどのように記録されるかを確認しました。

Bottlerocket のコンポーネントはオープンソースで、ロードマップも公開されています。AWS は Bottlerocket がコミュニティの共同プロジェクトであることを目指しております。皆様からのフィードバックや直接のコントリビュートもお待ちしております。ぜひ GitHub リポジトリをチェックしていただき、issue を通じて議論したり、プルリクエストを通じてコントリビュートしてください。

また、非公式なチャネルですが AWS Developer Slack の #bottlerocket チャンネルもあります。この slack チャンネルへのサインアップはこちらです。

翻訳はソリューションアーキテクト加治が担当しました。原文はこちらです。