第五章:Promtail 配置

深入学习 Promtail 日志收集代理的配置和使用方法。

最后更新: 2024-01-19
页面目录

Promtail 配置

Promtail 是 Loki 的日志收集代理,负责发现日志文件并将其发送到 Loki。

Promtail 概述

┌─────────────────────────────────────────────────────────────────┐
│                      Promtail 工作流程                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌─────────────┐     ┌─────────────┐     ┌─────────────┐      │
│   │   配置文件   │     │  日志发现    │     │   日志处理   │      │
│   │   Config    │ ──► │  Discovery  │ ──► │  Pipeline   │      │
│   └─────────────┘     └─────────────┘     └──────┬──────┘      │
│                                                   │              │
│                                                   ▼              │
│                                            ┌─────────────┐      │
│                                            │   Loki      │      │
│                                            │   Push      │      │
│                                            └─────────────┘      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

配置文件结构

# /etc/promtail/config.yaml
---
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /var/lib/promtail/positions.yaml

client:
  url: http://loki:3100/loki/api/v1/push

scrape_configs:
  - job_name: system
    static_configs:
      - targets:
          - localhost
        labels:
          job: system
          host: {{ ansible_hostname }}
          __path__: /var/log/*.log

完整配置示例

# /etc/promtail/config.yaml
---
# 服务器配置
server:
  http_listen_address: 0.0.0.0
  http_listen_port: 9080
  grpc_listen_address: ""
  grpc_listen_port: 0
  http_server_read_timeout: 30s
  http_server_write_timeout: 30s
  http_server_idle_timeout: 30s

# 位置文件
positions:
  filename: /var/lib/promtail/positions.yaml
  ignore_invalid_yaml: false
  max_line_size: 256kb
  max_lines: 0

# Loki 客户端配置
client:
  url: http://loki:3100/loki/api/v1/push
  timeout: 10s
  batchwait: 1s
  batchsize: 102400
  follow_redirects: true
  backoff_config:
    min_period: 500ms
    max_period: 5m
    max_retries: 20
  stream_lag_labels: hostname

  # 认证配置
  basic_auth:
    username: admin
    password: admin

  # TLS 配置
  tls_config:
    ca_file: /etc/promtail/certs/ca.crt
    cert_file: /etc/promtail/certs/cert.crt
    key_file: /etc/promtail/certs/key.key
    server_name: loki.example.com
    insecure_skip_verify: false

  # Proxy 配置
  proxy_url: http://proxy.example.com:8080

# 日志配置
log_level: info
log_format: logfmt

# 目标发现配置
target_config:
  watch_config_changes: true
  sync_period: 10s

# 采集配置
scrape_configs:
  - job_name: local
    static_configs:
      - targets:
          - localhost
        labels:
          job: local
          env: production
          __path__: /var/log/*.log

scrape_configs 配置

static_configs

# 静态文件配置
scrape_configs:
  - job_name: nginx
    static_configs:
      - targets:
          - localhost
        labels:
          job: nginx
          service: web
          environment: production
          __path__: /var/log/nginx/*.log

kubernetes_sd_configs

# Kubernetes 服务发现
scrape_configs:
  - job_name: kubernetes-pods
    kubernetes_sd_configs:
      - role: pod
        api_server: https://kubernetes.default.svc:443
        kubeconfig_file: /var/lib/promtail/kubeconfig
        namespaces:
          names:
            - default
            - production
        selectors:
          - role: pod
            label: "app.*"
          - role: pod
            label: "app=nginx"

    # Pipeline 阶段
    pipeline_stages:
      - docker: {}
      - labels:
          cluster: production
          namespace: default

journal_config

# systemd Journal
scrape_configs:
  - job_name: journal
    journal:
      max_age: 12h
      labels:
        job: journal
        host: hostname
      path: /var/log/journal
    relabel_configs:
      - source_labels: ['__journal__systemd_unit']
        target_label: unit
      - source_labels: ['__journal_priority']
        target_label: priority

syslog_config

# Syslog
scrape_configs:
  - job_name: syslog
    syslog:
      listen_address: 0.0.0.0:1514
      listen_protocol: tcp
      labels:
        job: syslog
      idle_timeout: 60s
      label_structured_data: true
      max_message_length: 2048
    relabel_configs:
      - source_labels: ['__syslog_message_hostname']
        target_label: hostname

Pipeline 阶段

docker

# Docker 日志格式
pipeline_stages:
  - docker: {}

cri

# CRI 日志格式
pipeline_stages:
  - cri: {}

regex

# 正则解析
pipeline_stages:
  - regex:
      expression: '^(?P<time>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)\s+(?P<level>\w+)\s+(?P<message>.*)$'
  - labels:
      level:

json

# JSON 解析
pipeline_stages:
  - json:
      expressions:
        timestamp: ts
        level: level
        message: msg
        user: user
        service: service
  - labels:
      level:
      service:
  - timestamp:
      source: timestamp
      format: RFC3339Nano
  - output:
      source: message

logfmt

# logfmt 解析
pipeline_stages:
  - logfmt: {}
  - labels:
      level:
      service:

timestamp

# 时间戳处理
pipeline_stages:
  - regex:
      expression: '^(?P<time>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})'
  - timestamp:
      source: time
      format: '2006-01-02 15:04:05'
      location: Asia/Shanghai

labels

# 标签处理
pipeline_stages:
  - labels:
      level:          # 添加 level 标签
      service:        # 添加 service 标签
      environment:    # 添加 environment 标签

output

# 输出处理
pipeline_stages:
  - json:
      expressions:
        message: msg
  - output:
      source: message

match

# 条件匹配
pipeline_stages:
  - match:
      selector: '{service="nginx"}'
      stages:
        - regex:
            expression: '^(?P<ip>\d+\.\d+\.\d+\.\d+)'
        - labels:
            client_ip:

Relabel 配置

# Relabel 配置
scrape_configs:
  - job_name: kubernetes-pods
    kubernetes_sd_configs:
      - role: pod

    relabel_configs:
      # 从标签提取信息
      - source_labels: ['__meta_kubernetes_pod_label_app']
        regex: '(.+)'
        target_label: app

      # 从元信息提取
      - source_labels: ['__meta_kubernetes_namespace']
        regex: '(.*)'
        target_label: namespace

      # 覆盖标签
      - source_labels: ['__meta_kubernetes_pod_name']
        regex: '(.*)'
        target_label: pod

      # 只保留 nginx pod
      - source_labels: ['__meta_kubernetes_pod_label_app']
        regex: 'nginx'
        action: keep

      # 移除不需要的标签
      - regex: '__meta_kubernetes_pod_label_(.*)'
        action: labeldrop

      # 替换标签前缀
      - regex: '__meta_kubernetes_(.*)'
        replacement: 'kubernetes_$1'
        action: labelmap

Kubernetes 部署

DaemonSet 部署

# promtail-daemonset.yaml
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: promtail
  namespace: loki
spec:
  selector:
    matchLabels:
      app: promtail
  template:
    metadata:
      labels:
        app: promtail
    spec:
      serviceAccountName: promtail
      containers:
        - name: promtail
          image: grafana/promtail:2.9.0
          args:
            - -config.file=/etc/promtail/config.yml
            - -config.expand-labels=true
          volumeMounts:
            - name: config
              mountPath: /etc/promtail
            - name: run
              mountPath: /var/run/promtail
            - name: containers
              mountPath: /var/lib/docker/containers
              readOnly: true
            - name: pods
              mountPath: /var/log/pods
              readOnly: true
            - name: syslog
              mountPath: /var/log/syslog
              readOnly: true
          env:
            - name: HOSTNAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          securityContext:
            runAsUser: 0
            privileged: true
      volumes:
        - name: config
          configMap:
            name: promtail
        - name: run
          hostPath:
            path: /var/run/promtail
        - name: containers
          hostPath:
            path: /var/lib/docker/containers
        - name: pods
          hostPath:
            path: /var/log/pods
        - name: syslog
          hostPath:
            path: /var/log/syslog

ConfigMap

# promtail-configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: promtail
  namespace: loki
data:
  config.yml: |
    server:
      http_listen_port: 9080
      grpc_listen_port: 0

    positions:
      filename: /var/run/promtail/positions.yaml

    client:
      url: http://loki:3100/loki/api/v1/push
      timeout: 10s
      batchwait: 1s
      batchsize: 102400

    scrape_configs:
      - job_name: kubernetes-pods
        kubernetes_sd_configs:
          - role: pod
        relabel_configs:
          - source_labels:
              - __meta_kubernetes_pod_label_name
            regex: (.+)
            target_label: service
          - source_labels:
              - __meta_kubernetes_namespace
            target_label: namespace
          - source_labels:
              - __meta_kubernetes_pod_name
            target_label: pod
          - source_labels:
              - __meta_kubernetes_pod_uid
            regex: (.+)
            target_label: __pod_uid__
          - source_labels:
              - __meta_kubernetes_pod_container_name
            target_label: container
          - source_labels:
              - __meta_kubernetes_pod_container_name
            regex: (.+)
            target_label: __service_container__
          - source_labels:
              - __meta_kubernetes_pod_label_name
            regex: ''
            action: drop
          - source_labels:
              - __meta_kubernetes_pod_label_app
            regex: (.+)
            target_label: app
          - source_labels:
              - __meta_kubernetes_pod_label_controller
            regex: (.+)
            target_label: controller

Docker 日志收集

# /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3",
    "labels": "production"
  }
}

常用命令

# 查看日志
journalctl -u promtail -f

# 检查配置
promtail -config.file=/etc/promtail/config.yml -dry-run

# 查看帮助
promtail -help

下一步

接下来让我们学习客户端 SDK。

👉 客户端 SDK