EKSのコンテナログをFluent Bitで収集しCloudWatch Logsに集約する

# はじめに
EKS上のログを収集してそれをCloudWatch Logsに集約するには[fluentd-cloudwatch](https://github.com/helm/charts/tree/master/incubator/fluentd-cloudwatch)をデプロイするのが定番のパターンです。
これをFluent Bitでも行えるようにAWSが公式で[aws-for-fluent-bit](https://hub.helm.sh/charts/aws/aws-for-fluent-bit)を公開しているので試してみました。

# 環境
macOS Mojave 10.14.6
EKS 1.16
Helm 2.14.3
Helmfile 0.122.0

# 導入手順
EKSやHelm Tillerは既にデプロイ済みであるとします。
Fluent BitはデフォルトでCloudWatch LogsにアクセスするためのIAM Roleが付与されないので自分で設定していく必要があります。

## IAM Roleの用意
Fluent BitがCloudWatch Logsにログを転送させるためのIAM Roleを作成していきます。
kube2iamを利用するためAssume Roleを設定する必要があります。

### Node用のIAM Role

作成したWorker Node用のIAM RoleにPolicyをアタッチします。
`<NODE_INSTANCE_ROLE>`にはWorker Nodeのインスタンスロールが入ります。

```assume-role-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "*"
    }
  ]
}
```

```console
$ aws iam create-policy \
  --policy-name assume-role-policy \
  --policy-document assume-role-policy.json
```

```console
$ aws iam attach-role-policy \
  --role-name <NODE_INSTANCE_ROLE> \
  --policy-arn arn:aws:iam::XXXXXXXXXX:policy/assume-role-policy
```

### Pod用のIAM Role

公式のCloudWatchLogsFullAccessのPolicyを付与したIAM Roleを作成します。

```json:cloud-watch-logs-full-access-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::XXXXXXXXXX:role/<NODE_INSTANCE_ROLE>"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

```console
$ aws iam create-role \
  --role-name cloud-watch-logs-full-access-role \
  --assume-role-policy-document cloud-watch-logs-full-access-policy.json
```

```console
$ aws iam attach-role-policy \
  --role-name cloud-watch-logs-full-access-role \
  --policy-arn arn:aws:iam::aws:policy/CloudWatchFullAccess
```

## kube2iamとFluent Bitのデプロイ
Helmでkube2iamとFluent Bitをデプロイしていきます。
Fluent Bitに関してはtemplateを修正する必要があるのでローカルにHelm Chartをダウンロードします。

```console
$ helm repo add aws https://aws.github.io/eks-charts
$ helm fetch aws/aws-for-fluent-bit --version 0.1.2
$ tar xvzf aws-for-fluent-bit-0.1.2.tgz
```

下記のようにPodのannotationsにIAM Roleを定義します。

```diff:aws-for-fluent-bit/templates/daemonset.yaml
spec:
  template:
    metadata:
+     annotations:
+       iam.amazonaws.com/role: cloud-watch-logs-full-access-role
```

Helmfileにkube2iamとFluent Bitに関する情報を記述します。
cloudwatchの設定でリージョン名を入れます。firehoseとkinesisは今回使いません。

```yaml:helmfile.yaml
repositories:
  - name: stable
    url: https://kubernetes-charts.storage.googleapis.com

releases:
  - name: kube2iam
    namespace: kube-system
    chart: stable/kube2iam
    version: 2.5.0
    values:
      - host:
          iptables: true
          interface: eni+
        extraArgs:
          auto-discover-base-arn: ""
        rbac:
          create: true
  - name: aws-for-fluent-bit
    namespace: kube-system
    chart: ./aws-for-fluent-bit
    values:
      - cloudWatch:
          region: "ap-northeast-1"
        firehose:
          enabled: false
        kinesis:
          enabled: false
```

次のコマンドでデプロイします。

```console
$ helmfile -f ./helmfile.yaml apply
```

# 確認
AWSコンソールで実際にログが集約されていることが確認できます。
デフォルトではロググループ名は`/aws/eks/fluentbit-cloudwatch/logs`となっています。
<img width="1440" alt="スクリーンショット 2020-07-26 18.08.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307853/7389de33-a98f-643e-50a4-a9fa082e540a.png">

# まとめ
FluentdではなくFluent Bitでコンテナログを収集してCloudWatch Logsに集約できることを確認しました。

本来はFluent Bitを使うことでリソースの節約をしたいところですが、Helm Chartのデフォルト値は`resources.requests.cpu=500m`、`resources.requests.memory=500Mi`となっており、Fluentd-CloudWatchがそれぞれ`100m`、`200Mi`であることを考えると厳しそうです。
あくまで参考値なので、実際のリソース消費は調査しないといけないです。

導入に関してはHelm Chartが存在するのでとても簡単でした。