OpenTelemetry Collector 是整个可观测性体系里承上启下的关键组件:它负责接收来自各个应用上报的 traces、metrics 和 logs,经过加工处理后转发到 Prometheus、Jaeger、Loki 或者各类商业后端。而要让它真正落地,容器化几乎是必经之路。本文从组件原理讲起,一步步给出可复用的镜像构建与部署配置。

一、先理解 Collector 的核心架构再动手
OpenTelemetry Collector 本质上是一条数据处理管道,由四类核心组件构成:receiver负责接收数据,processor负责加工数据,exporter负责导出数据,较新版本还引入了connector用来在管道之间转换信号类型。理解这个模型非常重要,因为配置文件的整体结构就是围绕这三类组件展开的。
一条典型的数据流向是:应用通过 OTLP 协议把 trace 数据推给 otlp receiver,数据经过 batch processor 做批量压缩,最后由 otlp exporter 或 prometheusremoteexporter 发往后端。配置文件用 YAML 描述这条管道,形如 service.pipelines.traces 下声明 receivers、processors、exporters 三个列表,三者串起来就是一条完整的链路。如果配置里声明了某个组件却没有挂进任何 pipeline,Collector 启动时会直接报错,这是新手最常踩的坑之一。
另一个需要理解的点是发行版区别。官方提供三个发行版:otelcol-contrib包含社区贡献的所有组件,功能最全但镜像体积也最大;otelcol是核心版,只保留官方维护的组件;otelcol-k8s则面向 Kubernetes 场景。容器化部署时如果没有特殊体积要求,建议直接选 contrib 版本,可以省去后续想接新后端时重新编译镜像的麻烦。
二、编写 Dockerfile 与配置文件
构建 Collector 镜像其实很简单,官方在 Docker Hub 上提供了 otel/opentelemetry-collector-contrib 基础镜像,我们要做的就是把自定义配置文件放进去。下面是一份生产可用的 Dockerfile,基于多阶段构建控制镜像体积,并显式声明暴露端口。
FROM otel/opentelemetry-collector-contrib:latest AS collector FROM alpine:3.19 COPY --from=collector /otelcol-contrib /otelcol-contrib COPY config.yaml /etc/otelcol-contrib/config.yaml EXPOSE 4317 4318 8888 13133 ENTRYPOINT ["/otelcol-contrib"] CMD ["--config=/etc/otelcol-contrib/config.yaml"]
对应的 config.yaml 需要重点关注两点:一是 receivers 中的端点绑定地址必须写 0.0.0.0 而不是 localhost,否则容器外无法访问;二是记得配置 health_check extension,它是容器健康检查的基础。
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 5s
send_batch_size: 1024
memory_limiter:
check_interval: 1s
limit_mib: 512
exporters:
prometheus:
endpoint: 0.0.0.0:8889
extensions:
health_check:
endpoint: 0.0.0.0:13133
service:
extensions: [health_check]
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp/jaeger]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [prometheus]
这里有几个细节值得展开。memory_limiter必须放在 processors 列表的第一位,它能在内存压力过大时主动拒绝接收数据,避免容器被 OOMKilled。batch processor 的 timeout 不宜设置过长,否则会明显增加数据上报延迟。如果你的后端是 Jaeger 或 Tempo,exporter 需要额外补充 endpoint 字段指向对应服务的地址,注意在容器网络里要用服务名而不是 127.0.0.1。
三、用 Docker Compose 组装完整链路
单独跑一个 Collector 意义不大,实际使用时通常要连同后端一起编排。下面这份 docker-compose 配置把 Collector、Jaeger 和 Prometheus 串成一条完整链路,应用上报的数据最终可以在 Jaeger UI 里查询。
version: "3.8"
services:
otel-collector:
image: otel-collector-custom:latest
container_name: otel-collector
command: ["--config=/etc/otelcol-contrib/config.yaml"]
volumes:
- ./config.yaml:/etc/otelcol-contrib/config.yaml
ports:
- "4317:4317"
- "4318:4318"
- "8889:8889"
- "13133:13133"
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:13133/"]
interval: 10s
timeout: 3s
retries: 3
deploy:
resources:
limits:
memory: 768M
restart: unless-stopped
jaeger:
image: jaegertracing/all-in-one:latest
ports:
- "16686:16686"
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
这份配置里有几处实践要点。第一,用 volume 挂载配置文件而不是打进镜像,方便开发阶段反复调整;生产环境如果追求配置不可变,再切换回镜像内置的方式。第二,healthcheck 使用 wget 探测 13133 健康检查端口,因为官方镜像里没有 curl,用 curl 会一直报探测失败。第三,资源限制设为 768M,比 memory_limiter 的 512M 上限略高,留出进程本身的余量,这两个数值的配合关系在生产环境非常关键,限制设得比 limiter 低会导致容器先于保护机制被杀掉。
启动后建议先做一次冒烟测试,用 curl 向 4318 端口推一条 trace,再到 Jaeger UI 确认数据是否到达。如果启动失败,优先检查配置文件里是否声明了未使用的组件,以及 exporter 指向的服务名在 compose 网络里能否解析。
四、独立部署与 Agent 部署的模式选择
容器化 Collector 有两种典型形态。一种是上面演示的独立网关模式,Collector 以中心化服务运行,所有应用直连它,适合多集群、多团队共享的规模场景,优点是配置集中管理、应用侧零侵入,缺点是网络多一跳、网关挂了影响面大。另一种是 Agent 模式,Collector 以 sidecar 或 DaemonSet 形态跑在应用旁边,接收本地数据后转发给中心网关,延迟更低,还能在本地做一些敏感数据脱敏处理。
选择时可以参考数据规模和合规要求:数据量大、希望减少跨网络传输的,用 Agent 加网关的两级架构;小规模环境直接单层网关即可,没必要引入额外复杂度。无论哪种形态,容器化部署的配置思路都是一致的——把配置外置、绑定 0.0.0.0、配好健康检查和内存保护,这三件事做扎实了,Collector 在生产环境就能长期稳定运行。
OpenTelemetry CollectorDocker部署可观测性修改时间:2026-09-13 17:58:49