2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

3-shakeAdvent Calendar 2024

Day 1

vector で kubernetes の container log を CloudWatch Logs に転送する

Last updated at Posted at 2024-12-01

Vector とは

vector は timber とともに買収され datadog がメンテナンスしているオープンソースプロジェクトのようです。(Datadog acquires Timber Technologies)

A lightweight, ultra-fast tool for building observability pipelines

ということで Rust で書かれたメトリクスやログ収集のためのツールです。今回はこれを使って Kubernetes (EKS) のコンテナログを CloudWatch Logs に送信するために使ってみます。

Vector Components

Vector component を SourceTransformSink と繋げることでデータの収集、変換、ルーティングを簡単に行うことができます。

今回はシンプルな構成で次のものを使います。

Helm を使って Kubernetes に deploy する

Agent を DaemonSet として deploy し、各 node から直接 CloudWatch Logs に送るという構成でセットアップします。
EKS ですので CloudWatch Logs へのアクセスには IRSA を使うこととします。(Pod Identity は試していない)

EKS は 1.30
node の OS は Amazon Linux 2023

Helm chart

Helm chart は次のリポジトリで管理されており、https://helm.vector.dev で公開されています。

helm repo add vector https://helm.vector.dev
$ helm search repo vector/vector
NAME                    	CHART VERSION	APP VERSION           	DESCRIPTION                                       
vector/vector           	0.37.0       	0.42.0-distroless-libc	A lightweight, ultra-fast tool for building obs...
vector/vector-agent     	0.21.3       	0.19.3                	A Helm chart to collect Kubernetes logs with Ve...
vector/vector-aggregator	0.21.3       	0.19.3                	A Helm chart to aggregate data with Vector        
vector/vector-shared    	0.2.1        	                      	Shared dependencies of Vector Helm charts         

今回試したのは helm chart の version が 0.37.0 で、vector の version は 0.42.0 です。

values

# DaemonSet として deploy する
role: Agent

# IRSA 用の IAM Role を指定
serviceAccount:
  annotations:
    eks.amazonaws.com/role-arn: ${roleArn}

# 全ての node に deploy する
tolerations:
  - operator: Exists

# node 内の優先度を上げる
podPriorityClassName: system-node-critical

# aggregator としての deploy ではないので Service は不要
service:
  enabled: false
serviceHeadless:
  enabled: false

logLevel: warn

livenessProbe:
  httpGet:
    path: /health
    port: api

# config ファイルの定義用変数
customConfig:
  # host の /var/lib/vector が /vector-data-dir に mount されるため、customConfig を使う場合はここを指定する必要がある
  data_dir: /vector-data-dir

  # livenessProbe のために api を有効化
  api:
    enabled: true
    address: 0.0.0.0:8686
    playground: false

  sources:
    # kubernetes_logs でログファイルから読み出す
    container_logs:
      type: kubernetes_logs
      auto_partial_merge: true
      delay_deletion_ms: 60000
      glob_minimum_cooldown_ms: 60000
      ignore_older_secs: 3600
      max_line_bytes: 32768
      read_from: beginning
      rotate_wait_secs: 300
      use_apiserver_cache: true

  transforms:
    # remap component を使ってログが JSON で出力されている場合に parse する
    parsed_container_logs:
      # inputs に sources で定義された名前を指定
      inputs:
        - container_logs
      type: remap
      # VRL で処理内容を定義
      source: |
        structured = parse_json(.message) ?? parse_nginx_log(.message, "combined") ?? parse_nginx_log(.message, "error") ?? null
        if structured != null {
          .data = structured
          del(.message)
        }

  sinks:
    # CloudWatch Log に送る
    cloudwatch:
      type: aws_cloudwatch_logs
      # inputs に sources や transforms で定義した名前を指定
      inputs:
        - parsed_container_logs
      group_name: ${cloudwatch_log_group_name}
      create_missing_group: false
      # LogStream の名前は複数の node で被らないように指定する
      stream_name: "{{`{{`}}kubernetes.pod_namespace{{`}}`}}-{{`{{`}}kubernetes.pod_name{{`}}`}}-{{`{{`}}kubernetes.container_name{{`}}`}}"
      create_missing_stream: true
      region: ap-northeast-1
      auth:
        region: ap-northeast-1
      # buffer には memory と disk が選択可能
      buffer:
        type: memory
        max_events: 500
        when_full: block
      encoding:
        codec: json

Vector Remap Language (VRL)

transform の remap component の source の中身は VRL という vector の DSL でよく使われる操作が function として定義されています。

今回は parse_json() を使って JSON で出力されたコンテナのログを parse して、CloudWatch Logs Insights で直接クエリできるようにしました。他にもいくつかよくあるログフォーマット用の parser も存在するので ?? で繋げてみました。こうすることで parse に失敗した場合に次の parser を試すといったことが可能です。

コンテナの出力は message という field に入っており、kubernetes_logs source は API Server から metadata を付与してくれます。JSON 内の項目がこの metadata を上書きしないようにここでは data という field に parse の結果を入れています。Google の Cloud Logging に倣って jsonPayload とするのも良いでしょう。del() で元の message を削除しています。

structured = parse_json(.message) ?? parse_nginx_log(.message, "combined") ?? parse_nginx_log(.message, "error") ?? null
if structured != null {
  .data = structured
  del(.message)
}

VRL playground や vector CLI の vrl サブコマンドで VRL の動作確認もできます。

CloudWatch Logs に送られたログ

kubernetes_logs ではデフォルトで多くの metadata が付与されます。
これらは pod_annotation_fieldsnamespace_annotation_fields, node_annotation_fields で制御可能です。

{
    "file": "/var/log/pods/kube-system_kube-proxy-fj9vw_23986ffa-791b-4c26-a8b5-e1ddf5bf4604/kube-proxy/0.log",
    "kubernetes": {
        "container_id": "containerd://c44b2ee3caca7594bd45f54203cb5b3887b3bc01b021c0a646378556d315e77c",
        "container_image": "111222333444.dkr.ecr.ap-northeast-1.amazonaws.com/eks/kube-proxy:v1.31.1-minimal-eksbuild.2",
        "container_image_id": "111222333444.dkr.ecr.ap-northeast-1.amazonaws.com/eks/kube-proxy@sha256:1f678e1d10559dec62ad6640a96e1deec17f3e1354e3002290a8bbc08da67c78",
        "container_name": "kube-proxy",
        "namespace_labels": {
            "kubernetes.io/metadata.name": "kube-system"
        },
        "node_labels": {
            "beta.kubernetes.io/arch": "amd64",
            "beta.kubernetes.io/instance-type": "m7i.4xlarge",
            "beta.kubernetes.io/os": "linux",
            "eks.amazonaws.com/capacityType": "ON_DEMAND",
            "eks.amazonaws.com/nodegroup": "system",
            "eks.amazonaws.com/nodegroup-image": "ami-1234567890abcdef0",
            "eks.amazonaws.com/sourceLaunchTemplateId": "lt-1234567890abcdef0",
            "eks.amazonaws.com/sourceLaunchTemplateVersion": "8",
            "failure-domain.beta.kubernetes.io/region": "ap-northeast-1",
            "failure-domain.beta.kubernetes.io/zone": "ap-northeast-1c",
            "k8s.io/cloud-provider-aws": "991feb0579d6e31b9de4b36d824a2fe8",
            "kubernetes.io/arch": "amd64",
            "kubernetes.io/hostname": "ip-10-0-19-208.ap-northeast-1.compute.internal",
            "kubernetes.io/os": "linux",
            "node.kubernetes.io/instance-type": "m7i.4xlarge",
            "topology.ebs.csi.aws.com/zone": "ap-northeast-1c",
            "topology.k8s.aws/zone-id": "apne1-az1",
            "topology.kubernetes.io/region": "ap-northeast-1",
            "topology.kubernetes.io/zone": "ap-northeast-1c",
            "workload/system": "true"
        },
        "pod_ip": "10.0.19.208",
        "pod_ips": [
            "10.0.19.208"
        ],
        "pod_labels": {
            "controller-revision-hash": "775c97d6d",
            "k8s-app": "kube-proxy",
            "pod-template-generation": "2"
        },
        "pod_name": "kube-proxy-fj9vw",
        "pod_namespace": "kube-system",
        "pod_node_name": "ip-10-0-19-208.ap-northeast-1.compute.internal",
        "pod_owner": "DaemonSet/kube-proxy",
        "pod_uid": "23986ffa-791b-4c26-a8b5-e1ddf5bf4604"
    },
    "message": "I1201 11:28:39.520230       1 proxier.go:822] \"SyncProxyRules complete\" ipFamily=\"IPv4\" elapsed=\"162.318057ms\"",
    "source_type": "kubernetes_logs",
    "stream": "stderr"
}

JSON 出力されていたログの場合

{
    "data": {
        "author": "アルフレッド・テニソン",
        "length": "75",
        "message": "過ぎ去りし麗しき日々は、再び我が元に返り来たらず。",
        "method": "GET",
        "severity": "info",
        "time": "2024-11-29T08:30:34.613521319Z",
        "uri": "/?n=100",
        "uuid": "82d6e748-6449-484b-bf1e-65df7e7628b9"
    },
    "file": "/var/log/pods/meigen_meigen-6559557bfb-vs6jv_3336ef94-b0f5-413f-a79b-bfe1e7f4c67f/meigen/0.log",
    "kubernetes": {省略},
    "source_type": "kubernetes_logs",
    "stream": "stderr"
}

終わりに

以上、とりあえず DaemonSet として vector を deploy して CloudWatch Logs にログを転送する例でした。
安定運用できるかは要検証ですが、Fluentd、Fluent Bit の代替として検討しようかという今日この頃です。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?