EKS on Fargate上の単一Pod内で起動している複数のコンテナログを別々のCloudWatchLogsグループに転送する
はじめに
前回の記事でAmazon EKS on Fargate上のPodログをCloudWatchLogsに送信するを紹介させていただきました。
今回はその派生版として、Pod内に複数のコンテナが起動している場合にそれぞれのコンテナログを別々のロググループに転送する方法をご紹介たします。
利用シーン
例えば、監視目的でEKSクラスタにDatadogエージェントを導入した場合、1つのPod内にアプリケーション用のコンテナとは別にDatadogAgent用のコンテナが起動します。
この際、仮にそれぞれのコンテナログを同じCloudWatchLogsグループに転送した場合、アプリケーション以外のログも混ざってしまうため、
- ログ収集/保存料金が嵩んでしまう
- アラート設定を行なっていた場合、アプリとは関係のないエラーでアラートが発報されてしまう
といったリスクが発生します。
コンテナごとに転送されるロググループを指定することで、料金コストの削減・期待通りの監視を実現できます。
結論
OUTPUT
のMatch
を分類することで実現可能です。
このMatch
に記述されている文字列パターンと一致するタグのログのみが、log_group_name
で指定されたロググループへと転送される仕組みとなります。
各コンテナごとに設定されるタグは異なるため、ログを転送させたいコンテナのタグとのみ一致するようにOUTPUT
のMatch
を設定します。
各コンテナに設定されるタグは、実際にログをCloudwatchLogsに転送した際のログストリーム名と一致します。
例:
[OUTPUT]
Name cloudwatch
Match *demo_main*
region ap-northeast-1
log_group_name /aws/eks/fluent-bit-cloudwatch/main
[OUTPUT]
Name cloudwatch
Match *demo_php*
region ap-northeast-1
log_group_name /aws/eks/fluent-bit-cloudwatch/php
「*」はワイルドカードとなり、「任意の文字列」と表します。
[補足]検証手順
1. 検証用のEKSクラスタを作成する
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: fluentbit
region: eu-west-1
version: '1.20'
iam:
withOIDC: true
fargateProfiles:
- name: defaultfp
selectors:
- namespace: demo
- namespace: kube-system
cloudWatch:
clusterLogging:
enableTypes: ["*"]
$ eksctl create cluster -f eks-cluster-config.yaml
2. 検証用のEKS on Fargete実行ロールにCloudWatchLogsへの書き込み権限ポリシーを付与する
$ curl -o permissions.json \
https://raw.githubusercontent.com/aws-samples/amazon-eks-fluent-logging-examples/mainline/examples/fargate/cloudwatchlogs/permissions.json
$ aws iam create-policy \
--policy-name FluentBitEKSFargate \
--policy-document file://permissions.json
$ aws iam attach-role-policy \
--policy-arn arn:aws:iam::xxxxxxxxxxx:policy/FluentBitEKSFargate \
--role-name eksctl-fluentbit-cluster-FargatePodExecutionRole-xxxxxxxxxxx
3. 専用のaws-observability namespaceをapplyする
kind: Namespace
apiVersion: v1
metadata:
name: aws-observability
labels:
aws-observability: enabled
$ kubectl apply -f aws-observability-namespace.yaml
4. ConfigMapを適用する
それぞれのコンテナに付与されるタグに当てはまるようにMatch
の値をセットします。
kind: ConfigMap
apiVersion: v1
metadata:
name: aws-logging
namespace: aws-observability
labels:
data:
output.conf: |
[OUTPUT]
Name cloudwatch
Match *demo_main*
region eu-west-1
log_group_name /aws/eks/fluent-bit-cloudwatch/main
log_stream_prefix from-fluent-bit-
auto_create_group true
[OUTPUT]
Name cloudwatch
Match *demo_php*
region eu-west-1
log_group_name /aws/eks/fluent-bit-cloudwatch/php
log_stream_prefix from-fluent-bit-
auto_create_group true
$ kubectl apply -f aws-logging-cloudwatch-configmap.yaml
5. Deploymentを適用する
main
とphp
という名前の2つのコンテナを1つのPod内で起動させます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: logger-server
namespace: demo
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: main
image: nginx:1.14.2
ports:
- containerPort: 80
- name: php
image: php:7.4-fpm
imagePullPolicy: Always
ports:
- containerPort: 9000
$ kubectl -n demo apply -f logger-server.yaml && kubectl -n demo expose deploy logger-server
6. CloudWatchLogsを確認して、「php」のコンテナログが期待されたロググループに出力されたことを確認する
ログストリームを確認すると{namespace}_{コンテナ名}=demo_php
となっている箇所があります。手順4.で設定したOUTPUT
のMatch
と一致しているため、期待通りログが転送されてきています。
ログストリーム名: from-fluent-bit-kube.var.log.containers.logger-server-85f45c5d5f-wfwm5_demo_php-1ce141359cb01b0633b964fbd4a118e7f0a2c877cb645d0bd9d2a1fa09270a0e.log
7. もう片方のコンテナ「main」のログを出力させる
$ kubectl -n demo port-forward svc/logger-server 8080:80
$ curl localhost:8080
8. もう一度、CloudWatchLogsを確認して、コンテナ「main」のログが期待されたロググループに出力されたことを確認する
ログストリームを確認すると{namespace}_{コンテナ名}=demo_main
となっている箇所があります。手順4.で設定したOUTPUT
のMatch
と一致しているため、期待通りログが転送されてきています。
ログストリーム名: from-fluent-bit-kube.var.log.containers.logger-server-669fb86cf4-vjrsp_demo_main-cdb04690e593f8a97aa166407a3ff04e876561509b3d213eb76bde5136f52f93.log