🚀

AWS ECSでBottlerocket AMIを利用する際のメモ

2023/07/15に公開

はじめに

名前は聞いたことあったけど使ったことがなかったBottlerocketを触ってみました。
費用面からNATゲートウェイが立てたくない人にはパブリックIPあたりは引っかかりポイントがあるのかもと思ったので、メモがてら共有です。
Bottlerocket自体についてはAWS公式含めていろいろな記事があるので、簡単に自分が気になった部分とURLの紹介のみにとどめています。
個人的な知見はBottlerocketでの懸念点から

Bottlerocketとは

Bottlerocket
Bottlerocketとは、AWSによって作成されたLinuxベースのOSです。コンテナを実行することを目的として構築されており、アタックサーフェスの縮小などの効果が得られます。
AWS ECSにおいても、EC2のAMIを指定することで利用することができます。

利用するモチベーション

AWS ECSではLinuxコンテナを実行する場合、実行環境としては主に以下の3つが候補として上がります。

  • Amazon Linux
  • Bottlerocket
  • AWS Fargate

Amazon Linuxとの比較

Amazon Linux
BottlerocketはAmazon Linuxと同様にEC2上で動作しますが、できることはAmazon Linuxに比べてだいぶ制限されます。ホストOSへのソフトウェアのインストールなど、コンテナ外に対する作業を必要とする場合にはAmazon Linuxのほうが向いています。

ホストOSへのアクセス

BottleroketではホストOSへの直接のアクセスができませんが、代替手段としてコントロールコンテナと管理コンテナが用意されています。なお、管理コンテナはデフォルトでは無効にされています。
SSMでアクセスできるのがコントロールコンテナ、SSHを利用したい場合は管理コンテナとなるようです。また、SSMで実行できるコマンドには制限があるようです。
この辺りは以下が参考になるので、省略
https://aws.amazon.com/jp/blogs/news/getting-started-with-bottlerocket-and-amazon-ecs/

アップデート

Bottlerocketの特徴の一つとして、パッケージ単位ではなくイメージベース単位で更新されます。

Bottlerocket は、イメージベースの方法を使用して、アップデートのたびにオペレーティングシステム全体を特定のバージョン番号に置き換えることで、この問題を解決します。
https://aws.amazon.com/jp/blogs/news/a-deep-dive-into-bottlerocket-ecs-updater/

参考リンク

カスタマイズ性

Amazon Linuxのほうが柔軟ですが、Bottlerocketがまったくカスタマイズできないというわけではありません。後述するbootstrap-containersや、自前でのカスタマイズバージョンの作成などもできるようです。
自分が利用したいカスタマイズがどの実行環境であれば実現できるのかを考えることがアーキテクチャの決定づける一つの動機になると思います。

AWS Fargateとの比較

Fargate

BottlerocketやAmazon Linuxと異なり、FargateはEC2上で動くものではありません。EC2が担っていた部分をAWSが担うことでよりマネージドサービスとしての割合が高まったサービスです。
部分的にBottleroketとFargateの比較ではなく、EC2とFargateの比較になる箇所があります。

責任範囲

Bottlerokcet(Amazon Linuxも含めた)と異なり、ホストOSのアップデートは利用者ではなくAWSの責任範囲になります。
ホストOSへのアクセス方法やホストOSで動作するソフトウェアのインストールなどもできません。
コンテナの中身自体は引き続き利用者の責任で運用管理していく必要があるます。

カスタマイズ性

FargateはBottlerokcetに比べても、さらにカスタマイズの範囲が狭まります。
例えば、後述するタスク定義でのシステムコントロールはFargateではサポートされていないなど、Fargateではできないことあります。反対にBottlerokcetだけできないこともありますので、仕様については確認が必要です。
サービスのアップデートによってこのいくつかの部分は解消されるかもしれません。

料金

これはEC2との比較になります。
EC2よりもマネージドである分、こちらのほうが価格が上回ることが多いと思います。
特別な要望がなくて、節約の必要性が高くなければFargateが有力な候補になるはずです。
アップデートなどの運用コストがかからないのが魅力的です。

Bottlerocketでの懸念点

機能・サービス

SSHをはじめとして、Bottlerocketでは使えないいくつかの機能・サービスがあります。
特に気になったのはApp MeshやService Connectなどのコンテナ間での相互接続サービスが使えないことです。
ECSのサービス検出は利用はできるのですが、AWSVPCでないとAレコードにならないなどの制約があるので注意です。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs-bottlerocket.html#ecs-bottlerocket-considerations

ネットワーク

ECSにはコンテナを外部に接続するためのネットワークモードを3種類から選択できます。
FargateはネットワークモードにAWSVPCモードだけをサポートしていますが、BottleRocketはEC2ですので、いずれのネットワークモードも選ぶことができます。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/bestpracticesguide/networking-networkmode.html

AWSVPCモードですが、EC2とFargateでインターネットへの接続時のパブリックIPの有無で若干異なる部分があります。

EC2において、コンテナがパブリックIPを持てるのはHOSTまたはBRIGEモードの場合のみです。AWSVPCモードではパブリックIPが付与されないため、NATゲートウェイなどを用意する必要があります。

Amazon EC2 の使用 — パブリックサブネットで EC2 インスタンスを起動できます。Amazon ECS は、これらの EC2 インスタンスをクラスター容量として使用します。インスタンスで実行されているコンテナは、アウトバウンドネットワーキングのためにホストの基盤となるパブリック IP アドレスを使用できます。これは、hostおよびbridgeネットワークモード。ただし、awsvpcネットワークモードでは、タスクの ENI にパブリック IP アドレスが付与されません。したがって、インターネットゲートウェイを直接使用することはできません。

一方で、FargateではAWSVPCモードしか利用できず、設定の有無でコンテナにパブリックIPの付与することができます。

Fargate の使用 — Amazon ECS サービスを作成するときに、サービスのネットワーク設定にパブリックサブネットを指定し、パブリック IP アドレスの割り当てオプションが有効になっています。各 Fargate タスクはパブリックサブネットでネットワーク化され、インターネットと直接通信するための独自のパブリック IP アドレスがあります。

相互接続サービス

Bottlerocketには相互接続サービスであるApp MeshやService Connectを利用することはできません。
自前でRoute53プライベートホストゾーンに登録するなどの手段を除けば、AWS ECSのサービス検出を使うことが多くなるかと思いますが、サービス検出はネットワークモードごとに動作が異なります。

サービス検出ではAレコードまたはSRVレコードとして作成することができますが、Aレコードを利用できるのはネットワークモードがAWSVPCモードの場合のみです。HOSTまたはBRIGEモードではSRVレコードのみの対応となります。
節約などの理由で、インターネット向け通信をさせるためにパブリックIPをコンテナに持たせたい場合に、EC2を利用する場合にはAWSVPCモードは選択できません。一方で、コンテナ間通信の名前解決にサービス検出を利用したい場合にはAWSVPCモードでないとAレコードが利用できないのです。
クライアント側がSRVレコードを解決できれば問題ないですが、Aレコードが必要な場合には注意が必要です。
Fargateに変更してパブリックIPを付与するか、AWSVPCモードにしたうえでNATゲートウェイなどを立てるなど、追加コストとの相談になります。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/service-discovery.html#service-discovery-considerations

ユーザーデータ

BottlerocketをECSで利用する際には、EC2のユーザーデータにECSのcluster名を格納することでECSに管理されています。
したがって、EC2起動時のコマンド実行としてのユーザーデータの利用はできませんが、Bottlerocketではbootstrap-containersという仕組みで、コンテナの起動よりも前にコマンドを実行することができます。

https://github.com/bottlerocket-os/bottlerocket/blob/328b50aa489bd6c7d386ea7ad0790ec39d2a9ca9/sources/api/bootstrap-containers/README.md

toml形式のユーザーデータを渡すことで、Bottlerocketの操作をすることができます。
例えば、sysctlをなんとかしたい場合には以下をECSの設定と並ぶようにユーザーデータに格納することで、ECSからコントロールされるBottlerocketなEC2インスタンスになります。

[settings.kernel.sysctl]
"user.max_user_namespaces" = "16384"
"vm.max_map_count" = "262144"

https://github.com/bottlerocket-os/bottlerocket/tree/develop#kernel-settings

使ってみた感想

ネットワークモードなどの違いはあれど、使う分には大きく変更しなくてもBottlerocketを試すことができたので、割と使いやすい気はする。実運用となるとアップデート周りとかはいろいろ迷うこともあるかもしれないが、、見ている分にはむしろ明確でやりやすいのでは?とは思う。
ただ、実運用を気にしだすと、お金払ってFargateにしたほうがいい気もしてしまうので、他の要件があれば選択肢に入ってくるかな?という感覚。それこそ自分が個人で使う分には安さが正義なのでFargateより優先するかも。

今回初めてECSのEC2インスタンスをオートスケーリングループで設定したのだが、ユーザーデータにコマンドを書いたところEC2は起動したのにECSの管理下にいない状態になった。ユーザーデータはECSが使うものとしての認識があまりなかったのでそのあたりは勉強になった。

Discussion