使用 Vector 将日志转换为 JSON 并添加 Kubernetes Pod 标签?

解读

在国内云原生面试中,这道题表面问“日志转 JSON”,实则考察是否能把非结构化日志与 Kubernetes 元数据打通并落地到 CouchDB
Vector 作为 CNCF 毕业项目,已大量替代 Logstash/Fluent Bit,面试官想确认:

  1. 你熟悉 Vector 的 transform 阶段 能否完成正则→JSON 的解析;
  2. 你能否利用 kubernetes_logs source 自动注入 Pod 标签;
  3. 最终写入 CouchDB 时,如何构造 _id 与 _rev 以避免写冲突
  4. 是否考虑离线场景(边缘节点断网续传)与多主复制带来的幂等性要求。

知识点

  • Vector 的 remap (VRL) 语言:parse_regex、parse_json、merge 函数
  • kubernetes_logs source 内置字段:kubernetes.pod_labels、kubernetes.pod_namespace、kubernetes.pod_name
  • CouchDB bulk docs API_bulk_get 的幂等写入策略
  • 国内主流镜像站(阿里云、DaoCloud)拉取 timberio/vector 镜像的加速配置
  • 离线优先场景下,Vector 的 disk_buffer 与 CouchDB 的 _local 文档协同做断点续传
  • 多主复制时,_id 必须包含宿主机+Pod UUID+时间戳 避免不同边缘节点冲突

答案

  1. 部署 Vector DaemonSet,使用国内镜像 registry.cn-hangzhou.aliyuncs.com/acs/vector:0.38.0-alpine,挂载 /var/log/pods/var/lib/docker/containers
  2. 配置 kubernetes_logs source,自动注入 Pod 标签
[sources.k8s]
type = "kubernetes_logs"
extra_label_selector = "app in (order, payment)"   # 仅采集业务 Pod,降低 60% 流量
  1. 在 transform 阶段用 VRL 把原始日志转为 JSON 并合并标签:
[transforms.to_json]
type = "remap"
inputs = ["k8s"]
source = '''
  # 业务日志格式:2025-06-05 14:23:01 | INFO | userId=123 | action=pay
  parsed = parse_regex!(.message, r'^(?P<timestamp>\S+ \S+) \| (?P<level>\w+) \| userId=(?P<userId>\d+) \| action=(?P<action>\w+)')
  . = merge(., parsed)
  .pod_labels = .kubernetes.pod_labels          # 保留 Pod 标签
  .couch_id = join!([.kubernetes.pod_name, .timestamp, .userId], "-")  # 构造唯一 _id
'''
  1. sink 到 CouchDB,开启 bulk 与幂等
[sinks.couch]
type = "http"
inputs = ["to_json"]
uri = "http://couchdb-svc.couchdb.svc.cluster.local:5984/logs/_bulk_docs"
method = "post"
encoding.codec = "json"
request.concurrency = "adaptive"
request.headers = "Content-Type:application/json"
auth.strategy = "basic"
auth.user = "admin"
auth.password = "${COUCH_PW}"
# 国内集群 TLS 普遍自签,需跳过校验
tls.verify_certificate = false
  1. 在 CouchDB 侧预置设计文档 _design/vector,把 couch_id 设为唯一索引,避免重复写入;同时开启 q=2 n=3 保证跨可用区高可用。
  2. 离线节点启用 Vector 的 disk_buffer.max_size = 10GBacknowledgements.enabled = true,网络恢复后自动重放;CouchDB 的 _local/vector_checkpoint 记录最后一条成功 _rev,实现断点续传

拓展思考

  • 如果日志量超过 5 万条/秒,可把 Vector 的 sink 换成 kafka 先削峰,再用独立 Consumer 组批量写 CouchDB,避免直接打爆单节点。
  • 国内金融场景要求 6 个月可追溯,可在 CouchDB 里按 年月分库,利用 _partition 插件把同一 Pod 的日志路由到同一分片,查询时加 ?partition=order-202506 把扫描范围缩小 1/30。
  • 多活容灾时,北京与深圳两套 CouchDB 集群做 双向同步,需给每个地区加 region 前缀到 _id,防止冲突;Vector 侧通过 环境变量 REGION=bj 动态拼接 _id,实现单元化闭环