起容器碰生产 mini-infra 暴露四坑,逐个修:
- 端口:9090 被 mini-infra 自身 mihomo/clash API 占(docker ps 看不到 host 网/宿主进程端口、摸底漏),Prometheus 让到 9091
- Loki+Tempo:配置注释里的 ${MINIO_*} 被 expand-env 连注释严格校验、通配符触发 "missing closing brace",改纯文字(先前误判 Tempo 宽松、其实同款)
- Collector 镜像:daocloud mirror 的 collector-contrib:0.116.0 缺 binary(exec no such file、force 重下同 digest 仍坏);0.114.0 的 redaction 缺 blocked_key_patterns/redact_all_types(脱敏红线);定版 0.155.0(binary 完好+redaction 字段最全)
五件全绿:Collector/Prometheus(9091)/Tempo/Loki/Grafana 全 200,实占约 170MiB(<< 3.4G 上限)。
follow-up:0.155 提示 otlphttp→otlp_http(deprecated warning、不阻塞)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
218 lines
11 KiB
YAML
218 lines
11 KiB
YAML
# =============================================================================
|
|
# 全链路可观测性栈 —— OTel Collector + Prometheus + Tempo + Loki + Grafana
|
|
# 配置控制面阶段四 · 第一波(纯增量、不碰生产)
|
|
# -----------------------------------------------------------------------------
|
|
# 设计权威:docs/agent-specs/2026-07-05-全链路可观测性-OTel三信号全栈-设计.md
|
|
# 五件的形状 = 多源汇一口、一口先脱敏再分三库、一板看到底(设计 §4)。
|
|
# Collector 收 OTLP → 脱敏 + 尾部采样 + 批量 → Prometheus(指标)/ Tempo(追踪)
|
|
# / Loki(日志);Grafana 统一看板 + 三联下钻。
|
|
#
|
|
# 落点 = mini-infra(100.64.0.8,已扩容到 32G / available 24Gi,设计 §10.6)。
|
|
# 同箱的是跨项目生产件(new-api / gitea / nacos / rocketmq / ragflow),所以资源纪律
|
|
# 要比 nacos/rocketmq 那套更严 —— 见下方"资源双上限"。
|
|
#
|
|
# ── 部署纪律(全部编进了本文件)──────────────────────────────────────────
|
|
# 1) 网络:接既有 infra-shared 网(external、不新建),与 infra-minio / new-api /
|
|
# infra-nacos / infra-rmq-namesrv 同网,容器间用 DNS 名互通。观测栈五件之间用
|
|
# compose 服务名(otel-collector / prometheus / tempo / loki / grafana)解析;
|
|
# 连既有件用其容器名(infra-minio)。
|
|
#
|
|
# 2) 端口避撞(逐个核对过 mini-infra 现有占用:new-api=3000 / gitea=3001 /
|
|
# ragflow=9380-9381 / postgres=5433 / minio=9000-9001 / mysql=3306 / redis=6379 /
|
|
# nacos=8848 / rocketmq=9876,10911 / nginx=80,443 / infinity=23817,23820):
|
|
# Grafana → 3002 (3000/3001 已占,绝不用默认 3000)
|
|
# Prometheus → 9091 (宿主;9090 被 mini-infra 的 mihomo/clash API 占,容器内仍 9090)
|
|
# Loki → 3100
|
|
# Tempo → 3200 (query API)
|
|
# Collector → 4317(gRPC OTLP)/ 4318(HTTP OTLP)/ 13133(健康探针)
|
|
# Collector 自身遥测 8888 与业务指标出口 8889 不对外映射 —— Prometheus 同网 scrape。
|
|
#
|
|
# 3) 资源双上限(设计 §5 面三 / §9 硬红线):每件设 mem_limit + cpus 双上限,
|
|
# 并把 cpu_shares 压到 512(生产件默认 1024 的一半),CPU 争用时观测让路,
|
|
# 绝不让失控的 Prometheus/Tempo 在 CPU/IO 上挤兑 new-api(生成命脉)。
|
|
# 五件 mem_limit 合计约 3.4G,落进 24Gi 余量绰绰有余。
|
|
#
|
|
# 4) 存储:Tempo / Loki 的对象存储后端复用既有 infra-minio(不占新端口),各用独立
|
|
# 新桶 obs-tempo / obs-loki(绝不碰 ragflow 现有桶),桶由 minio-init 一次性建。
|
|
# Prometheus 用本地卷、保留 15 天。WAL/index 等本地态落 named volume(避 uid 权限坑)。
|
|
#
|
|
# 5) 密钥:S3 凭据与 Grafana 口令经 ${VAR} 从同目录 .env 读(compose 起时自动加载),
|
|
# 本文件与各配置文件都不落明文;.env 只在服务器 chmod 600 存在、不入仓,权威副本见
|
|
# docs/内网凭据与端点.md。Tempo/Loki 配置内的 ${VAR} 由各自 -config.expand-env 从
|
|
# 容器环境变量展开(故下面给这两件显式注入 environment)。
|
|
#
|
|
# 起停:cd /opt/infra-observability && docker compose up -d;探活见 health-check.sh。
|
|
# 本文件由第一波交付,起容器由主控终审后择窗口做 —— 交付阶段不 up、不 ssh。
|
|
# =============================================================================
|
|
services:
|
|
|
|
# ── 一次性:在既有 infra-minio 上建观测专用桶(幂等,建完即退出)────────────
|
|
# 用 mc 客户端连同网 MinIO,--ignore-existing 保证可重复执行不报错。
|
|
# tempo / loki 经 depends_on 等它成功退出后再起,确保桶已就位。
|
|
minio-init:
|
|
image: minio/mc:RELEASE.2024-10-29T15-34-59Z
|
|
container_name: infra-obs-minio-init
|
|
networks: [infra-shared]
|
|
environment:
|
|
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
|
|
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
|
|
# $$ 转义:让 $ 原样传给容器内 shell 读环境变量,而非被 compose 提前替换。
|
|
entrypoint: >
|
|
/bin/sh -c "
|
|
mc alias set obs http://infra-minio:9000 $${MINIO_ACCESS_KEY} $${MINIO_SECRET_KEY} &&
|
|
mc mb --ignore-existing obs/obs-tempo &&
|
|
mc mb --ignore-existing obs/obs-loki &&
|
|
echo 'obs buckets ready: obs-tempo / obs-loki'
|
|
"
|
|
restart: "no"
|
|
|
|
# ── OTel Collector(统一入口)────────────────────────────────────────────
|
|
# 收 OTLP(跨机经 Tailscale 推来)→ 脱敏 + 尾部采样 + 批量 → 分发三库。
|
|
# 脱敏是进库前最后一道安全红线(手机号/token 打码)。健康探针在 13133。
|
|
otel-collector:
|
|
image: otel/opentelemetry-collector-contrib:0.155.0 # 版本几经周折:0.116.0 在 daocloud mirror 的镜像缺 binary(exec no such file、force 重下同 digest 仍坏);降 0.114.0 binary 好但 redaction 不认 blocked_key_patterns/redact_all_types(脱敏红线要键名屏蔽);0.155.0 binary 完好且 redaction 字段最全、向后兼容本配置
|
|
container_name: infra-otelcol
|
|
restart: unless-stopped
|
|
networks: [infra-shared]
|
|
command: ["--config=/etc/otelcol-contrib/config.yaml"]
|
|
volumes:
|
|
- ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml:ro
|
|
ports:
|
|
- "4317:4317" # gRPC OTLP 入口(跨机信号源推送)
|
|
- "4318:4318" # HTTP OTLP 入口(跨机信号源推送)
|
|
- "13133:13133" # health_check extension(供 health-check.sh 探活)
|
|
depends_on:
|
|
- tempo
|
|
- loki
|
|
mem_limit: 512m
|
|
cpus: 0.50
|
|
cpu_shares: 512 # 低于生产件默认 1024,CPU 争用时让路
|
|
logging:
|
|
driver: json-file
|
|
options: { max-size: "10m", max-file: "3" }
|
|
|
|
# ── Prometheus(指标存储)──────────────────────────────────────────────
|
|
# 本地卷、保留 15 天。scrape 自身 + Collector 出口;跨机抓 game-cloud/nacos/rmq
|
|
# 的目标在 prometheus.yml 里注释占位,后续波启用。
|
|
prometheus:
|
|
image: prom/prometheus:v3.1.0
|
|
container_name: infra-prometheus
|
|
restart: unless-stopped
|
|
networks: [infra-shared]
|
|
command:
|
|
- "--config.file=/etc/prometheus/prometheus.yml"
|
|
- "--storage.tsdb.path=/prometheus"
|
|
- "--storage.tsdb.retention.time=15d" # 保留期 15 天(设计 §7,7-15d 上限)
|
|
- "--web.enable-lifecycle" # 允许热加载配置(POST /-/reload)
|
|
volumes:
|
|
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
|
- prometheus-data:/prometheus
|
|
ports:
|
|
- "9091:9090" # 宿主 9091(9090 被 mini-infra 的 mihomo/clash API 占,对外改 9091;容器内仍 9090,Grafana 走 prometheus:9090 不受影响)
|
|
mem_limit: 1g
|
|
cpus: 0.75
|
|
cpu_shares: 512
|
|
logging:
|
|
driver: json-file
|
|
options: { max-size: "10m", max-file: "3" }
|
|
|
|
# ── Tempo(追踪存储,后端 = MinIO/obs-tempo)──────────────────────────────
|
|
# 单进程 monolithic。收 Collector 转发的 OTLP(容器内 4317,不对外映射),blocks
|
|
# 落 MinIO、WAL 落本地卷。-config.expand-env 让配置里的 ${MINIO_*} 从环境变量展开。
|
|
tempo:
|
|
image: grafana/tempo:2.7.1
|
|
container_name: infra-tempo
|
|
restart: unless-stopped
|
|
networks: [infra-shared]
|
|
command: ["-config.file=/etc/tempo.yaml", "-config.expand-env=true"]
|
|
environment:
|
|
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
|
|
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
|
|
volumes:
|
|
- ./tempo.yaml:/etc/tempo.yaml:ro
|
|
- tempo-data:/var/tempo
|
|
ports:
|
|
- "3200:3200" # query API(Grafana 内网走 tempo:3200,对外便于调试/探活)
|
|
depends_on:
|
|
minio-init:
|
|
condition: service_completed_successfully
|
|
mem_limit: 768m
|
|
cpus: 0.50
|
|
cpu_shares: 512
|
|
logging:
|
|
driver: json-file
|
|
options: { max-size: "10m", max-file: "3" }
|
|
|
|
# ── Loki(日志存储,后端 = MinIO/obs-loki)────────────────────────────────
|
|
# 单进程 monolithic。只收 WARN/ERROR(在源头控),chunks 落 MinIO、index 落本地卷。
|
|
# OTLP 摄入端点 = :3100/otlp,Collector 用 otlphttp 发到这里。
|
|
loki:
|
|
image: grafana/loki:3.3.2
|
|
container_name: infra-loki
|
|
restart: unless-stopped
|
|
networks: [infra-shared]
|
|
command: ["-config.file=/etc/loki/loki-config.yaml", "-config.expand-env=true"]
|
|
environment:
|
|
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
|
|
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
|
|
volumes:
|
|
- ./loki-config.yaml:/etc/loki/loki-config.yaml:ro
|
|
- loki-data:/loki
|
|
ports:
|
|
- "3100:3100"
|
|
depends_on:
|
|
minio-init:
|
|
condition: service_completed_successfully
|
|
mem_limit: 768m
|
|
cpus: 0.50
|
|
cpu_shares: 512
|
|
logging:
|
|
driver: json-file
|
|
options: { max-size: "10m", max-file: "3" }
|
|
|
|
# ── Grafana(统一看板 + 告警 + admin 一键进盘)──────────────────────────
|
|
# 预配三数据源(Prometheus/Tempo/Loki)+ 三联下钻 + 概览盘。容器内 3000、对外 3002。
|
|
# admin 口令经 .env 注入;首次进盘即见数据源与看板(设计 §10.3 本期做)。
|
|
grafana:
|
|
image: grafana/grafana:11.4.0
|
|
container_name: infra-grafana
|
|
restart: unless-stopped
|
|
networks: [infra-shared]
|
|
environment:
|
|
GF_SECURITY_ADMIN_USER: ${GF_ADMIN_USER:-admin}
|
|
GF_SECURITY_ADMIN_PASSWORD: ${GF_ADMIN_PASSWORD}
|
|
GF_USERS_ALLOW_SIGN_UP: "false"
|
|
GF_ANALYTICS_REPORTING_ENABLED: "false"
|
|
GF_ANALYTICS_CHECK_FOR_UPDATES: "false"
|
|
# 三联下钻(trace↔log↔metric)在 Grafana 11 已 GA,靠数据源 provisioning 的 jsonData
|
|
# 配跳转即可,无需 feature toggle。
|
|
volumes:
|
|
- ./grafana/provisioning:/etc/grafana/provisioning:ro
|
|
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro
|
|
- grafana-data:/var/lib/grafana
|
|
ports:
|
|
- "3002:3000"
|
|
depends_on:
|
|
- prometheus
|
|
- tempo
|
|
- loki
|
|
mem_limit: 384m
|
|
cpus: 0.50
|
|
cpu_shares: 512
|
|
logging:
|
|
driver: json-file
|
|
options: { max-size: "10m", max-file: "3" }
|
|
|
|
# ── 既有共享网(external,不新建)──────────────────────────────────────────
|
|
networks:
|
|
infra-shared:
|
|
external: true
|
|
|
|
# ── 本地持久卷(docker 托管,避 bind-mount 的 uid 权限坑)────────────────────
|
|
# Prometheus TSDB / Grafana 状态需持久;Tempo WAL / Loki index 是本地热态,块数据在 MinIO。
|
|
volumes:
|
|
prometheus-data:
|
|
grafana-data:
|
|
tempo-data:
|
|
loki-data:
|