My Note

自己理解のためのブログ

EKS ( Kubernetes ) のWorker NodeとContainerのログをDaemonSetのFluentdでS3に保存する

はじめに

今回はEKS環境でworkerノードのログとコンテナのログを永続化するためにFluentdを使ってログをS3に保存する方法について検証したので書いていきます。

環境と構成

  • EKS
    • Workerノード( Amazon Linux2 / ASG )
    • DaemonSet
      • Fluentd
      • IRSA
  • ログの保存先にS3
  • Kustomize

*) EnvごとにAWSアカウントが異なることを前提にしています。

f:id:yhidetoshi:20200704135649p:plain

保存するログの対象

今回、S3に転送する対象のログは以下の通りとします。

  • EKSのWorkerノード
    • /var/log/messages
    • /var/log/audit/audit.log
  • コンテナログ ( product-a のコンテナが稼働 )
    • /var/log/containers/

DaemonSetについて

kubernetes.io

DaemonSet は全て(またはいくつか)のNodeが単一のPodのコピーを稼働させることを保証します。Nodeがクラスターに追加されるとき、PodがNode上に追加されます。 fluentdやfilebeatのようなログ集計デーモンを各Node上で稼働させる。

DaemonSetで利用するFluentdについて

Kubernetesで利用するdaemonsetが公式GitHubで提供されているので、今回はこれを利用します。

github.com

今回はAWSのS3にログを保存するために、 v1.11.0-debian-s3-1.0 を利用しました。

fluentd-kubernetes-daemonset/docker-image/v1.11/debian-s3 at master · fluent/fluentd-kubernetes-daemonset · GitHub

IRSAについて

今回はFluentdからS3にログを保存するためFluentdにはS3にPUTする権限が必要になります。 権限を付与するために、IRSAを利用して権限を付与しています。今回はこの部分には触れません。 詳細は、以下の記事がとても参考になります。

dev.classmethod.jp

  • IRSAで付与するIAMポリリーの権限は以下のようにしました。
    • S3にobjectをputする権限
    • 保存するS3のバケットをkms暗号化している場合は、以下の設定も必要になります。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "kms:GenerateDataKey",
            "Resource": "arn:aws:kms:ap-northeast-1:XXX:key/xxxx"
        }
    ]
}

kustomizeを利用してデプロイする

kustomizeについては↓のリファレンスを。

kubectl.docs.kubernetes.io

base/ で用意するマニフェスト

base/ で共通となるマニフェストを作成してenvで異なる部分を overlay します。

fluentd
├── base
│   ├── daemonset.yaml
│   ├── kustomization.yaml
│   └── serviceaccount.yaml
└── overlays
    ├── dev
        ├── fluent.conf
        ├── kustomization.yaml
        └── patches
            ├── daemonset.yaml
            └── serviceaccount.yaml
  • base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: fluentd

resources:
  - daemonset.yaml
  - serviceaccount.yaml
  • base/serviceaccount.yaml
    • role-arnの部分は envで異なるために overlay します。
kind: ServiceAccount
apiVersion: v1
metadata:
  name: fluentd
  namespace: fluentd
  annotations:
    eks.amazonaws.com/role-arn: overlay

daemonset.yamlについて

daemonsetのPodでworkerノードに出力されているログを収集するために ノードのディレクトリをマウントします。

  • base/daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: fluentd
spec:
  selector:
    matchLabels:
      name: fluentd
  template:
    metadata:
      labels:
        name: fluentd
    spec:
      serviceAccountName: fluentd
      containers:
        - name: fluentd
          image: fluentd:overlay
          env:
            - name: FLUENTD_SYSTEMD_CONF
              value: disable
            - name: S3_BUCKET_REGION
              value: ap-northeast-1
          resources:
            limits:
              memory: "200Mi"
          volumeMounts:
          - name: fluent-conf
            mountPath: /fluentd/etc
          - name: varlog
            mountPath: /var/log
          - name: varlibdockercontainers
            mountPath: /var/lib/docker/containers
            readOnly: true
      volumes:
        - name: fluent-conf
          configMap:
            name: fluent-conf
            items:
              - key: fluent.conf
                path: fluent.conf
        - name: varlog
          hostPath:
            path: /var/log
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers

overlays/ で用意するマニフェスト

  • overlays/kustomization.yamlで設定するもの

    • kustomization.yamlで fluentdのconfを configMapGenerator で設定する
    • fluentdのimageを images で指定する
    • ServiceAccountとDaemonSetのマニフェストpatchesJson6902 で それぞれを overlay する
  • overlays/dev/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: fluentd

bases:
  - ../../base

configMapGenerator:
  - name: fluent-conf
    files:
      - fluent.conf

images:
  - name: fluentd:overlay
    newName: fluent/fluentd-kubernetes-daemonset
    newTag: v1.11.0-debian-s3-1.0

patchesJson6902:
  - target:
      version: v1
      kind: ServiceAccount
      name: fluentd
      namespace: fluentd
    path: patches/serviceaccount.yaml
  - target:
      version: v1
      kind: DaemonSet
      group: apps
      name: fluentd
      namespace: fluentd
    path: patches/daemonset.yaml
  • overlays/dev/patches/serviceaccount.yaml
    • iamロールはENVごとに異なるため、patchesで置き換える
- op: replace
  path: /metadata/annotations/eks.amazonaws.com~1role-arn
  value: arn:aws:iam::XXXXXXXXXXX:role/fluentd-xxxxx
  • overlays/dev/patches/daemonset.yaml
    • コンテナに割り当てるメモリ制限はENVごとに変更するため、pathcesで書き換えられるようにしています。
    • バケット名はENVごとに異なるため、pathcesで環境変数を追加しています。
- op: replace
  path: /spec/template/spec/containers/0/resources/limits/memory
  value: "500Mi"
- op: add
  path: /spec/template/spec/containers/0/env/-
  value:
    name: S3_BUCKET_NAME_COMMON
    value: test-common-logs-dev
- op: add
  path: /spec/template/spec/containers/0/env/-
  value:
    name: S3_BUCKET_NAME_PRODUCT_A
    value: test-product-a-logs-dev

fluent.confについて

設計

  • バケット名とリージョン名は環境変数でconfに展開する。
  • workerノードのログを S3_BUCKET_NAME_COMMONバケットに保存。
    • messages/ と audit/ のパスにそれぞれの種類ごとに分けて保存する。
  • product-aのログを S3_BUCKET_NAME_PRODUCT_Aバケットに保存。
    • nginx/ と api/ のパスにそれぞれの種類ごとに分けて保存する 。
  • APIキーでななく、IAMロールで権限を付与しているので、 check_apikey_on_start false とする。これを設定しないと、APIキーが設定されていなくエラーになった。
  • ログをS3に保存するときにオブジェクトの重複していないか確認させないように check_object false とする。
    • GETのAPIが結構な数が叩かれる可能性があるため。その代わりに、object名が重複しないように、%{hostname}-${tag}-%Y%m%d%H%M%S.%{file_extension} とした。
    • true にする場合は、s3:Getの権限が必要になる。
  • バケットに保存するパスは ログの名前( tag名 )/dt=yyyymmdd/hour=xx/オブジェクト名 とする。

fluentdの設定ファイル名について

ConfigMapで設定しているファイル名は fluentdのDockerfileの環境変数 ( ENV FLUENTD_CONF="fluent.conf" )に設定されているため fluent.conf にしています。詳細は↓。

# worker node log
## /var/log/messages
<source>
  @type tail
  path /var/log/messages
  tag common.messages
  pos_file /var/log/td-agent/messages.pos
  format syslog
</source>

## audit
<source>
  @type tail
  path /var/log/audit/audit.log
  tag common.audit
  pos_file /var/log/td-agent/audit.pos
  format ltsv
</source>

# container log
## product-a

### nginx
<source>
  @type tail
  path "/var/log/containers/product-a-nginx-*.log"
  pos_file /var/log/nginx.log.pos
  tag product-a.nginx
  read_from_head true
  <parse>
    @type json
    time_format %Y-%m-%dT%H:%M:%S.%NZ
  </parse>
</source>

### api
<source>
  @type tail
  path "/var/log/containers/product-a-api-*.log"
  pos_file /var/log/product-a-api.log.pos
  tag product-a.api
  read_from_head true
  <parse>
    @type json
    time_format %Y-%m-%dT%H:%M:%S.%NZ
  </parse>
</source>


# worker node
<match common.*>
  @type s3
  format json
  s3_bucket "#{ENV['S3_BUCKET_NAME_COMMON']}"
  s3_region "#{ENV['S3_BUCKET_REGION']}"
  s3_object_key_format %{path}%{time_slice}/%{hostname}-${tag}-%Y%m%d%H%M%S.%{file_extension}
  path worker-node/${tag[1]}/
  time_slice_format dt=%Y%m%d/hour=%H
  check_apikey_on_start false
  check_object false
  flush_interval 300s
  flush_at_shutdown true
  time_slice_wait 30s
  include_time_key true
  time_key time

  <buffer tag,time>
    @type file
    path "/var/log/fluentd-buffers-common-varlog/s3.buffer"
    chunk_limit_size 256MB
    timekey 5m
  </buffer>
</match>

# container
## product-a
<match product-a.*>
  @type s3
  format json
  s3_bucket "#{ENV['S3_BUCKET_NAME_PRODUCT_A']}"
  s3_region "#{ENV['S3_BUCKET_REGION']}"
  s3_object_key_format %{path}%{time_slice}/%{hostname}-${tag}-%Y%m%d%H%M%S.%{file_extension}
  path ${tag[1]}/
  time_slice_format dt=%Y%m%d/hour=%H
  check_apikey_on_start false
  check_object false
  flush_interval 300s
  flush_at_shutdown true
  time_slice_wait 30s
  include_time_key true
  time_key time

  <buffer tag,time>
    @type file
    path "/var/log/fluentd-buffers-product-a/s3.buffer"
    chunk_limit_size 256MB
    timekey 5m
  </buffer>
</match>

さいごに

今回は、マニフェストの管理はkustomizeを利用して EKS環境下のWorkerノードの一部のログとコンテナのログをKubernetesのDaemonSetでFluentd動かしてS3にログを保存しました。 kustomizeで管理しているマニフェストのデプロイはArgoCDを利用していますが今回は言及していません。DaemonSetで利用するFluentdのイメージは用途別にイメージが公開されているのでとても便利でした!