OCB : construire son propre OpenTelemetry Collector sur-mesure
Pourquoi et comment utiliser l'OpenTelemetry Collector Builder (OCB) pour assembler une distribution du Collector taillée pour vos besoins : plus légère, plus sûre et plus facile à maintenir.
L’OpenTelemetry Collector est la pièce maîtresse de toute architecture d’observabilité moderne : il reçoit, transforme et exporte vos traces, métriques et logs sans coupler votre code à un vendor particulier. Mais quand vient le moment de le déployer en production, une question revient toujours : quelle distribution utiliser ?
La réponse de beaucoup d’équipes est otelcol-contrib, la distribution
« tout-en-un » qui embarque des centaines de composants. C’est pratique pour
démarrer, mais c’est rarement le bon choix en production. C’est là
qu’intervient OCB, l’OpenTelemetry Collector Builder.
Qu’est-ce qu’OCB ?
OCB (ocb, pour OpenTelemetry Collector Builder) est l’outil officiel qui
permet de générer votre propre distribution du Collector à partir d’un
simple fichier de manifeste. Vous déclarez la liste exacte des composants dont
vous avez besoin — receivers, processors, exporters, connectors, extensions —
et OCB se charge de générer le code Go, de résoudre les dépendances et de
compiler un binaire unique.
En d’autres termes : au lieu de prendre une distribution figée et trop large, vous composez la vôtre.
flowchart LR
A[builder-config.yaml] --> B[ocb]
B --> C[Code Go généré]
C --> D[go build]
D --> E[Binaire otelcol sur-mesure]
E --> F[Déploiement en production]
Pourquoi ne pas simplement utiliser otelcol-contrib ?
C’est la vraie question, et c’est elle qui justifie OCB. La distribution
contrib est excellente pour expérimenter, mais en production elle pose
plusieurs problèmes :
- Surface d’attaque. Chaque composant embarqué est du code qui tourne dans votre infrastructure. Embarquer 200 composants alors que vous en utilisez 8, c’est exposer inutilement votre plateforme aux CVE des 192 autres.
- Taille du binaire et de l’image. La distribution contrib pèse plusieurs centaines de Mo. Une distribution sur-mesure peut descendre à quelques dizaines de Mo, ce qui accélère les pulls d’image, les démarrages de pods et réduit la consommation mémoire.
- Audit et conformité. Une SBOM (Software Bill of Materials) courte et maîtrisée est bien plus facile à auditer qu’une liste de dépendances pléthorique. Vos équipes sécurité vous remercieront.
- Composants internes ou tiers. OCB permet d’intégrer vos propres composants ou des composants tiers non présents dans contrib, ce qui est impossible avec une distribution figée.
En résumé :
otelcol-contribpour prototyper, OCB pour produire.
Le manifeste : builder-config.yaml
Tout part d’un fichier de manifeste. Il décrit la distribution à produire et la liste des modules à inclure. Voici un exemple minimal mais réaliste — un Collector qui reçoit de l’OTLP, applique du batching et exporte vers un backend OTLP :
dist:
name: otelcol-custom
description: "Distribution OpenTelemetry Collector sur-mesure"
output_path: ./_build
version: 1.0.0
receivers:
- gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.116.0
processors:
- gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.116.0
- gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.116.0
exporters:
- gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.116.0
- gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.116.0
extensions:
- gomod: go.opentelemetry.io/collector/extension/healthcheckextension v0.116.0
Chaque entrée référence un module Go (gomod) avec sa version. C’est aussi
simple que ça : vous n’incluez que ce que vous déclarez.
Installer OCB : deux méthodes
Il existe deux façons d’obtenir le binaire ocb. Dans les deux cas, une chaîne
d’outils Go reste nécessaire : OCB génère du code Go puis orchestre un
go build pour produire le Collector final.
Méthode 1 — go install (compilation locale)
Si vous avez déjà Go sous la main, la commande la plus directe est :
go install go.opentelemetry.io/collector/cmd/builder@latest
Pratique en local, mais elle recompile OCB et installe « la dernière version » — deux choses peu souhaitables en CI, où l’on veut une version épinglée et des builds reproductibles.
Méthode 2 — télécharger le binaire pré-compilé (recommandé en CI)
Le projet opentelemetry-collector-releases
publie OCB sous forme de binaires pré-compilés pour chaque OS/arch. On
télécharge alors directement la version voulue, sans recompiler OCB :
OCB_VERSION=0.116.0
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
curl --proto '=https' --tlsv1.2 -fL -o ocb \
"https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/cmd%2Fbuilder%2Fv${OCB_VERSION}/ocb_${OCB_VERSION}_${GOOS}_${GOARCH}"
chmod +x ocb
Avantages : la version est explicitement épinglée (OCB_VERSION), il n’y a
rien à compiler pour obtenir OCB, et le téléchargement est rapide et identique
d’un run à l’autre — exactement ce qu’on attend d’un pipeline.
Construire la distribution
Quelle que soit la méthode d’installation, le build se fait avec la même commande :
# Générer le code Go + compiler la distribution
./ocb --config builder-config.yaml
# (option) générer le code SANS compiler — utile pour l'inspecter
# ou déléguer la compilation à go build (cross-compilation, cache, etc.)
./ocb --skip-compilation --config builder-config.yaml
# Lancer le Collector produit avec votre configuration d'exécution
./_build/otelcol-custom --config otel-config.yaml
OCB lit le manifeste, génère le code Go, télécharge les dépendances et compile
le binaire dans output_path. Le drapeau --skip-compilation est précieux en
CI : on génère les sources une fois, puis on lance autant de go build que
d’architectures cibles.
Industrialiser : manifeste partagé + manifeste local
Sur un parc avec plusieurs équipes, on ne veut pas dupliquer le même manifeste partout. Un pattern qui passe très bien à l’échelle consiste à scinder la description en deux fichiers :
- un manifeste partagé (
shared-manifest.yaml), maintenu par l’équipe plateforme : le socle commun imposé à toutes les distributions (extensions de santé, processors de limitation mémoire, composants internes maison…) ; - un manifeste local (
local-manifest.yaml), propre à chaque équipe : le nom de la distribution, sa version et les quelques composants spécifiques.
Le manifeste partagé peut être templatisé avec des variables d’environnement, ce qui permet d’aligner d’un coup la version du Collector sur tous ses composants — et d’intégrer vos propres modules Go hébergés dans votre organisation :
# shared-manifest.yaml — socle commun, templatisé
dist:
name: ${COLLECTOR_NAME:-otelcol-custom}
version: ${COLLECTOR_VERSION:-0.0.1}
output_path: _build
processors:
- gomod: go.opentelemetry.io/collector/processor/batchprocessor v${OTEL_VERSION}
- gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor v${OTEL_VERSION}
# composant interne, hébergé dans votre propre organisation
- gomod: github.com/votre-org/otel-signalsreporterprocessor v0.0.8
name: signalsreporterprocessor
extensions:
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v${OTEL_VERSION}
# local-manifest.yaml — spécifique à une équipe
dist:
name: my-custom-collector
description: My custom collector implementation
version: 0.1.1
exporters:
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter v${OTEL_VERSION}
Les deux fichiers sont ensuite fusionnés (par exemple avec yq, en
dédoublonnant chaque liste de composants), puis les variables sont résolues
(avec envsubst) pour produire le builder-config.yaml final passé à OCB :
export OTEL_VERSION=0.116.0
export COLLECTOR_NAME=$(yq '.dist.name' local-manifest.yaml)
export COLLECTOR_VERSION=$(yq '.dist.version' local-manifest.yaml)
# Fusion socle + local, puis résolution des variables -> builder-config.yaml
yq eval-all 'select(fileIndex==0) *+ select(fileIndex==1)' \
shared-manifest.yaml local-manifest.yaml | envsubst > builder-config.yaml
./ocb --config builder-config.yaml
Ce découpage donne à l’équipe plateforme la maîtrise du socle (sécurité, conformité, composants internes) tout en laissant chaque équipe libre d’ajouter ce dont elle a besoin. Le tout reste versionné dans Git, donc auditable et reproductible.
Reproductibilité et CI/CD
L’intérêt d’OCB ne s’arrête pas au build local. Comme le manifeste est un simple fichier versionné dans Git, il devient la source de vérité de votre distribution. Quelques bonnes pratiques :
- Épinglez les versions. Utilisez exactement la même version pour le Collector core et tous les composants afin d’éviter les incompatibilités.
- Intégrez le build dans votre CI. Générez et publiez votre image dans un pipeline, exactement comme n’importe quel autre artefact applicatif.
- Scannez l’image. Profitez de la SBOM réduite pour faire passer un scanner de vulnérabilités sur une surface maîtrisée.
Un exemple de job GitHub Actions
Voici les étapes clés d’un job qui valide et compile la distribution à chaque push. On y retrouve le téléchargement d’OCB en version épinglée, un cache Go pour accélérer les builds, puis la génération et la compilation :
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.25.7'
# Cache des dépendances et de la compilation Go
- name: Setup Go build cache
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: go-build-${{ runner.os }}-${{ hashFiles('builder-config.yaml', '**/go.sum') }}
restore-keys: go-build-${{ runner.os }}-
# Télécharger le binaire OCB pré-compilé, version épinglée
- name: Install OCB
env:
OCB_VERSION: 0.116.0
run: |
curl --proto '=https' --tlsv1.2 -fL -o ocb \
"https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/cmd%2Fbuilder%2Fv${OCB_VERSION}/ocb_${OCB_VERSION}_linux_amd64"
chmod +x ocb
# Générer le code Go puis compiler la distribution
- name: Build distribution
run: ./ocb --config builder-config.yaml
Pour produire des images multi-architecture, on dissocie génération et
compilation : OCB génère les sources une seule fois (--skip-compilation),
puis on lance un go build statique par architecture cible avant de construire
l’image :
- name: Generate collector source code
run: ./ocb --skip-compilation --config builder-config.yaml
- name: Build static binaries per arch
run: |
for arch in amd64 arm64; do
mkdir -p "container_binaries/$arch"
( cd _build && \
CGO_ENABLED=0 GOOS=linux GOARCH="$arch" \
go build -trimpath -ldflags="-s -w" \
-o "../container_binaries/$arch/otelcol" . )
done
-trimpathet-ldflags="-s -w"retirent les chemins de build et les tables de symboles : le binaire est plus léger et plus reproductible. AvecCGO_ENABLED=0, il est entièrement statique — ce qui ouvre la porte à une image vraiment minimale (voir plus bas).
Voici à quoi ressemble la chaîne complète, du manifeste au runtime :
sequenceDiagram
participant Dev as Développeur
participant CI as Pipeline CI
participant OCB as ocb
participant Reg as Registry
participant K8s as Kubernetes
Dev->>CI: push builder-config.yaml
CI->>OCB: ./ocb --config builder-config.yaml
OCB-->>CI: binaire otelcol-custom
CI->>Reg: docker push image sur-mesure
Reg->>K8s: pull image
K8s->>K8s: rollout du Collector
Une image minimale : FROM scratch
Comme le binaire produit est statique (CGO_ENABLED=0), on peut le glisser
dans une image partant de scratch : aucun OS, aucun shell, aucun
gestionnaire de paquets. Le seul ajout indispensable est le bundle de
certificats CA (pour les exports en TLS) :
FROM alpine:3.21 AS certs
RUN apk --update add ca-certificates
FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --chmod=755 ./container_binaries/amd64/otelcol /otelcol
# Tourner en utilisateur non-root
USER 10001
# OTLP gRPC / HTTP
EXPOSE 4317 4318
ENTRYPOINT ["/otelcol"]
CMD ["--config", "/config/otel-config.yaml"]
Couplée à un manifeste réduit, cette approche donne une image de quelques dizaines de Mo, sans shell ni paquets superflus. La surface d’attaque se limite à votre seul binaire — exactement ce qu’attendent les équipes sécurité.
En pratique : par où commencer ?
- Listez vos besoins réels. Quels signaux collectez-vous (traces, métriques, logs) ? Vers quels backends exportez-vous ? Cette liste devient votre manifeste.
- Partez du strict nécessaire. Ajoutez les composants au fur et à mesure plutôt que de tout inclure « au cas où ».
- Versionnez le manifeste et automatisez le build dans votre CI.
- Mesurez. Comparez la taille d’image, l’empreinte mémoire et le temps de démarrage avant/après : les gains sont souvent spectaculaires.
Conclusion
OCB transforme l’OpenTelemetry Collector d’une boîte noire générique en un composant maîtrisé, léger et auditable, parfaitement adapté à votre contexte. C’est la différence entre subir une distribution et posséder la sienne — un réflexe d’ingénierie qui paie en sécurité, en coûts et en sérénité opérationnelle.
Si vous souhaitez auditer votre pipeline d’observabilité ou mettre en place une distribution sur-mesure du Collector, parlons-en.