EKS ( Kubernetes ) のWorker NodeとContainerのログをDaemonSetのFluentdでS3に保存する
はじめに
今回はEKS環境でworkerノードのログとコンテナのログを永続化するためにFluentdを使ってログをS3に保存する方法について検証したので書いていきます。
環境と構成
- EKS
- Workerノード( Amazon Linux2 / ASG )
- DaemonSet
- Fluentd
- IRSA
- ログの保存先にS3
- Kustomize
*) EnvごとにAWSアカウントが異なることを前提にしています。
保存するログの対象
今回、S3に転送する対象のログは以下の通りとします。
- EKSのWorkerノード
- /var/log/messages
- /var/log/audit/audit.log
- コンテナログ ( product-a のコンテナが稼働 )
- /var/log/containers/
DaemonSetについて
DaemonSet は全て(またはいくつか)のNodeが単一のPodのコピーを稼働させることを保証します。Nodeがクラスターに追加されるとき、PodがNode上に追加されます。 fluentdやfilebeatのようなログ集計デーモンを各Node上で稼働させる。
DaemonSetで利用するFluentdについて
Kubernetesで利用するdaemonsetが公式GitHubで提供されているので、今回はこれを利用します。
今回はAWSのS3にログを保存するために、 v1.11.0-debian-s3-1.0
を利用しました。
IRSAについて
今回はFluentdからS3にログを保存するためFluentdにはS3にPUTする権限が必要になります。 権限を付与するために、IRSAを利用して権限を付与しています。今回はこの部分には触れません。 詳細は、以下の記事がとても参考になります。
- 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については↓のリファレンスを。
base/ で用意するマニフェスト
base/
で共通となるマニフェストを作成してenvで異なる部分を overlay
します。
- 今回のkustomizeのディレクトリ構成
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/ で用意するマニフェスト
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
- 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の権限が必要になる。
- GETのAPIが結構な数が叩かれる可能性があるため。その代わりに、object名が重複しないように、
- バケットに保存するパスは
ログの名前( 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のイメージは用途別にイメージが公開されているのでとても便利でした!