Vector: лог-пайплайн из Kubernetes в Elasticsearch

Published: 2026-03-15

Fluentd и Logstash — традиционные сборщики логов. Vector — современная альтернатива: написан на Rust, заметно меньше потребляет CPU и памяти, использует единую модель sources/transforms/sinks и формат конфигурации, который читается без обращения к вики.


Архитектура

Pods (stdout/stderr)
  → Vector DaemonSet (на каждом узле)
  → Transform (парсинг, обогащение, фильтрация)
  → Elasticsearch / Loki / S3

Vector работает как DaemonSet. Каждый под собирает логи из файлов контейнеров на том же узле.


Установка через Helm

yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: vector
  namespace: observability
spec:
  chart:
    spec:
      chart: vector
      version: "0.x"
      sourceRef:
        kind: HelmRepository
        name: vector
        namespace: flux-system
  values:
    role: Agent
    customConfig:
      data_dir: /vector-data-dir
      sources:
        kubernetes_logs:
          type: kubernetes_logs
          namespace_labels_field: namespace_labels
          node_metadata_fields: [node_ip]
      transforms:
        parse_json:
          type: remap
          inputs: [kubernetes_logs]
          source: |
            if is_string(.message) {
              parsed, err = parse_json(.message)
              if err == null {
                . = merge(., parsed)
              }
            }
        add_env_label:
          type: remap
          inputs: [parse_json]
          source: |
            .environment = "${VECTOR_ENV:-unknown}"
            .cluster = "${VECTOR_CLUSTER:-unknown}"
      sinks:
        elasticsearch:
          type: elasticsearch
          inputs: [add_env_label]
          endpoints:
            - http://elasticsearch.elk.svc.cluster.local:9200
          index: "k8s-%F"
          bulk:
            action: index
    env:
      - name: VECTOR_ENV
        value: "prod"
      - name: VECTOR_CLUSTER
        value: "infra"

VRL: язык трансформаций Vector

VRL — специализированный язык для обработки логов. Никакого Lua, Groovy или JVM.

Парсинг JSON-логов:

parsed, err = parse_json(.message)
if err == null {
  . = merge(., parsed)
}

Удаление логов health-чеков:

if starts_with(string!(.message), "GET /healthz") {
  abort
}

abort полностью удаляет событие. Логи health-проб составляют 30–40% всех логов в нагруженном кластере.

Фильтр по namespace:

if !includes(["app", "production"], .kubernetes.namespace) {
  abort
}

Скрытие чувствительных данных:

if exists(.headers.authorization) {
  .headers.authorization = "REDACTED"
}

ServiceMonitor для метрик Vector

yamlvalues:
  serviceMonitor:
    enabled: true
    additionalLabels:
      release: kube-prom-stack

Полезные метрики:

promql# Скорость обработки логов
rate(vector_component_received_events_total[5m])

# Ошибки sink (неудачная доставка в Elasticsearch)
rate(vector_component_errors_total{component_kind="sink"}[5m])

# Размер буфера (backpressure)
vector_buffer_byte_size

Алерт на ошибки sink:

yaml- alert: VectorSinkErrors
  expr: rate(vector_component_errors_total{component_kind="sink"}[5m]) > 0
  for: 5m
  labels:
    severity: warning
  annotations:
    description: Vector не может доставить логи в sink.

Несколько sink: Elasticsearch и S3

yamlsinks:
  elasticsearch:
    type: elasticsearch
    inputs: [add_env_label]
    endpoints: [http://elasticsearch.elk.svc.cluster.local:9200]
    index: "k8s-%F"

  s3_archive:
    type: aws_s3
    inputs: [add_env_label]
    bucket: logs-archive-example
    region: ru-central1
    endpoint: https://storage.yandexcloud.net
    key_prefix: "k8s/%Y/%m/%d/"
    compression: gzip
    encoding:
      codec: ndjson
    auth:
      access_key_id: "${S3_ACCESS_KEY}"
      secret_access_key: "${S3_SECRET_KEY}"

Логи в S3 — gzip-сжатый NDJSON. 1 ГБ/день raw-логов → ~120 МБ.


Диагностика

Логи не появляются в Elasticsearch:

bashkubectl get pods -n observability -l app.kubernetes.io/name=vector
kubectl logs -n observability daemonset/vector --tail=50

Высокое потребление памяти: Vector по умолчанию буферизует в памяти. Для больших объёмов — дисковые буферы:

yamlsinks:
  elasticsearch:
    buffer:
      type: disk
      max_size: 268435488  # 256 MiB на узел

Отсутствуют k8s-метаданные: проверьте, что у ServiceAccount есть права на чтение pods и namespaces. Helm-чарт настраивает их автоматически.