この記事はFLINTERS Advent Calendar 2022の20日目の記事です。
こんにちは、永倉です。
私が所属しているチームでは多くのアプリケーションをKubernetes上で動かしています。Kubernetes ClusterはAmazon Elastic Kubernetes Service (EKS)を使って構築しています。
ワーカーノード(Amazon EC2 Instance)はManaged Node Groupによってプロビジョニングされており、Managed Node GroupのAMIにはBottlerocketを指定しています。
このKubernetes上で動かしているアプリケーションの事情により、ワーカーノードの起動時に特定の処理を実行させたいことがありました。 これにはBottlerocketのbootstrap containerの仕組みを使いました。
このBottlerocketのManaged Node Groupでbootstrap containerを使うという情報は調べた限りではほとんどなかったので紹介したいと思います。
なおこの記事ではBottlerocketやManaged Node Groupについての説明は特にはしていません。
BottlerocketについてはAWSのページやGitHubのリポジトリ、Managed Node GroupについてはAWSのドキュメントをそれぞれご確認ください。
bootstrap containerとは
bootstrap containerはBottlerocketのドキュメントによれば、ホストをブートストラップするために使われるコンテナです。このコンテナは、ECS AgentやKubernetes、Dockerが開始されるより前に実行されます。
AWSのBlogにはbootstrap containerの使用用途の例として以下のようなものが書かれています。
ブートストラップコンテナは、さまざまな目的で使用できます。例えば、エフェメラルストレージのパーティション作成やフォーマット、実行可能な Pod の最大数の計算や設定、Kubernetes の追加ラベルの設定などに使用できます。可能性が広がりますね!
bootstrap containerには以下の設定ができます。詳細はこちらをご確認ください。
- コンテナの実行に失敗した場合ブートプロセスを停止させるか
- コンテナがいつ実行されるか(毎回のブート時、初回のブート時など)
- 実行されるコンテナのイメージ
- コンテナに対して渡すデータ(user data)
BottlerocketのManaged Node Groupでbootstrap containerの設定を行う方法
BottlerocketのManaged Node Groupでbootstrap containerの設定を行うにはLaunch Templateを使います。
Managed Node GroupではLaunch Templateがサポートされています。 Launch Templateはuser dataを指定でき、Bottlerocketではそのuser dataを使ってbootstrap containerなどBottlerocketに関する設定ができます。
BottlerocketのManaged Node Groupでbootstrap containerを使う手順
ということで、BottlerocketのManaged Node Groupで、bootstrap containerを使うためには以下のような手順を踏むことになります。
- bootstrap containerで使用するコンテナイメージを用意する
- Bottlerocketのbootstrap containerの設定を含むuser dataを指定したLaunch Templateを作成する
- 作成されたLaunch Templateを指定したBottlerocketのManaged Node Groupを作成する
以下では上記の手順をコード例を含めて紹介します。
コード例の中で、Managed Node GroupやLaunch Templateの作成にはTerraformのAWS Provider(バージョン4.46.0)を使っています。
bootstrap containerで使用するコンテナイメージを用意する
bootstrap containerとして動かすコンテナ用にコンテナイメージを用意します。 既に動かしたいコンテナイメージが用意されていればこの手順は必要ないです。
今回は例としてbootstrap containerで使うコンテナイメージ用に簡単なDockerfileを用意します。
# syntax = docker/dockerfile:1.4 FROM alpine:3.17.0 COPY <<EOF /bootstrap-script #!/usr/bin/env sh # Transparent Huge Page を無効にする # bootstrap containerでは`/.bottlerocket/rootfs`でホスト側のファイルシステムへアクセスができます # この例はBottlerocketのissue(https://github.com/bottlerocket-os/bottlerocket/discussions/1989)を参考にしています。 echo never > /.bottlerocket/rootfs/sys/kernel/mm/transparent_hugepage/enabled # 下でbootstrap containerのログを確認するので標準出力に適当な文言を出力させる echo hello world EOF RUN chmod +x /bootstrap-script ENTRYPOINT ["sh","/bootstrap-script"]
Dockerfileの例はAWSのBlogやbootstrap containerのドキュメントにも書かれているので参考にしてみてください。
上記のDockerfileを元にしてコンテナイメージを作成します。 作成されたコンテナイメージは、DockerHubやAmazon ECRなどにPushしておきます。
Bottlerocketのbootstrap containerの設定を含むuser dataを指定したLaunch Templateを作成する
aws_launch_templateresourceを使いLaunch Templateを作成します。
Bottlerocketのuser dataはTOMLの形式で記述します。
bootstrap containerの設定はsettings.bootstrap-containers.<name>
テーブル内に書きます。
この例ではbootstrap containerの設定しかしていませんが、他にもさまざまな設定項目があります。詳細はドキュメントをご確認ください。
locals { # launch templateに渡すuser data launch_template_user_data = <<USER_DATA # bootstrap containerの設定 [settings.bootstrap-containers.example] # bootstrap containerとして実行されるコンテナのイメージ source = ${用意したコンテナイメージ} # コンテナがいつ実行されるか(毎回のブート時、初回のブート時など) mode = "always" # コンテナの実行に失敗した場合ブートプロセスを停止させるか essential = true USER_DATA } resource "aws_launch_template" "example" { name = "example" user_data = base64encode(local.launch_template_user_data) }
作成されたLaunch Templateを指定したManaged Node Groupを作成する
aws_eks_node_group resourceを使いManaged Node Grouopを作成します。(今回の説明に必要のない設定項目は除いています。)
resource "aws_eks_node_group" "example" { node_group_name = "example" # Bottlerocketを指定します ami_type = "BOTTLEROCKET_x86_64" # 作成したLaunch Templateを指定します。 launch_template { id = aws_launch_template.example.id version = aws_launch_template.example.latest_version } }
bootstrap containerが実行されたことを確認する
詳細は割愛しますが、BottlerocketではAWS Systems ManagerのSession Managerを使い、BottlerocketのEC2 Instance上でシェルを立ち上げることができます。*1
シェルを立ち上げた後以下のコマンドを実行します。
実行されたbootstrap containerが使っているコンテナイメージは、上で書いたDockerfileをもとに作成し、Amazon ECRにPushしたコンテナイメージです。
[ssm-user@control]$ enter-admin-container Confirming admin container is enabled... Waiting for admin container to start....... Entering admin container Welcome to Bottlerocket's admin container! ╱╲ ╱┄┄╲ This container provides access to the Bottlerocket host │▗▖│ filesystems (see /.bottlerocket/rootfs) and contains common ╱│ │╲ tools for inspection and troubleshooting. It is based on │╰╮╭╯│ Amazon Linux 2, and most things are in the same places you ╹╹ would find them on an AL2 host. To permit more intrusive troubleshooting, including actions that mutate the running state of the Bottlerocket host, we provide a tool called "sheltie" (`sudo sheltie`). When run, this tool drops you into a root shell in the Bottlerocket host's root filesystem. [root@admin]# sheltie # bootstrap containerのログを確認する。参考: https://github.com/bottlerocket-os/bottlerocket/blob/1.11.x/sources/api/bootstrap-containers/README.md # `example`の箇所は、bootstrap containerの設定`settings.bootstrap-containers.<name>`の`<name>`の値と同じです bash-5.1# journalctl -u bootstrap-containers@example.service Dec 16 08:46:15 10.0.3.25 systemd[1]: Starting bootstrap container example... Dec 16 08:46:16 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:16Z" level=info msg="pulling with Amazon ECR Resolver" ref="ecr.aws/arn:aws:ecr:ap-northeast-1:<aws_account_id>:repository/bottlerocket-bootstrap:latest" Dec 16 08:46:16 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:16Z" level=info msg="pulled image successfully" img="ecr.aws/arn:aws:ecr:ap-northeast-1:<aws_account_id>:repository/bottlerocket-bootstrap:latest" Dec 16 08:46:16 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:16Z" level=info msg="unpacking image..." img="ecr.aws/arn:aws:ecr:ap-northeast-1:<aws_account_id>:repository/bottlerocket-bootstrap:latest" Dec 16 08:46:16 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:16Z" level=info msg="tagging image" img="<aws_account_id>.dkr.ecr.ap-northeast-1.amazonaws.com/bottlerocket-bootstrap:latest" Dec 16 08:46:16 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:16Z" level=info msg="Container does not exist, proceeding to create it" ctr-id=boot.example Dec 16 08:46:16 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:16Z" level=info msg="container task does not exist, proceeding to create it" container-id=boot.example Dec 16 08:46:17 10.0.3.25 host-ctr[1101]: hello world Dec 16 08:46:17 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:17Z" level=info msg="successfully started container task" Dec 16 08:46:17 10.0.3.25 host-ctr[1101]: time="2022-12-16T08:46:17Z" level=info msg="container task exited" code=0 Dec 16 08:46:17 10.0.3.25 bootstrap-containers[1170]: 08:46:17 [INFO] bootstrap-containers started Dec 16 08:46:17 10.0.3.25 bootstrap-containers[1170]: 08:46:17 [INFO] Mode for 'example' is 'always' Dec 16 08:46:17 10.0.3.25 systemd[1]: Finished bootstrap container example. # Transparent Huge Page を無効になっていることを確認する bash-5.1# cat /sys/kernel/mm/transparent_hugepage/enabled always madvise [never]
無事実行されていることが確認できました。
参考
- Security features of Bottlerocket, an open source Linux-based operating system | AWS Open Source Blog
- Bottlerocket, A Year in the Life | Containers
- Transparent hugepages configuration · bottlerocket-os/bottlerocket · Discussion #1989 · GitHub
最後に
明日は @rikuta_fl さんの記事が投稿されます。
*1:内部的にはcontrol-containerというコンテナが使われます。詳細はこちらをご確認ください。