EKS on Fargate上の単一Pod内で起動している複数のコンテナログを別々のCloudWatchLogsグループに転送する

EKS on Fargate上の単一Pod内で起動している複数のコンテナログを別々のCloudWatchLogsグループに転送する

はじめに

前回の記事でAmazon EKS on Fargate上のPodログをCloudWatchLogsに送信するを紹介させていただきました。
今回はその派生版として、Pod内に複数のコンテナが起動している場合にそれぞれのコンテナログを別々のロググループに転送する方法をご紹介たします。

利用シーン

例えば、監視目的でEKSクラスタにDatadogエージェントを導入した場合、1つのPod内にアプリケーション用のコンテナとは別にDatadogAgent用のコンテナが起動します。

この際、仮にそれぞれのコンテナログを同じCloudWatchLogsグループに転送した場合、アプリケーション以外のログも混ざってしまうため、

  • ログ収集/保存料金が嵩んでしまう
  • アラート設定を行なっていた場合、アプリとは関係のないエラーでアラートが発報されてしまう

といったリスクが発生します。

コンテナごとに転送されるロググループを指定することで、料金コストの削減・期待通りの監視を実現できます。

結論

OUTPUTMatchを分類することで実現可能です。

このMatchに記述されている文字列パターンと一致するタグのログのみが、log_group_nameで指定されたロググループへと転送される仕組みとなります。

各コンテナごとに設定されるタグは異なるため、ログを転送させたいコンテナのタグとのみ一致するようにOUTPUTMatchを設定します。

各コンテナに設定されるタグは、実際にログを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を適用する

mainphpという名前の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.で設定したOUTPUTMatchと一致しているため、期待通りログが転送されてきています。

ログストリーム名: 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.で設定したOUTPUTMatchと一致しているため、期待通りログが転送されてきています。

ログストリーム名: from-fluent-bit-kube.var.log.containers.logger-server-669fb86cf4-vjrsp_demo_main-cdb04690e593f8a97aa166407a3ff04e876561509b3d213eb76bde5136f52f93.log