Bottlerocket を使ってみよう！


:rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket:
[AWS Containers Advent Calendar 2021](https://qiita.com/advent-calendar/2021/aws-containers) の 14 日目のエントリーです。
:rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket::rocket:

## この記事について
Bottlerocket ってのを聞いてみたけど使ってみようかな？と思っている方に向けた Bottlerocket の導入部分について書いています。
中身の動きや詳細はブログが多数出ておりますので文末の[関連リンク](#関連リンク)をご参照ください。


## 目次
- [Bottlerocket って何？](#Bottlerocket って何？)
- [セキュリティ面での特徴](#セキュリティ面での特徴)
- [どこで使える？](#どこで使える？)
- [バリアント](#バリアント)
- [Amazon ECS で使ってみる](#Amazon ECS で使ってみる)
- [Amazon EKS で使ってみる](#Amazon EKS で使ってみる)
- [Bottlerocket 自体のアップデート運用どうすれば良い？](#Bottlerocket 自体のアップデート運用どうすれば良い？)
- [具体的に、アップデートどうやる？](#具体的に、アップデートどうやる？)
- [OS へのアクセス](#OS へのアクセス)
- [Control Container (コントロールコンテナ)](#Control Container (コントロールコンテナ))
- [Admin Container (管理コンテナ)](#Admin Container (管理コンテナ))
- [Bottlerocket のカスタマイズ](#Bottlerocket のカスタマイズ)
- [Bootstrap Container (ブートストラップコンテナ)](#Bootstrap Container (ブートストラップコンテナ))
- [ロードマップ](#ロードマップ)
- [関連リンク](#関連リンク)

## Bottlerocket って何？
- Bottlerocket はコンテナをホスティングするために設計された OSS の Linux ベース OS です。
- Amazon で長年に渡って大規模な本番環境サービスを実行して学んだ教訓の結果、[Bottlerocket プロジェクト](https://github.com/bottlerocket-os/bottlerocket)として始まり、2020 年 8 月にローンチされました。
- Rust で開発され、ソースコードは [GitHub](https://github.com/bottlerocket-os/bottlerocket) に公開されています。
- セキュリティと保守性に重点を置き、コンテナベースのワークロードに対して、信頼性が高く一貫性のある安全なプラットフォームを提供します。


## セキュリティ面での特徴
- パッケージマネージャのようなものは含まれておらず、フットプリントを小さくするよう意識されています。
- 攻撃者がコンテナを脱出できたとしても、使用できるツールはかなり制限されます。
- SELinux をデフォルトで enforcing モードで実行しています。
- ルートファイルシステムは読み取り専用となっており、Linux カーネルモジュールの dm-verity を利用して、ファイルシステムの整合性を維持します。
- 詳しくはブログ「[Bottlerocket のセキュリティ機能 〜オープンソースの Linux ベースオペレーティングシステム〜](https://aws.amazon.com/jp/blogs/news/security-features-of-bottlerocket-an-open-source-linux-based-operating-system/)」をご参照ください。

## どこで使える？
- Amazon EKS、Amazon ECS、VMWare Kubernetes などで、コンテナをホストするためのノードとして利用できます。
- さまざまなユースケースに合わせてカスタマイズされたバリエーションが有り、[バリアント](https://github.com/bottlerocket-os/bottlerocket/tree/develop/variants)という形で提供されています。


## バリアント
- [バリアント](https://github.com/bottlerocket-os/bottlerocket/tree/develop/variants)は、簡単にいうとユースケース別のバリエーションです。
- 一般的な Linux ディストリビューションでもコンテナを実行することは可能ですが、Bottlerocket はコンテナホストとして必要なもののみで構成しています。
- [バリアント](https://github.com/bottlerocket-os/bottlerocket/tree/develop/variants)のそれぞれが、独自のソフトウェアと API 設定を持っています。
    - 「aws-k8s-1.21」というバリアントは Kubernetes 1.21 で使用するためのものです。
    - 現在利用できるバリアントは、[ここ](https://github.com/bottlerocket-os/bottlerocket/tree/develop/variants)を参照ください。


## Amazon ECS で使ってみる
- AMI で提供されている ECS バリアントを使い、コンテナインスタンスとして起動します。
- 起動するインスタンスは、ECS API と AWS Systems Manager セッションマネージャー API の両方と通信するために IAM ロールが必要になります。   


### IAM ロール作成

- `AmazonSSMManagedInstanceCore` と `AmazonEC2ContainerServiceforEC2Role` の両方の管理ポリシーがアタッチされている IAM ロールを作成してください。(ここでは手順を省略します)

### EC2 起動
- 利用できる AMI は AWS Systems Manager Parameter Store に格納されています。
- 以下のコマンドで AMI ID を取得できます。
※東京リージョンの場合

```
$ aws ssm get-parameter --region ap-northeast-1 \
    --name "/aws/service/bottlerocket/aws-ecs-1/x86_64/latest/image_id" \
    --query Parameter.Value --output text
```

- 取得した AMI ID で EC2 を起動します。
- IAM ロールは前の手順で作成したものを指定してください。
- ユーザーデータ に以下を指定し、ECS クラスターと紐付けます。


```
[settings.ecs]
cluster = "ecs-bottlerocket"
```
※`ecs-bottlerocket` は ECS クラスターの名前を指定します。


- コンテナインスタンスが登録されていることを確認します。

```
$ aws ecs list-container-instances --cluster ecs-bottlerocket
{
    "containerInstanceArns": [
        "arn:aws:ecs:ap-northeast-1:999999999999:container-instance/ecs-bottlerocket/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ]
}
```
※AWS コンソールからも確認できます。

- 表示されない場合は、EC2 のユーザーデータに上記の設定が正しくされているか(ECS クラスター名が指定されているか)、IAM ロールのポリシーが正しく設定されているかを確認してください。

※ここでは EC2 を単体で起動しますが、Auto Scaling グループで起動しても構いません。

## Amazon EKS で使ってみる
- `eksctl` を利用して、マネージド型ノードグループとして作成可能です。

```nodegroup_bottlerocket.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-bottlerocket
  region: ap-northeast-1

managedNodeGroups:
  - name: bottlerocket-nodegroup
    instanceType: m5.large
    amiFamily: Bottlerocket
    desiredCapacity: 1
    minSize: 1
    maxSize: 5
    volumeSize: 30
    labels: { role: bottlerocket-worker }
    tags:
      nodegroup-type: Bottlerocket
    ssh:
      allow: true
      publicKeyName: eks_bottlerocket 
```

```
$ eksctl create nodegroup -f nodegroup_bottlerocket.yaml  
```

- マネージド型ノードグループが作成されていることを確認します。

```
$ aws eks list-nodegroups --cluster eks-bottlerocket
{
    "nodegroups": [
        "bottlerocket-nodegroup"
    ]
}
```

## Bottlerocket 自体のアップデート運用どうすれば良い？
- Bottlerocket 自体にもバージョンがあり、また新しいバリアントを利用するためにもアップデート作業が必要になります。
- 一般的な Linux のように、アップデートパッケージを適用する形ではなく、イメージベースの方法を使用してアップデートのたびに　OS 全体を特定のバージョン番号に置き換える形を取っています。
- 詳細については「[Bottlerocket update infrastructure](https://github.com/bottlerocket-os/bottlerocket/blob/develop/sources/updater/README.md)」をご参照ください。

## 具体的に、アップデートどうやる？
- 後述の「コントロールコンテナ」からコマンドラインで実行可能です。
- Amazon ECS、Amazon EKS それぞれに Updater があります。

### Bottlerocket ECS Updater
- こちらのブログ「[Bottlerocket ECS Updater に Deep Diveする](https://aws.amazon.com/jp/blogs/news/a-deep-dive-into-bottlerocket-ecs-updater/)」で紹介しております。
- [CloudFormation テンプレート](https://github.com/bottlerocket-os/bottlerocket-ecs-updater/blob/develop/stacks/bottlerocket-ecs-updater.yaml)が公開されているので、こちらをダウンロード、展開します。
- デプロイに必須なパラメータは以下です
    - Bottlerocket コンテナインスタンスが動作する ECS クラスターの名前
    - Bottlerocket ECS Updater のログ送信先となる CloudWatch Logs のロググループの名前
    - インターネットにアクセスできる最低 1 つのサブネット ID

```
$ aws cloudformation deploy \
--stack-name "bottlerocket-ecs-updater" \
--template-file "./bottlerocket-ecs-updater.yaml" \
--capabilities CAPABILITY_NAMED_IAM \
--parameter-overrides \
ClusterName="ecs-bottlerocket" \
Subnets="subnet-xxxxxxxx, subnet-yyyyyyyy" \
LogGroupName="bottlerocket-log"

```

- Bottlerocket ECS Updater で作成されるリソースは以下になります
    - Task Definition
    - EventBridge
    - SSM Document
    - IAM Role

- デフォルトで12時間に1度実行トリガーされるイベントスケジュールが設定され、12時間ごとに以下が行われます。
    - アップデートのチェック
    - バージョンのチェック
    - コンテナインスタンスのドレイン
    - アップデートの反映
    - ECS クラスターへの再登録
- 挙動については[こちらのブログ](https://aws.amazon.com/jp/blogs/news/a-deep-dive-into-bottlerocket-ecs-updater/)をご参照ください。


### Kubernetes の Bottlerocket Update Operator 
- `eksctl` コマンドで、マネージド型ノードグループのアップデートが可能です
- ノードにデプロイされているのと同じ Kubernetes バージョンの最新の Bottlerocket AMI リリースにアップデートできます

```
$ eksctl upgrade nodegroup --name=bottlerocket-nodegroup --cluster=eks-bottlerocket
```

- Kubernetes のバージョンを指定することもできます。  
※2021年12月14日時点、Kubernetes バージョン指定によるアップグレードは正常に動かない可能性があります。[issue はこちら](https://github.com/weaveworks/eksctl/issues/4423)。

```
$ eksctl upgrade nodegroup --name=bottlerocket-nodegroup --cluster=bottlerocket-cluster --kubernetes-version=1.21
```

- 特定のリリースバージョンを指定することもできます。

```
$ eksctl upgrade nodegroup --name=bottlerocket-nodegroup --cluster=bottlerocket-cluster --release-version=1.3.0-395b459c
```

## OS へのアクセス
- ユーザーは Bottlerocket OS に直接アクセスすることはできません。
- OS の特定のインターフェイスを提供する 2 つのコンテナを操作します。
    - Control Container (コントロールコンテナ): `デフォルト有効`
    - Admin Container(管理コンテナ): `デフォルト無効`
- これら 2 つのコンテナは、ユーザーがワークロードを実施するコンテナランタイムとは別のコンテナランタイム (containerd) で実行されます。


## Control Container (コントロールコンテナ)
- コントロールコンテナには SSM Agent が入っており、セッションマネージャ経由でアクセスが可能です。
- アクセス可能ですが、使用できるコマンドは限られています。
- Bottlerocket の設定を行う場合は `apiclient` コマンドを介して実施します。
    - イメージのアップデートも `apiclient update` コマンドで実施できます。
    - `apiclient` については[apiclient の README](https://github.com/bottlerocket-os/bottlerocket/tree/develop/sources/api/apiclient)をご参照ください。



## Admin Container (管理コンテナ)
- 管理コンテナを有効化すると SSH サーバが起動し、Bottlerocket インスタンス起動時に指定したキーペアを使用して SSH 接続が可能となります。
    - セキュリティグループなどで　SSH を制限している場合は、SSH アクセスが可能になるように変更が必要です。
- Bottlerocket インスタンスに SSH 接続すると、強い特権を持つ Amazon Linux 2 コンテナに入ります。
- 管理コンテナからホストプロセスの名前空間にアクセスができますが、ホストのトラブルシューティングなど、例外的な状況でのみ起動することを推奨しています。


### 管理コンテナの有効化
- Bottlerocket インスタンス起動時に、ユーザーデータで有効化しておくこともできます。

```
[settings.host-containers.admin]
enabled = true
```

- コントロールコンテナから管理コンテナを有効化できます。

```
$ enable-admin-container
```

## Bottlerocket のカスタマイズ
- 追加のパッケージを実行したい要件がある場合、Bootstrap Container (ブートストラップコンテナ)での実行を推奨しています。
- 要件に応じて、独自のバリアントを作成することも可能ですが、 Bottlerocket の公式イメージという信頼性が無くなるなどの点には注意が必要です。
    - カスタムイメージの公開については、[Publishing Bottlerocket](https://github.com/bottlerocket-os/bottlerocket/blob/develop/PUBLISHING.md) のドキュメントを参照してください。

## Bootstrap Container (ブートストラップコンテナ)
- ブートストラップコンテナは、Docker、Amazon ECS エージェント、kubelet のようなサービスが開始される前に実行されます。
- systemd の `configured.target` ユニットがアクティブになった後に実行されます。
- ブートストラップコンテナは、さまざまな目的で使用できます。
    - エフェメラルストレージのパーティション作成やフォーマット
    - 実行可能な Pod の最大数の計算や設定
    - Kubernetes の追加ラベルの設定
    - etc..
- 詳しくは[こちらのブログ](https://aws.amazon.com/jp/blogs/news/bottlerocket-a-year-in-the-life/)の「ブートストラップコンテナ」をご参照ください。

### ブートストラップコンテナの制限
- 複数のブートストラップコンテナを設定することができますが、実行される順序はコントロールできません。
- コントロールコンテナ/管理コンテナとは異なり、`superpowered` コンテナとして実行することはできません。
- Linux の `CAP_SYS_ADMIN` 機能で動作し、ホスト上で表示されるファイル、ディレクトリ、マウントを作成することができます。


## ロードマップ
- Bottlerocket のロードマップについては[こちら](https://github.com/orgs/bottlerocket-os/projects/1)で公開されております。

## 関連リンク
Bottlerocket の概要やはじめ方に付いて簡単に紹介させていただきました。選択肢の一つとして認識してもらえれば幸いです。
Bottlerocket に関するブログが日本語でも出ておりますのでご一読いただければと思います。

- [Bottlerocket、1 年間のあゆみ](https://aws.amazon.com/jp/blogs/news/bottlerocket-a-year-in-the-life/)
- [Bottlerocket: 特定目的のコンテナオペレーティングシステム](https://aws.amazon.com/jp/blogs/news/bottlerocket-a-special-purpose-container-operating-system/)
- [Bottlerocket のセキュリティ機能 〜オープンソースの Linux ベースオペレーティングシステム〜](https://aws.amazon.com/jp/blogs/news/security-features-of-bottlerocket-an-open-source-linux-based-operating-system/)
- [Amazon ECS での Bottlerocket の始め方 〜 コンテナ向けのセキュアな Linux ディストリビューション](https://aws.amazon.com/jp/blogs/news/getting-started-with-bottlerocket-and-amazon-ecs/)
- [Bottlerocket ECS Updater に Deep Diveする](https://aws.amazon.com/jp/blogs/news/a-deep-dive-into-bottlerocket-ecs-updater/)
- [Amazon EKS はマネージド型ノードグループでの Bottlerocket のネイティブサポートを追加しました](https://aws.amazon.com/jp/blogs/news/amazon-eks-adds-native-support-for-bottlerocket-in-managed-node-groups/)