Amazon Web Services ブログ

Fluentd を使用して Amazon EKS Windows ポッドから Amazon CloudWatch Logs にログをストリーミングする

コンテナはオペレーティングシステム仮想化の方法の 1 つで、リソース隔離処理でアプリケーションとその依存関係を実行できるようにするものです。コンテナを使用することで、アプリケーションのコード、設定、依存関係を使いやすいビルディングブロックに簡単にパッケージ化でき、環境の一貫性、運用効率、開発者の生産性を高め、バージョン管理を行うことができます。

Windows コンテナを使うと、前に述べた利点をすべて享受できるだけでなく、Windows Server 2003、2008、2008 R2 などのサポートされていない運用システムで実行しているレガシーアプリ (現在では、環境全体をセキュリティの脅威にさらし、セキュリティルールのコンプライアンスに準拠していない恐れがあります) を移行することも可能です。

AWS でコンテナを実行する場合、2 つの選択肢があります。1 つ目は、サーバーを管理するかどうかです。コンテナ用のサーバーレスコンピューティングが必要な場合は AWS Fargate を選択し、コンピューティング環境のインストール、設定、管理を制御する必要がある場合は Amazon EC2 を選択します。2 つ目は、Amazon Elastic Container Service (ECS) または Amazon Elastic Kubernetes Service (EKS) のどちらかのコンテナオーケストレーターを選択して使用します。コンテナの詳細については、こちらをご参照ください。

同時に、新しいプラットフォームに移行するには、適切な作業に適切なツールが必要です。このブログ投稿では、ログを一元化する方法として、Windows ポッドで作成した IIS ログを Amazon CloudWatch Logs にストリーミングする方法について解説します。

では、これをどのように実現するかをご説明しましょう。

前提条件および仮定:

このブログでは、次のタスクを実行します。

  1. Windows ワーカーノードが実行中であることを確認する。
  2. OIDC プロバイダーを Amazon EKS クラスターに関連付ける。
  3. サービスアカウントで使用する IAM ポリシー、ロール、Kubernetes 名前空間を作成する。
  4. IIS と LogMonitor を含む Windows コンテナイメージを作成する。
  5. Fluentd を含む Windows コンテナイメージを作成する。
  6. Fluentd をデーモンセットとして含む Windows コンテナイメージをデプロイする。
  7. IIS と LogMonitor を含む Windows コンテナイメージをデプロイする。
  8. IIS ポッドにアクセスして、ログを作成する。(オプション)
  9. Amazon CloudWatch Logs でログを確認する。

1.Windows ワーカーノードが実行中であることを確認する。

1.1 Windows ワーカーノードが準備完了として返されるかどうかを確認します。次のコマンドを実行します。

kubectl get nodes -o wide 

1.2 EKS Windowsクラスターにポッド vpc-admission-webhook と vpc-resource-controller が実行中として返されることを確認する必要があります。 次のコマンドを実行します。

kubectl get pods -A | grep vpc

2.OIDC プロバイダーを Amazon EKS クラスターに関連付ける。

2.1 Amazon EKS でサービスアカウントの IAM ロールを設定するには、OIDC を Amazon EKS クラスターに関連付ける必要があります。Amazon EKS クラスター がOIDC をサポートしているかどうかを確認し、次のコマンドを実行します。

aws eks describe-cluster --name cluster_name --region region-id --query "cluster.identity.oidc.issuer" --output text

cluster_name を Amazon EKS クラスター名に置き換えます。

region-id を Amazon EKS クラスター名に置き換えます。

出力:

https://oidc.eks.region-id.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E

2.2 OIDC との関連付けを作成する必要がある場合は、次のコマンドを実行します。

eksctl utils associate-iam-oidc-provider  --region region-id --cluster cluster_name --approve
  • cluster_name を Amazon EKS クラスター名に置き換えます。
  • region-id を Amazon EKS クラスターを起動したリージョンに置き換えます。

3.サービスアカウントで使用する IAM ポリシー、ロール、Kubernetes 名前空間を作成する。

IAM サービスアカウントには、Amazon CloudWatch アクセス許可を含む添付ポリシーが必要です。これにより、Amazon EKS クラスターがログイベントを作成、記述し、ログストリームに配置できるようになります。

3.1 IAM ポリシーとして使用する次のアクセス許可を含む JSON ファイルを作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "EKSFluentdCW",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams",
                "logs:CreateLogGroup",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

3.2 IAM ポリシーを作成し、次のコマンドを実行します。

aws iam create-policy --policy-name MyPolicy --policy-document file://File Path
  • MyPolicy を目的のポリシー名に置き換えます。
  • File Path をポリシーの JSON ファイルパスに置き換えます。

3.3 Kubernetes 名前空間は名前の範囲を提供し、クラスター内のワークロードを整理します。リソースの名前は名前空間内で一意である必要がありますが、名前空間全体で一意である必要はありません。Kubernetes のすべてのリソースは、1 つの名前空間にのみ存在できます。このブログ投稿では、上記の YAML ファイルを使用して amazon-cloudwatch という名前空間を作成します。:

apiVersion: v1
kind: Namespace
metadata:
  name: amazon-cloudwatch
kubectl apply -f namespace.yaml

3.4 IAM サービスアカウントを作成し、すでに作成したポリシーを添付します。次のコマンドを実行します。

eksctl create iamserviceaccount --cluster cluster_name \
--attach-policy-arn PolicyARN \
--name fluentd-windows --namespace amazon-cloudwatch --approve \
--region region-id
  • cluster_name を Amazon EKS クラスター名に置き換えます。
  • PolicyARN をポリシー ARN に置き換えます。
  • region-id を Amazon EKS クラスターを起動したリージョンに置き換えます。
  • 上記のコマンドは、以前にeksctl を使用して Amazon EKS クラスターを作成した場合にのみ機能します。次のメッセージ (クラスターは eksctl で作成されていません) が表示された場合、AWS マネジメントコンソールまたは AWS CLI のタブにある手順に従ってください。また、amazon-cloudwatch 名前空間に Kubernetes サービスアカウントが既に作成されている必要があります。サービスアカウントを作成するには、次のコマンドを実行します。
kubectl create serviceaccount fluentd-windows —namespace amazon-cloudwatch

4. LogMonitor を含む Windows コンテナイメージを作成する。

4.1 このブログで説明している機能をテストするには、IIS と LogMonitor を含む Windows コンテナイメージを作成します。LogMonitor の使用方法の詳細については、公式の GitHub リポジトリにアクセスしてください。

次の例は、IIS と LogMonitor を含む Windows コンテナイメージを構築する Dockerfile です。

FROM mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019

#Set powershell as default shell
SHELL ["powershell", "-NoLogo", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

#Add X-Forward-For Header to IIS Default website log
RUN Add-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/siteDefaults/logFile/customFields" -name "." "-value @{logFieldName='X-Forwarded-For';sourceName='X-Forwarded-For';sourceType='RequestHeader'}" 

#Add STDOUT LogMonitor binary and config in json format
COPY LogMonitor.exe LogMonitorConfig.json 'C:\LogMonitor\'
WORKDIR /LogMonitor

SHELL ["C:\\LogMonitor\\LogMonitor.exe", "powershell.exe"]
ENTRYPOINT C:\ServiceMonitor.exe w3svc;

LogMonitorConfig.json
このサンプル LogMonitorConfig 設定では、IIS アクセスログを含む、C:\inetpub\logs およびサブディレクトリに保存された拡張子 .log を持つすべてのログファイルを取得します。

{
  "LogConfig": {
    "sources": [
      {
        "type": "EventLog",
        "startAtOldestRecord": true,
        "eventFormatMultiLine": false,
        "channels": [
          {
            "name": "system",
            "level": "Error"
          }
        ]
      },
      {
        "type": "File",
        "directory": "c:\\inetpub\\logs",
        "filter": "*.log",
        "includeSubdirectories": true
      },
      {
        "type": "ETW",
        "providers": [
          {
            "providerName": "IIS: WWW Server",
            "ProviderGuid": "3A2A4E84-4C21-4981-AE10-3FDA0D9B0F83",
            "level": "Information"
          },
          {
            "providerName": "Microsoft-Windows-IIS-Logging",
            "ProviderGuid": "7E8AD27F-B271-4EA2-A783-A47BDE29143B",
            "level": "Information",
            "keywords": "0xFF"
          }
        ]
      }
    ]
  }
}

構築が完了したら、ECR レジストリに イメージをプッシュします

5.Fluentd を含む Windows コンテナイメージを作成する。

5.1 Kubernetes ポッドからのログ (具体的には Docker ログ) を集約するには、Windows ServerCore をベースイメージとして使用して、Fluentd RubyGems でログを解析および書き換えて、aws-sdk-cloudwatchlogs RubyGems for Amazon CloudWatch Log で認証と AWS サービスとの通信を行います。 Dockerfile のダウンロードは、AWS GitHub リポジトリから行うことができます。

Dockerfile はすべての要件を含むコンテナイメージを構築します。 この Dockerfile はマルチステージビルドと呼ばれる Docker の機能を使用して、最終的にコンテナサイズを約 600MB に縮小します。

FROM mcr.microsoft.com/windows/servercore:ltsc2019 as base

#Set powershell as default shell
SHELL ["powershell", "-NoLogo", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

#Install chocolatey package manager
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; \
    iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

#Install ruby and msys2 with chocolatey
RUN choco install -y ruby --version 2.6.5.1 --params "'/InstallDir:C:\ruby26'"; \
    choco install -y msys2 --params "'/NoPath /NoUpdate /InstallDir:C:\ruby26\msys64'"

#Install Ruby gems from fluentd Dockerfile + aws-sdk-cloudwatchlogs 
#+ Fluent plugins to parse and rewrite the logs
RUN refreshenv; \
ridk install 2 3; \
'gem: --no-document' | Out-File -Encoding UTF8 -NoNewline -Force -FilePath 'C:\ProgramData\gemrc'; \
gem install bundler; \
bundle config build.certstore_c --with-cflags="-Wno-attributes"; \
bundle config build.yajl-ruby --with-cflags="-Wno-attributes"; \
bundle config build.oj --with-cflags="-Wno-attributes"; \
gem install cool.io -v 1.5.4 --platform ruby; \
gem install oj -v 3.3.10; \
gem install json -v 2.2.0; \
gem install fluentd -v 1.10.0; \
gem install win32-service -v 1.0.1; \
gem install win32-ipc -v 0.7.0; \
gem install win32-event -v 0.6.3; \
gem install windows-pr -v 1.2.6; \
gem install aws-sdk-cloudwatchlogs; \
gem install fluent-plugin-concat; \
gem install fluent-plugin-rewrite-tag-filter; \
gem install fluent-plugin-multi-format-parser; \
gem install fluent-plugin-cloudwatch-logs; \
gem sources --clear-all; \
Remove-Item -Force C:\ruby26\lib\ruby\gems\2.6.0\cache\*.gem; \
Remove-Item -Recurse -Force C:\ProgramData\chocolatey

FROM mcr.microsoft.com/windows/servercore:ltsc2019

COPY --from=base /ruby26 /ruby26

RUN setx /M PATH "C:\ruby26\bin;%PATH%"

CMD ["powershell", "-command", "fluentd"]

構築が完了したら、ECR レジストリに イメージをプッシュします。構築処理中にフリーズした場合は、構築サーバーで次のコマンドを実行し、構築フェーズ中の Docker リアルタイムモニタリングを無効にします。

Set-MpPreference -DisableRealtimeMonitoring $true

5.2 Fluentd を設定するには、ファイル fluent.conf と containers.conf をコンテナに挿入する必要があります。Kubernetes を使用しているので、ConfigMap と呼ばれるオブジェクトを使用して、設定ファイルをポッド内に直接マウントします。ConfigMaps を使用すると、アプリケーション設定をアプリケーションコードから疎結合できます。コンテナイメージを再構築することなく、設定を変更できます。

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-windows
  namespace: amazon-cloudwatch
  labels:
    k8s-app: fluentd-windows
data:
  AWS_REGION: region-id
  CLUSTER_NAME: cluster_name
  fluent.conf: |
    <match fluent.**>
      @type null
    </match>

    @include containers.conf
  containers.conf: |
    <source>
      @type tail
      @id in_tail_container_logs
      path /var/log/containers/*.log
      exclude_path ["/var/log/containers/fluentd*"]
      pos_file /var/log/fluentd-containers.log.pos
      tag k8s.*
      read_from_head true
      <parse>
        @type "json"
        time_format %Y-%m-%dT%H:%M:%S.%NZ
      </parse>
    </source>
    
    <filter **>
      @type record_transformer
      @id filter_containers_stream_transformer
      <record>
        stream_name ${tag_parts[4]}
      </record>
    </filter>
    
      <match k8s.**>
        @type cloudwatch_logs
        @id out_cloudwatch_logs_containers
        region "#{ENV.fetch('AWS_REGION')}"
        log_group_name "/EKS/#{ENV.fetch('CLUSTER_NAME')}/Windows"
        log_stream_name_key stream_name
        remove_log_stream_name_key true
        auto_create_stream true
        <buffer>
          flush_interval 5
          chunk_limit_size 2m
          queued_chunks_limit_size 32
          retry_forever true
        </buffer>
      </match>
  • region-id 値を Amazon EKS クラスターを起動したリージョンに置き換えます。
  • cluster_name 値を Amazon EKS クラスター名に置き換えます。
kubectl apply -f configmap.yaml

6. Fluentd をデーモンセットとして含む Windows コンテナイメージをデプロイする。

デーモンセットは、すべて (または一部) のノードがポッドのコピーを実行することを保証するものです。ノードがクラスターに追加されると、ポッドもそのクラスターに追加されます。すべての Windows ワーカーノードに Windows Fluentd ポッドのコピーがあることを確認するために、次で説明するデプロイファイルを使用してデーモンセットをデプロイします。

6.1 次のコンテンツを使用して、デプロイファイルを作成します。

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd-windows
  namespace: amazon-cloudwatch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: fluentd-windows
  namespace: amazon-cloudwatch
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - namespaces
  verbs:
  - get
  - list
  - watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd-windows
roleRef:
  kind: ClusterRole
  name: fluentd-windows
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: fluentd-windows
  namespace: amazon-cloudwatch
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-windows
  namespace: amazon-cloudwatch
  labels:
    k8s-app: fluentd-windows
spec:
  selector:
    matchLabels:
      name: fluentd-windows
  template:
    metadata:
      labels:
        name: fluentd-windows
    spec:
      serviceAccount: fluentd-windows
      serviceAccountName: fluentd-windows
      # Because the fluentd requires to write on /etc/fluentd/ but we 
      # mount the config using a configmap which is read-only,
      # this initContainer needs to be used to copy 
      # from Read Only folder to Read Write folder.
      initContainers:
      - name: copy-fluentd-config
        image: mcr.microsoft.com/windows/servercore:ltsc2019
        command: ['powershell', '-command', 'cp /etc/temp/*.conf /etc/fluent/']
        volumeMounts:
        - name: fluentdconftemp
          mountPath: /etc/temp/
        - name: fluentdconf
          mountPath: /etc/fluent
      containers:
      - name: fluentd-windows
        image: Fluentd-ECRrepository/tag
        env:
          - name: AWS_REGION
            valueFrom:
              configMapKeyRef:
                name: fluentd-windows
                key: AWS_REGION
          - name: CLUSTER_NAME
            valueFrom:
              configMapKeyRef:
                name: fluentd-windows
                key: CLUSTER_NAME
        resources:
          limits:
            memory: 2Gi
          requests:
            cpu: 100m
            memory: 1Gi
        volumeMounts:
        - name: fluentdconftemp
          mountPath: /etc/temp/
        - name: fluentdconf
          mountPath: /etc/fluent
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: C:\ProgramData\Docker\containers
          readOnly: true
      nodeSelector:
        beta.kubernetes.io/os: windows
      terminationGracePeriodSeconds: 30
      volumes:
      - name: fluentdconftemp
        configMap:
          name: fluentd-windows
      - name: varlog
        hostPath:
          path: C:\var\log
      - name: varlibdockercontainers
        hostPath:
          path: C:\ProgramData\Docker\containers
      - name: fluentdconf
        emptyDir: {}
  • Fluentd-ECRrepository/tag イメージを、ステップ 5.1 で作成した ECR アドレスとタグに置き換えます。

6.2 次のコマンドでポッドをデプロイします。

kubectl apply -f deploymentfilename.yaml

次のステップに進む前に、Fluentd ポッドが実行中として返されることを確認する必要があります。

  • ポッドが実行中の状態になるには、コンテナのサイズにもよりますが、7 分程度かかります。次のコマンドでステータスを確認できます。
kubectl get pods -A | grep fluentd

7. IIS と LogMonitor を含む Windows コンテナイメージをデプロイする。

デプロイを行うと、nodeSelector 属性「beta.kubernetes.io/os: windows」に基づいて、必要なレプリカ (ポッド) の数 (今回の場合は 2) が Windows ワーカーノードで実行されます。 サービスは Kubernetes 内に仮想 IP を作成し、ポッド間のトラフィックの負荷を分散します。

7.1 次のコンテンツを使用して、デプロイファイルを作成します。

---
apiVersion: v1
kind: Service
metadata:
  name: winiis
  labels:
    run: winiis
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: winiis
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: winiis
  name: winiis
  namespace: default
spec:
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      run: winiis
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        run: winiis
    spec:
      containers:
      - image: IIS-ECRrepository/tag
        imagePullPolicy: IfNotPresent
        name: winiis
      dnsPolicy: ClusterFirst
      nodeSelector:
        beta.kubernetes.io/os: windows
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
  • IIS-ECRrepository/tag イメージを、ステップ 4.1 で作成した ECR アドレスとタグに置き換えます。

7.2 次のコマンドでポッドをデプロイします。

kubectl apply -f deploymentfilenameiis.yaml

7. IIS ポッドにアクセスして、ログを作成する (オプション)

7.1 こちらのステップは、オプションです。元のトラフィックがコンテナに到達するのを待つこともできますし、すぐに結果を確認することもできます。コンテナに直接ログを作成するには、次のコマンドを実行します。

kubectl -it exec &lt;your_winiis_pod_name&gt; powershell

7.2 コンテナ内から、次のコマンドを実行します。

curl winiis -UseBasicParsing

8.Amazon CloudWatch Logs でログを確認する。

8.1 ログがログストリームに正常にストリーミングされたかどうかを確認します。Amazon CloudWatch コンソールにアクセスし、ロググループ /EKS/cluster_name/Windows と、ポッドにマッピングされている目的のログストリームをクリックします。

8.2 ご覧のとおり、IIS ログがログストリームにストリーミングされています。

まとめ

Amazon CloudWatch Logs を使用することですべての Windows ポッドログを一元化し、管理者がアプリケーションの問題をすばやく特定できるだけでなく、ビジネスの運用が可視化され、洞察を得ることができます。