The OpenTelemetry Collector Builder (OCB) in OpenTelemetry
A complete, plain-English guide to the tool that lets you assemble your very own OpenTelemetry Collector, with exactly the pieces you need and nothing more, and to the habits that keep a custom Collector safe, small and maintainable.
Imagine you are packing for a trip. The shop sells a huge ready-made suitcase that already contains clothes for every climate, a tent, a snorkel, three kinds of shoes and a winter coat. It is convenient, because you never have to think, but it is heavy, expensive to carry, and most of what is inside you will never use. Or you could pick a small bag and pack only what your trip needs. You spend a little time choosing, and in return you travel light, you know exactly what you are carrying, and nothing surprising is hiding in the corners.
The OpenTelemetry Collector offers the same choice. You can take a ready-made version that includes a large collection of components, or you can build a version that contains only the receivers, processors and exporters your system really uses. The tool that makes the second option possible is called the OpenTelemetry Collector Builder, usually shortened to OCB. In this tutorial we will explain what OCB is, how it works, how to use it well, and how to avoid the traps that catch teams who build their own Collector for the first time.
1Why Would Anyone Build Their Own Collector?
Before learning the tool, it helps to understand the problem it solves.
The OpenTelemetry Collector is a program that receives telemetry such as traces, metrics and logs, optionally changes it, and sends it onward to storage and analysis systems. It does this through small building blocks called components. A receiver accepts data, a processor transforms it, and an exporter sends it away. The project offers hundreds of such components, covering an enormous range of technologies, from popular databases and cloud services to message systems and monitoring formats.
No single organisation uses all of them. A typical company needs perhaps a handful of receivers, a few processors and one or two exporters. If every Collector in the company carries hundreds of unused components, several things happen quietly. The program file is larger than it needs to be, which slows downloads and container startups. More code means more places where a security flaw can hide. More dependencies mean more updates to track. And when something goes wrong, there is more to search through.
Think of a restaurant that offers a thousand dishes versus a small café with a menu of ten. The big restaurant needs a giant kitchen, a large staff and a huge stock of ingredients, and some of those ingredients go stale unnoticed. The small café keeps a short list of fresh ingredients and knows every one by heart. OCB lets you run the small café version of the Collector.
Building your own Collector is optional. Many teams happily run an official ready-made version. OCB becomes valuable when you need a smaller binary, a tighter security footprint, a component that is not in any official version, or full control over exactly what runs in production.
2The Vocabulary You Need First
Each term below comes with what it is, why it exists, and a picture to hold in your head.
Collector
The program that receives, processes and forwards telemetry. Think of a sorting centre for observability data.
Component
One building block inside the Collector, such as a receiver or exporter. Each does one specific job.
Distribution
A particular bundle of components packaged as one runnable Collector. Like an edition of a book with certain chapters included.
OCB
The OpenTelemetry Collector Builder, a tool that creates a distribution from a list you provide.
Manifest
The short text file in which you describe your distribution: its name and the components you want. It is OCB’s shopping list.
Module
A packaged unit of Go code with an address and a version. Every component lives in a module that OCB downloads.
Go
The programming language the Collector is written in. OCB uses the Go toolchain to compile your distribution.
Binary
The final single executable file you run. It contains every component you chose, ready to start.
Core and contrib
Core holds the essential components. Contrib is a large community-maintained collection of additional ones.
Connector
A special component that acts as an exporter at the end of one pipeline and a receiver at the start of another.
Extension
A helper that adds capabilities beyond data handling, such as health checks, authentication or storage.
Provider
A component that tells the Collector where to read its configuration from, such as a file or an environment variable.
OCB is not the Collector. OCB is a factory that builds Collectors. The Collector you produce is a separate program that runs on its own, and OCB is no longer needed while it runs.
3The Ready-Made Distributions You Can Choose Instead
OCB is one of several ways to get a Collector, so let us see where it sits among the options.
The OpenTelemetry project publishes several official distributions. The core distribution contains the essential components and is deliberately small. The contrib distribution adds a very large set of extra receivers, processors, exporters and extensions, contributed by the wider community. There is also a variant tuned for Kubernetes environments, one focused on the OpenTelemetry protocol, and a specialised variant for profiling with eBPF technology. Each distribution lists its components in a manifest file in the project’s repositories.
Beyond the official ones, many vendors publish their own distributions. Cloud providers and observability companies package the Collector with the components that work best with their platforms. The OpenTelemetry project lists these as community resources but does not validate or endorse them, so teams choosing a vendor distribution should read the vendor’s own support and security statements.
| Option | What you get | Strength | Weakness |
|---|---|---|---|
| Official core distribution | A small set of essential components | Small and focused | Missing many integrations |
| Official contrib distribution | A very large set of community components | Almost everything is available at once | Large, with many components you will never use |
| Other official variants | Sets tuned for Kubernetes, the OpenTelemetry protocol, or eBPF profiling | Good starting points for those environments | Fixed choices that may not match your needs exactly |
| Vendor distribution | A bundle tuned to one vendor’s platform | Support and convenience from the vendor | Not endorsed by the project, tied to the vendor’s choices |
| Custom distribution built with OCB | Exactly the components you list | Smallest, most controlled, fully yours | You own the build, updates and security patching |
This is like buying a computer. You can buy a ready-made model, a model sold by a particular brand with its own extras, or you can assemble one yourself from chosen parts. Self-assembly gives the best fit and the tightest control, but you are also the one who repairs it.
4The Core Idea in One Page
The whole workflow is a short chain with five links.
Decide what you need
List which receivers, processors, exporters, extensions and connectors your Collector must contain, based on your real pipelines.
Describe it in a manifest
Write a short text file that names your distribution and lists each chosen component with its location and version.
Let OCB generate the code
OCB reads the manifest and produces a small Go project that wires every chosen component together.
Compile it
OCB runs the Go toolchain to download the components and compile everything into one executable file.
Run and deliver it
You run the binary like any other Collector, or package it into a container image for your platform.
Notice how little you must write. You do not write Go code for the standard case. You write a list, and OCB turns the list into a working program. That is the whole promise of the tool: turn a short, readable description into a repeatable build.
5What OCB Actually Does Behind the Scenes
Understanding the machinery removes the mystery and helps when something goes wrong.
OCB is a command-line program. When you run it with your manifest, it performs two broad jobs. First it generates source code: a small Go project containing a main program, a file that registers each component you listed, and the module files that record which versions of everything are needed. Second it compiles that project by calling the Go toolchain, which downloads the listed components from their module addresses and links everything into a single executable.
Because the output includes both the generated source and the finished binary, you can inspect exactly what was assembled. This is useful for debugging, for security reviews, and for developers who want to build their own components and test them inside a real Collector.
flowchart LR
M["Manifest file: your component list"] --> O["OCB reads and validates it"]
O --> G["Generate Go project: main, components, module files"]
G --> D["Go toolchain downloads component modules"]
D --> C["Compile and link"]
C --> B["Single custom Collector binary"]
Think of a build-your-own-furniture shop. You choose the pieces from a catalogue and fill out an order form. The shop cuts the parts, drills the holes and assembles the item for you. You never touch a saw, but you can still open it up to see how it was put together. The manifest is the order form and OCB is the workshop.
OCB can be told to generate the code without compiling it, or to compile code that already exists. Teams use the first to inspect or modify generated code, and the second to repeat builds from reviewed source.
6Getting OCB onto Your Machine
Installation is simple, but there is one prerequisite that surprises beginners.
OCB is distributed as a ready-to-run executable for the common platforms: Linux on both Intel-style and ARM processors, macOS, and Windows. On macOS it can also be installed through the popular package manager Homebrew. For other platforms you download the correct file from the project’s releases page, make it executable, and run the help command to confirm that it works.
The surprise is that OCB itself does not contain a compiler. To compile your distribution, OCB calls the Go toolchain, so Go must be installed on the machine that runs OCB. The project’s repository states which Go versions are compatible, and it is wise to check this before your first build, since a mismatch can produce confusing errors.
Install a compatible Go toolchain
Check the repository for the supported version range, then install Go using your platform’s usual method.
Download the OCB release
Choose the file that matches your operating system and processor type, and prefer a release whose version matches the Collector version you plan to build.
Make it executable and check it
Give the file permission to run, then ask it for its help text. If the help appears, installation worked.
Downloading whichever OCB release is newest without checking that it matches the component versions in your manifest. The builder version and the component versions are meant to move together, and we will see why in a later chapter.
7The Manifest: Your Shopping List
Everything OCB does is driven by one small text file, so it pays to understand its parts.
The manifest is a plain text file in a simple, human-readable format. It has a handful of sections. One section, called dist, describes the distribution itself. Several sections list components, one per kind. Two further sections cover where configuration is read from and how modules may be substituted. You only include the sections you need.
dist
Describes the distribution as a whole: its name, version, description and where the output goes. It controls how generation and compilation behave.
receivers
The doors through which telemetry enters. List only the protocols and sources you will actually accept.
processors
The steps that change data in flight, such as batching, filtering and memory protection.
exporters
The doors through which telemetry leaves, towards backends or other Collectors.
extensions
Helpers like health checks, authentication and persistent storage that sit beside the data path.
connectors
Components that link one pipeline to another, for example turning traces into metrics.
providers
Define where configuration can be read from, such as files or environment variables.
replaces
Lets you substitute one module for another, which is useful when developing or patching components.
The manifest decides which components exist in the binary. A separate runtime configuration file decides which of them are used, and how, when the Collector starts. A component that is not in the manifest cannot be used, no matter what the runtime configuration says.
8The dist Section in Detail
A few short fields in this section control how your distribution is named, versioned and written to disk.
| Field | What it controls | Practical advice |
|---|---|---|
| name | The name of the produced binary. Defaults to a generic custom name. | Choose a meaningful name such as your company and role, so that people can recognise it in process lists. |
| module | The Go module path of the generated project. | Use a path you control, following your organisation’s convention. |
| description | A human-readable summary shown in help output. | Write one clear sentence saying who owns the distribution and why it exists. |
| version | The version number of your distribution. | Version your distribution deliberately so you can tell which build is in production. |
| output_path | The folder where generated source and the binary are written. | Keep it consistent, and remember to update any container build steps that refer to it. |
| go | Which Go executable to use for compilation. | Set it when several Go versions are installed and you need a specific one. |
| debug_compilation | Whether to keep extra debugging information in the binary. | Turn it on for development and off for production, since it makes the file larger. |
The dist section is like the label on a jar of homemade jam. It says what the jam is called, which batch it came from, and what is written on the lid. You can make jam without a label, but when you have twenty jars in the cupboard, you will be very glad you wrote one.
If you change the binary name or the output folder, anything else that refers to them, such as container build files and deployment scripts, must change too. Forgetting this is a very common cause of builds that succeed but deployments that fail.
9Listing Components: Addresses and Versions
Each component in the manifest is identified by where it lives and which version you want.
Every entry under a component section points to a Go module. The entry gives the module’s address, which says where to find it, and a version, which says exactly which release to use. OCB uses these two pieces of information to download the right code. The versions are normally pinned precisely, which means every build with the same manifest produces the same result.
To find the correct address and the available versions, teams use the OpenTelemetry Registry, a searchable catalogue of components. It lists receivers, processors, exporters, extensions and connectors across the ecosystem, with links to their documentation, so you can confirm what a component does and which release matches your Collector version.
| Kind of component | Job | Typical examples in a gateway-style Collector |
|---|---|---|
| Receiver | Accept telemetry from outside | The standard OpenTelemetry protocol receiver |
| Processor | Change data in flight | Memory protection, batching, resource labelling |
| Exporter | Send data onward | The standard protocol exporter, a debugging exporter |
| Extension | Add supporting capabilities | Health checking, authentication, file-based storage |
| Connector | Join two pipelines | Span-to-metrics conversion, routing |
Rule of thumb for choosing
Every component you include is code you must build, update and trust. Include a component only if you can point to a specific pipeline that uses it. If nobody can name the pipeline, remove it from the manifest.
A pipeline that works in a test often fails in production because a small helper was left out of the manifest, such as the memory protection processor or the health check extension. Review your runtime configuration against the manifest before you build.
10Versions and Compatibility: Keep the Family Together
The most frequent source of build trouble is mixing pieces that were not designed to work together.
The Collector’s components are released on a regular schedule, and releases of the core program, the builder and the community components are numbered together as a family. A component built against one family of releases expects the core program to behave in a particular way. If you mix releases from distant families, for example a very old component inside a very new core, the pieces may disagree about how they talk to each other. The result can be a build that fails with confusing messages, or worse, a build that succeeds but misbehaves at runtime.
The sensible rule is to keep every version in the manifest, and the builder itself, within the same release family. The builder even performs a check on this by default, and it complains when versions are too far apart. Switching that check off is possible, but it removes a safety net, so it should be done only for a short-lived experiment and never for production.
Think of building a model railway. Track pieces from the same maker fit together perfectly. Track from a different era or brand may look similar but the connectors do not quite match, and trains derail at the joints. Component versions are the track pieces, and the release family is the maker.
Pick one release family
Decide which Collector release your distribution targets, and use the matching builder version.
Pin every component to that family
Use the registry to find the component release that corresponds to your chosen family, and write it down exactly.
Upgrade everything together
When you move to a newer family, change the builder, the core and all components in one deliberate step, then test.
Upgrading a single component to get a new feature, while leaving everything else behind, is the classic way to create a mismatch. If you need one newer component, plan to upgrade the whole family.
11Your First Build, Step by Step
Let us walk through the complete first build in plain language.
Sketch your pipelines on paper
Write down where telemetry comes from, what must be done to it, and where it must go. Each noun in that sentence becomes a component.
Look up each component in the registry
Find its module address and the release that matches your chosen family.
Write the manifest
Fill in the dist section, then add one entry per component. Keep the file short and commented where the reason is not obvious.
Run OCB with the manifest
Point OCB at the file. It generates the project and compiles it. The first run takes longer because many modules must be downloaded.
Look at the output folder
You will find the generated source files and your binary. Notice the binary’s name matches the one you chose.
Run it with a runtime configuration
Write the usual Collector configuration, start the binary, and send it some test telemetry to prove that the pipeline works.
For your very first build, choose just one receiver, one or two processors and one exporter. Once that works, add components one at a time. Small steps make it easy to see which addition caused a problem.
Learning to cook a new dish, you do not buy every spice on the shelf. You make the plain version first, taste it, and then add one flavour at a time. Building a Collector works best the same way.
12What OCB Leaves Behind: The Generated Project
The output folder is not a black box; each file has a clear purpose.
The main program file
The entry point that starts the Collector. It is generated and rarely edited by hand.
The components file
Registers every receiver, processor, exporter, extension and connector you listed so the Collector knows they exist.
The module files
Record which exact versions of every dependency are used. They are what makes builds repeatable.
The binary
The finished executable that you run and deploy.
Why the generated source matters
The generated project is useful in three ways. For auditing, a reviewer can read exactly which components and which versions went into a build. For development, an engineer can open the project in a normal Go editor, step through the Collector’s code with a debugger, and see how a component behaves in context. For reproducibility, keeping the manifest and the module files in version control means anyone can rebuild the same distribution later.
Treat as source of truth
- The manifest, kept in version control.
- The pinned versions recorded in the manifest.
- The build script or pipeline that runs OCB.
Treat as disposable output
- The generated source files, which can be recreated at any time.
- The binary on a developer’s laptop.
- Hand edits made directly to generated files, which will be overwritten on the next generation.
Changes made directly inside generated files are lost the next time you generate. If you need different behaviour, change the manifest, or write a proper custom component, rather than patching the output.
13Running and Verifying Your Custom Collector
A build that compiles is not yet a build that works, so verify before you trust it.
Your custom binary behaves like any other Collector, with a few built-in commands that are very helpful for verification. It can list the components that are compiled into it, which lets you confirm that everything in your manifest made it into the binary and nothing unexpected did. It can also validate a runtime configuration file without starting the pipelines, which catches typing errors and references to components that are not present.
List the compiled-in components
Compare the list with your manifest. Missing items mean the build did not include them; extra items are a surprise worth understanding.
Validate your runtime configuration
Ask the binary to check the configuration file against the components it contains. Fix any complaints before starting it for real.
Run a smoke test
Start the Collector, send a small amount of test telemetry and confirm that it appears at the destination.
Check its own health
Confirm that the health check endpoint reports a ready state and that its own internal metrics look sensible.
Turn these checks into an automatic step that must pass before a new build is allowed into production. Verification that depends on someone remembering to do it will eventually be skipped.
14Providers: Where the Configuration Comes From
A small manifest section decides how your Collector can read its runtime settings.
When a Collector starts, it needs to find its runtime configuration. Providers are the pieces that know how to fetch it from different places. One provider may read from a file on disk, another from an environment variable, another from a web address, and another from inline text on the command line. In the standard distributions a sensible set of providers is already included, but in a custom distribution you choose which ones to carry.
| Kind of source | When it is useful | Caution |
|---|---|---|
| File | Simple deployments and mounted configuration files | Make sure the file is protected and version controlled |
| Environment variable | Injecting secrets and small settings at start time | Avoid leaking values in logs or process listings |
| Web address | Central configuration that many Collectors fetch | The server becomes a dependency, and the connection should be secured |
| Inline text | Quick tests and small overrides | Hard to review and easy to mistype |
Providers are like the different ways a chef can receive an order: handwritten on a slip, spoken by a waiter, read from a screen or fetched from a central system. A kitchen only needs to support the methods it actually uses, and each additional method is one more thing that can go wrong.
If you remove a provider from your manifest and your deployment still tries to use it, the Collector will refuse to start. Review how your environment delivers configuration before choosing the providers to include.
15The Replaces Section and Local Components
Sometimes you need to use a component that is not the exact published version, and the replaces section is the escape hatch.
The replaces section lets you tell the build to use a different module, or a different version of a module, than the one that would otherwise be chosen. This is a standard feature of the Go ecosystem, and OCB passes it through. It is useful in a few situations, and risky in all of them if used carelessly.
Developing your own component
While building a new component on your laptop, you can point the build at the folder where you are working, so that every build uses your latest edits without publishing anything.
Applying a temporary fix
If an upstream component has a bug that you have already fixed in your own copy, you can use your copy until the official fix is released.
Resolving a dependency conflict
When two components require incompatible versions of the same supporting library, a replacement can force a single agreed version, though you must test carefully afterwards.
Every replacement is a quiet fork that you now own. It will not receive upstream fixes automatically, and it can hide incompatibilities. Record why each one exists, who owns it, and when it can be removed, and review the list at every upgrade.
A replacement is like fixing a car with a part from a different model. It may fit well enough to drive, and sometimes it is the only way to get on the road quickly, but you must remember it is there, because the next mechanic will not expect it.
16Building Your Own Components with OCB as a Launchpad
OCB is not only for assembling existing parts; it is also the fastest way to start writing new ones.
Sometimes the component you need does not exist, perhaps because it talks to an internal system, applies a rule that is specific to your company, or implements an unusual authentication method. You can write your own component in Go. OCB helps because it produces a complete, buildable Collector project around your component, so you can run and debug it inside the real thing from the very first day.
Generate a base distribution
Use OCB with a small manifest to produce a project that contains the standard pieces you need around your future component.
Write the component
Create your receiver, processor, exporter, extension or connector in its own module, following the project’s component conventions.
Reference it locally
Point the manifest at your component’s folder, using a replacement or a local path, so builds always pick up your latest code.
Debug it in your editor
Open the generated project in a Go editor and use ordinary breakpoints and stack traces to watch how the Collector calls your code.
Publish and pin
When it is ready, publish the component as a versioned module, replace the local path with a pinned version, and remove the temporary replacement.
Custom components are code you must maintain through every future release. Before writing one, check the registry carefully and consider whether configuring an existing component, or contributing an improvement upstream, would meet the need.
17Packaging into a Container Image
Most Collectors end up in containers, so the build usually continues beyond OCB.
On container platforms you do not copy a binary onto a server; you package it into an image. A common pattern is the multi-stage build. In the first stage, a temporary image contains Go and OCB, and it runs the builder to create the binary. In the final stage, a clean, minimal image receives only the finished binary and the runtime files it needs. The big build tools never reach production, which keeps the final image small and reduces its attack surface.
flowchart LR
subgraph S1["Stage 1: build image"]
GO["Go toolchain"] --> OC["OCB runs with manifest"] --> BIN["Binary produced"]
end
BIN --> COPY["Copy only the binary"]
subgraph S2["Stage 2: runtime image"]
COPY --> RUN["Minimal image with the Collector binary"]
end
RUN --> REG["Image registry"]
Match the architecture
Build for the processor type of the machines that will run the image, such as Intel-style or ARM. A binary for the wrong type will not start.
Keep names consistent
The binary name and output folder in the manifest must match what the image build copies. Change one, change both.
Pin base images
Use specific versions of the Go and runtime base images, so the same inputs always give the same image.
Run without extra privileges
Configure the final image to run as a normal user and include only what the Collector needs.
Building on a laptop of one processor type and deploying to servers of another. The image builds happily and then fails at start-up with an error about an invalid executable format.
18Building for Several Platforms
Real fleets are rarely uniform, so a distribution often has to run on more than one kind of machine.
An organisation may run servers with Intel-style processors, newer machines with ARM processors, developer laptops of both kinds, and perhaps some Windows hosts. A custom distribution therefore needs a build for each target. The Go toolchain supports building for a different platform than the one it runs on, and OCB works with this ability, so one pipeline can produce several binaries from one manifest.
| Target | Typical use | What to watch |
|---|---|---|
| Linux, Intel-style | Most servers and cloud virtual machines | The most common target; test here first |
| Linux, ARM | Cost-efficient cloud instances and edge devices | Verify every component works on this architecture |
| macOS | Developer laptops | Useful for local testing, rarely for production |
| Windows | Windows servers and desktops | Confirm that each component supports Windows before promising it |
Publish one image for several architectures
Container tooling can combine builds for several processor types behind a single image name, so deployments pick the right one automatically. This keeps deployment configuration simple even when the fleet is mixed.
A binary that compiles for a platform has not necessarily been proven to work there. Run at least a smoke test on each platform you publish, since some components depend on features of a particular operating system.
19Automating the Build in a Pipeline
A build that only works on one person’s laptop is a risk, so move it into an automated pipeline early.
Continuous integration systems run tasks automatically whenever something changes. For a custom Collector, a pipeline gives you repeatable builds, a visible history, and an easy place to add checks. The manifest lives in version control; every change to it triggers the pipeline; and the pipeline produces a tested, labelled image or binary ready for release.
flowchart LR
A["Change to manifest in version control"] --> B["Review and approval"]
B --> C["Pipeline starts"]
C --> D["Install pinned Go and OCB"]
D --> E["Run OCB build"]
E --> F["List components and validate configuration"]
F --> G["Smoke test and security scan"]
G --> H["Publish versioned image and records"]
Pin the tools
Use fixed versions of Go and OCB inside the pipeline, so a tool update never silently changes your output.
Build from the manifest only
The pipeline should need nothing but the manifest and pinned tools. If it needs manual steps, it is not repeatable.
Run the verification gates
Check the component list, validate sample configurations, and run a smoke test. A failing gate stops the release.
Scan and record
Scan for known vulnerabilities and produce a bill of materials listing every dependency, then store both with the artefact.
Publish with a clear version
Label each release with the distribution version and the underlying release family, so it is obvious what is running where.
Downloading hundreds of modules makes builds slow. Caching downloaded modules between pipeline runs speeds things up greatly, provided the cache is keyed to the manifest so that a changed list invalidates it.
20Choosing the Right Components
The quality of your distribution is decided by what you leave out as much as by what you put in.
A useful way to choose is to work backwards from your pipelines. Start from the runtime configuration you intend to run in production. Every receiver, processor, exporter, extension and connector named there goes into the manifest. Then add the supporting actors that keep the Collector healthy, such as memory protection and health checking. Finally, ask whether any component is there just in case. If so, leave it out; you can always rebuild when a real need arrives.
| Question to ask | If the answer is yes | If the answer is no |
|---|---|---|
| Is it named in a production pipeline? | Include it | Leave it out for now |
| Does it keep the Collector safe or observable? | Include it, even though no pipeline names it | Reconsider |
| Is it stable and maintained? | Include with confidence | Accept it only with an owner and a plan |
| Does it pull in many extra dependencies? | Weigh the cost in size and risk | Cheap to include |
| Could existing configuration do the job? | Prefer configuration to a new component | A new component may be justified |
Choosing components is like packing a first aid kit. You include what you will plausibly need and what keeps people safe, but you do not pack a surgical theatre. Every extra item adds weight, and items nobody understands are items nobody will use correctly in an emergency.
Components have different stability levels, and some are experimental. Check the stability notes in each component’s documentation before including it in a production distribution, and prefer stable ones for the critical path.
21Size, Memory and Start-Up Benefits
A smaller distribution is not only tidier; it brings measurable practical advantages.
A binary that contains hundreds of components is larger on disk than one that contains a dozen. Larger files take longer to download, longer to start in a fresh container, and use more storage in image registries and on nodes. Registered components also consume a little memory at startup, even if they are never used. In a large fleet where containers start and stop constantly, these small costs multiply.
| Aspect (illustrative) | Large all-in-one distribution | Focused custom distribution |
|---|---|---|
| Binary size | Large | A fraction of the size |
| Image download time | Slower, especially on cold nodes | Faster |
| Start-up time | Longer | Shorter |
| Dependencies to patch | Hundreds | Only those you use |
| Time to review before release | Long | Short |
The table above is intentionally qualitative, because exact numbers vary with versions, components and platforms. The way to know your own numbers is to build both and measure. Many teams find that the largest gain is not raw speed but the reduction in what needs reviewing and patching.
Before justifying a custom build on size grounds, build the standard distribution and your custom one and compare file size, image size and start time on your own infrastructure. Numbers from your own system are the only ones that matter for your decision.
Compare two backpacks for a day hike. One holds everything for a week in the mountains, and the other holds lunch, water and a jacket. Both can complete the walk, but one tires you out sooner, and when you need to find your keys you must search through a lot more.
22Security and Supply Chain Considerations
Choosing fewer components reduces risk, but owning the build also creates responsibilities.
Every component you include is code that runs inside a program that handles sensitive telemetry and often holds credentials. If a flaw is discovered in a component you do not need, but it is present in your binary, you are exposed anyway. By building only what you use, you shrink the number of places where such flaws can lurk. This is the strongest security argument for a custom distribution.
At the same time, once you build your own Collector, you become the one who must notice security fixes and ship them. Ready-made distributions are maintained by others; yours is maintained by you.
Pin and review versions
Record every component and dependency version. Review changes to the manifest like you would review changes to production code.
Scan for known vulnerabilities
Run automated scans in the pipeline and on a schedule, since new flaws are discovered in old code all the time.
Produce a bill of materials
Keep a list of everything inside each build, so you can answer quickly which releases are affected when a flaw is announced.
Protect the build itself
Limit who can change the manifest and the pipeline, and sign released artefacts so that deployment systems can verify where they came from.
Trust components deliberately
Community components vary in maintenance and review. Prefer well-maintained ones and know who owns each in your organisation.
Run with least privilege
Give the running Collector only the permissions, network access and credentials it needs.
Problem
A platform team wants a custom Collector for its smaller attack surface but has no process for tracking security fixes.
Decision
Adopt the custom distribution only together with an owner, a scheduled vulnerability scan, a bill of materials per build, and an agreed time limit for shipping fixes.
Consequence
The security benefit becomes real, at the cost of ongoing work. If the team cannot commit to that work, a maintained official distribution is the safer choice.
23The Upgrade Lifecycle
A custom distribution is a living thing: it must be rebuilt regularly or it slowly becomes a liability.
The Collector project releases new versions regularly, with new features, fixes and sometimes changes that require attention. A custom distribution does not update itself. Someone must decide when to move to a new release family, update the manifest, rebuild, test and roll out. If this is neglected, the distribution drifts further from upstream, security fixes pile up, and the eventual jump becomes large and risky.
flowchart TD
A["New release family published"] --> B["Read release notes and deprecations"]
B --> C["Update builder and all component versions together"]
C --> D["Rebuild in pipeline"]
D --> E["Run verification and smoke tests"]
E --> F["Canary rollout to a small group"]
F --> G{"Healthy?"}
G -->|"Yes"| H["Roll out to everyone"]
G -->|"No"| I["Roll back and investigate"]
Healthy habits
- Upgrade on a regular, planned schedule.
- Read release notes for removed or renamed settings.
- Upgrade the builder, core and components together.
- Roll out gradually with a prepared rollback.
Warning signs
- Running a release family that is many versions old.
- Several leftover replacements nobody can explain.
- No one who owns the manifest.
- Upgrades postponed until an emergency forces them.
Moving by one release family at a time is far easier than jumping across many. Smaller steps mean fewer changes to understand and an easier path to find the cause when something breaks.
24From Manifest to Production: The Full Flow
Let us follow one change all the way from an idea to a running Collector, noting who does what.
sequenceDiagram
participant D as Developer
participant R as Repository
participant P as Pipeline
participant G as Image registry
participant K as Cluster
D->>R: Propose manifest change
R->>R: Review and approve
R->>P: Trigger build
P->>P: Run OCB, verify, scan
P->>G: Publish versioned image
P->>K: Roll out to canary
K-->>P: Health and metrics look good
P->>K: Roll out to all
Propose
A developer wants a new exporter. They add it to the manifest and explain why in the change description.
Review
A second person checks the component’s maturity, its version family, its dependencies and its need.
Build and verify
The pipeline builds the distribution and runs its gates. A failure stops the change here.
Publish
The pipeline stores a uniquely versioned image and its supporting records.
Canary
A small group of Collectors receives the new image first, while the team watches their health and queue metrics.
Full rollout
If the canary is healthy, the rest of the fleet follows, with rollback ready.
25Governance: Who Owns the Distribution?
In an organisation, a shared Collector is a shared product, and shared products need owners and rules.
When several teams use the same custom Collector, questions appear quickly. Who decides which components are allowed? Who responds when a component has a security issue? How does a team request a new integration? Without answers, the manifest either grows without control or becomes a bottleneck that frustrates everyone. A light but clear governance model solves both problems.
A platform team owns the manifest
One team is responsible for the distribution, its pipeline and its releases. Other teams request changes through a simple, documented process.
An approved component list
The platform team maintains a short list of vetted components. Requests for components outside the list go through a quick review covering maturity, ownership, dependencies and security.
A clear versioning scheme
The distribution carries its own version, plus a note of the release family it is based on. Teams can see at a glance which version they run and what changed.
Published support expectations
The platform team states how quickly it will ship security fixes and how long older distribution versions remain supported, so that application teams can plan their own upgrades.
Governance should make safe choices easy, not make every change painful. A short review turnaround and a self-service way to test a candidate component keeps teams from working around the process.
26Design Patterns and Anti-Patterns
Patterns capture what usually works and anti-patterns what usually hurts, and both are cheaper to learn from a page than from an incident.
Patterns that work
One distribution per role
Build a small agent distribution and a separate, richer gateway distribution. Each carries only what its role needs, which keeps agents tiny and gateways capable.
Manifest as reviewed code
Keep the manifest in version control with the same review rules as production code, and build only from it.
Verification gates before release
Make component listing, configuration validation and smoke tests automatic checks that every build must pass.
Anti-patterns to avoid
Problem
The team copies a huge list of components into the manifest just in case, recreating the large distribution they were trying to avoid.
Why It’s Harmful
All the costs of a large binary return, along with the extra work of maintaining a custom build.
Correct Approach
Start from the pipelines actually in use and add components only when a real need appears.
Problem
Component versions are mixed across several release families, with the compatibility check switched off to get the build to pass.
Why It’s Harmful
The build may succeed but behave unpredictably in production, and failures are very hard to trace.
Correct Approach
Keep the builder, core and all components within one release family and upgrade them together.
Problem
A build exists only on one engineer’s laptop, produced by manual steps nobody has written down.
Why It’s Harmful
If that engineer is unavailable, nobody can rebuild or patch the Collector, and nobody can prove what is inside it.
Correct Approach
Build only in an automated pipeline from a version-controlled manifest, with pinned tools.
Problem
The distribution is built once and never rebuilt, because it works.
Why It’s Harmful
Known vulnerabilities and bugs accumulate, and the eventual forced upgrade becomes a large, risky project.
Correct Approach
Schedule regular rebuilds and upgrades, scan continuously, and treat the distribution as a product with an owner.
27Best Practices and Common Mistakes
A short checklist is often more useful than a long argument.
Best practices
- Choose components by working backwards from real pipelines.
- Keep builder, core and components in one release family.
- Pin every version and keep the manifest in version control.
- Build in an automated pipeline with pinned tools.
- Verify the component list and configuration before every release.
- Use multi-stage container builds and match target architectures.
- Scan for vulnerabilities and keep a bill of materials.
- Upgrade regularly and roll out gradually.
Common mistakes
- Including components just in case.
- Forgetting supporting components such as memory protection and health checks.
- Mixing versions from different release families.
- Leaving undocumented replacements in the manifest.
- Hand-editing generated files.
- Building for the wrong processor architecture.
- Never rebuilding after the first release.
For every component in your manifest you should be able to answer in one sentence: which pipeline uses it, who owns it, and which version is pinned.
28Real-World Scenarios
Examples help the ideas settle, so here are five situations where teams reach for OCB.
A regulated company with a strict review process
Every program in production must be reviewed. A distribution of twelve components can be reviewed in days; one of hundreds cannot. The team builds a focused distribution and keeps the bill of materials for auditors.
A company with an internal protocol
Legacy systems emit telemetry in a company-specific format. The team writes a small custom receiver, uses OCB to build it into a distribution, and retires the receiver later when the systems are modernised.
A fleet of small edge devices
Devices have little storage and memory. A minimal agent distribution with one receiver and one exporter fits comfortably, where a large distribution would not.
A platform team serving many product teams
The platform team publishes two supported distributions, one for agents and one for gateways, with a clear process for requesting additions and a published upgrade schedule.
A team experimenting with new components
An engineer wants to try an experimental processor without affecting production. A short-lived custom build lets them test it on a development cluster while production stays on the stable distribution.
29OCB Compared with the Alternatives
OCB is a good answer to some questions and a poor answer to others, so it helps to compare honestly.
| Approach | Best when | Main cost |
|---|---|---|
| Use the official contrib distribution as it is | You want the widest choice with the least effort, and size and attack surface are not concerns | A large binary with many unused components |
| Use the official core distribution | Your needs are modest and covered by essential components | Missing integrations that you may later need |
| Use a vendor distribution | You rely heavily on one vendor and want their support | Reliance on the vendor’s choices and release schedule |
| Build a custom distribution with OCB | You need a focused, controlled, possibly extended Collector | You own builds, upgrades and security patching |
| Fork and modify the Collector source directly | You need deep changes to the core itself | The highest maintenance burden, rarely justified |
Advantages of OCB
- A smaller binary and a smaller attack surface.
- Exact control over which components and versions run.
- A way to add your own components cleanly.
- Reproducible, reviewable builds from a short manifest.
- A fast start for developing and debugging components.
Disadvantages and trade-offs
- You become responsible for upgrades and security fixes.
- Version compatibility must be managed carefully.
- A build pipeline and tooling must be maintained.
- Missing components are discovered at runtime, not build time.
- Support from others is harder, since your build is unique.
If you have no concrete reason to build your own, an official distribution is a perfectly good choice. Reach for OCB when you can name the benefit, whether that is size, security review, a custom component or experimentation, and when you have someone to own the result.
30A Worked Example: Designing a Gateway Distribution
Let us design a real distribution on paper, step by step, to see how the reasoning flows.
A company runs a gateway tier that accepts telemetry from many applications using the standard OpenTelemetry protocol, protects itself from overload, adds a label saying which environment the data came from, groups items into efficient batches, and sends everything to a single backend over the same protocol. During testing, engineers also want a debugging output. Operations wants health checks for the container platform and authentication of incoming calls.
Write the pipeline in words
Receive by the standard protocol, limit memory, label the environment, batch, send by the standard protocol.
Turn each phrase into a component
One receiver, three processors, one exporter. Add a debugging exporter for testing.
Add supporting extensions
A health check extension for the platform and an authentication extension for incoming calls.
Look up versions in the registry
Choose one release family and pin every entry to it, alongside the matching builder.
Name and describe the distribution
Give it a role-based name and description, and choose the output location used by the container build.
| Component kind | Component | Reason it is included |
|---|---|---|
| Receiver | Standard protocol receiver | Accepts telemetry from applications |
| Processor | Memory limiter | Prevents crashes during overload |
| Processor | Resource labelling | Adds the environment label |
| Processor | Batch | Improves efficiency of sending |
| Exporter | Standard protocol exporter | Sends data to the backend |
| Exporter | Debug exporter | Helps engineers during testing; can be removed for production |
| Extension | Health check | Lets the platform judge readiness |
| Extension | Authentication | Verifies incoming callers |
Notice how easy it would have been to forget the memory limiter or the health check, since no data flows through them. A final review of the manifest against production needs, not just the pipelines, catches such omissions before they become outages.
31Testing a Custom Distribution
A custom build deserves the same testing discipline as any other program you ship.
| Test | What it proves | When to run it |
|---|---|---|
| Component list check | The binary contains exactly the components you intended | Every build |
| Configuration validation | Sample production configurations are accepted by the binary | Every build |
| Smoke test | Telemetry flows from input to output | Every build |
| Load test | The distribution handles realistic traffic with stable memory | Before each release family change |
| Failure test | Behaviour under backend outage and restarts matches expectations | Before major changes |
| Platform test | The binary works on each operating system and architecture you publish | Every release |
| Security scan | No known serious vulnerabilities in the dependencies | Every build and on a schedule |
| Upgrade test | Configurations still work after moving to a new release family | Before every upgrade |
Think of a bakery that makes its own bread recipe. Before selling a new batch, the baker checks the ingredients, tastes a slice, and compares it with last week’s loaf. Testing a custom distribution is the same ritual: check the contents, taste a sample, and compare with the previous release.
Store a few representative runtime configurations next to the manifest and validate them in the pipeline. This catches the situation where a component was removed from the manifest but is still used by a real configuration.
32Troubleshooting Guide
When something goes wrong, a symptom-first table gets you to the right question quickly.
| Symptom | Likely cause | What to check first |
|---|---|---|
| OCB refuses to start the compile step | Go is missing, too old or not found by the builder | Installed Go version and the configured Go executable |
| Build fails with version complaints | Builder and component versions are from different release families | Align every version in the manifest with the builder |
| Build fails while downloading modules | Network restrictions, wrong module address or a mistyped version | Module addresses, versions and network access from the build machine |
| Collector refuses to start: unknown component | A component named in runtime configuration is not in the binary | Compare the compiled-in list with the runtime configuration |
| Collector refuses to start: unknown configuration source | A provider is missing from the manifest | How the deployment delivers configuration |
| Image builds but will not start | Wrong processor architecture or wrong binary name copied | Target architecture and the name and path used by the image build |
| Behaves oddly after an upgrade | Mixed versions or a leftover replacement | Replacement entries and any partly upgraded components |
| Binary is larger than expected | Debug information included or extra components listed | Debug setting and the component list |
| Edits to generated files disappear | The files were regenerated by a new build | Move the change to the manifest or to a proper component |
A calm way to debug a failed build
Read the first error, not the last
Later messages are often consequences of the first failure. Fix the earliest one and rebuild.
Reduce the manifest
Temporarily remove half of the components and rebuild. If it succeeds, the problem is in the removed half. Repeat until you find the culprit.
Ask what changed
A new component, a new version, a new Go release or a new builder usually explains a build that worked yesterday.
33Knowing What You Run: Labels, Metrics and Support
Once a custom Collector is in production, you need to be able to answer a simple question: what exactly is running here?
With many custom builds in circulation, it quickly becomes difficult to remember which one is deployed where. The remedy is to make every build identify itself. Use the version field in the manifest to give each distribution a meaningful version, label container images with the distribution version and the underlying release family, and keep the bill of materials in a place that engineers can find easily. When someone asks whether a vulnerability affects you, the answer should take minutes, not days.
Distribution version
A number you control that increases whenever the manifest changes in a way that matters.
Release family
Which Collector release the build is based on, recorded in image labels and release notes.
Bill of materials
A complete list of components and dependencies for every released build.
Self-reported metrics
The Collector reports its own internal metrics, which should be collected and labelled with the distribution version, so you can compare behaviour between versions during a rollout.
When people ask the wider community for help with a custom build, they will be asked which components and versions it contains. A manifest and a bill of materials make that conversation short and productive.
Think of the label on a medicine bottle. It says what is inside, how much, and when it was made. Without the label, even a perfectly good medicine becomes a risk, because nobody can tell whether it is the right one.
34Just Enough Go for OCB Users
You do not need to become a Go programmer, but a few Go ideas explain nearly every message OCB shows you.
Go organises code into modules. A module is a folder of code with a name that looks like a web address and a version number such as a release label. When your distribution needs a component, Go finds that component’s module by its address, downloads the requested version, and stores it in a local cache on the build machine. The next build finds it in the cache and does not download it again. This is why the very first build is slow and later ones are quick.
Module address
The name that tells Go where a component lives. A typo here is the most common reason a download fails.
Version pinning
Go records the exact version of every module, so the same inputs always produce the same build. This is the basis of repeatability.
Dependency graph
Components depend on other modules, which depend on still others. Go works out the full list and picks compatible versions automatically.
Local cache
Downloaded modules are kept on disk. Keeping this cache between pipeline runs makes builds much faster.
Cross-compilation
Go can build a program for a different operating system or processor than the one it runs on, which is how one machine produces several binaries.
Module proxy
Go usually downloads through a proxy service that serves published modules. Organisations may run their own proxy for speed and control.
Think of a recipe that lists ingredients by the shop that sells them and the batch number. The first time you cook, you visit each shop and bring the ingredients home. The next time, they are already in your pantry. The shop address is the module address, the batch number is the version, and your pantry is the local cache.
Most build errors fall into three families: a module could not be found, a version could not be resolved, or two modules disagree about a shared dependency. Knowing which family you are in tells you whether to check the address, the version or the compatibility.
35Building in Restricted and Offline Networks
Many organisations do not let build machines reach the open internet, and OCB can still work in those places with some preparation.
OCB needs to download modules, so a build machine that cannot reach the public module services will fail on its first step. Security-conscious organisations solve this in a few well-known ways. All of them move the download from the build machine to a controlled place that your security team can inspect.
An internal module mirror
The organisation runs a mirror service that holds approved copies of public modules. Build machines are configured to download only from the mirror. New modules are added to the mirror after review, and the mirror keeps working even if the original source disappears.
A pre-populated cache
A trusted machine with internet access performs the first build and saves its module cache. That cache is then copied to the offline build machines, which can build without downloading anything.
Keeping a copy of the source
The generated project and all of its dependencies can be stored inside the organisation’s own source repository. Builds then work entirely from local files, at the cost of a large repository.
Private components
Custom components that live in private repositories need credentials during the build. Provide them through the pipeline’s secret handling, never by writing them into the manifest or the image.
| Approach | Strength | Weakness |
|---|---|---|
| Internal module mirror | Central control, fast, resilient | A service to run and keep current |
| Pre-populated cache | Simple and quick to set up | Cache can go stale and must be refreshed deliberately |
| Source stored in the repository | Completely self-contained | Large repository, harder updates |
Access tokens used to fetch private modules must never end up in the final image or in logs. Use a multi-stage build so that build-time secrets stay in the discarded build stage.
36Moving from a Ready-Made Distribution to a Custom One
Most teams do not start with OCB; they start with an official distribution and migrate when a reason appears.
The safest migration is gradual. You do not need to guess which components you use, because your existing runtime configurations already say so. Every component named in any configuration that runs in production must be in the new manifest. Collect those configurations, list the components they name, and you have the heart of your manifest.
Gather every production configuration
Include the ones for agents, gateways and special cases such as batch jobs. Missing even one leads to a surprise later.
List the components they use
Write down each receiver, processor, exporter, extension and connector, and any configuration sources used.
Add supporting components
Include the helpers that keep the Collector healthy, even if some configurations do not name them explicitly.
Build and validate every configuration
Run each real configuration through the new binary’s validation. Any complaint means a component is missing.
Run side by side
Deploy the custom build to a small, low-risk part of the fleet and compare its behaviour and metrics with the existing distribution.
Expand gradually
Move more of the fleet once the comparison looks good, keeping the old distribution available for rollback until you are confident.
During the side-by-side stage, compare data volumes, error counts and resource use between the two distributions. Identical behaviour is the goal of a migration; any difference deserves an explanation before you proceed.
Moving house is easiest when you look through every cupboard first and decide what to pack. Moving to a custom Collector is the same: the cupboards are your configurations, and the packing list is your manifest. A room you forgot to check is where the missing item will be.
37Managing Several Distributions Across a Fleet
As an organisation grows, one distribution rarely fits every role, and a small family of distributions becomes the natural answer.
Different places in a telemetry system have different needs. A small agent beside an application needs very few components and as little memory as possible. A gateway needs richer processing, authentication and durable queues. A special collector for a particular technology may need an unusual receiver that nobody else wants. Giving each role its own distribution keeps every one of them as small as it can be.
| Distribution | Role | Typical contents | Main benefit |
|---|---|---|---|
| Agent | Runs beside applications or on each host | Standard receiver, memory protection, batching, one exporter | Tiny and quick to start |
| Gateway | Shared tier receiving from agents | Standard receiver, richer processors, authentication, storage extensions, exporters | Powerful and centrally managed |
| Specialist | Serves one technology or team | The unusual receiver plus the minimum around it | Isolates unusual dependencies from everyone else |
| Development | Used by engineers for testing and debugging | Extra debugging components and debug symbols | Never shipped to production |
flowchart TD
M["One repository with several manifests"] --> P["Shared build pipeline"]
P --> A["Agent distribution"]
P --> G["Gateway distribution"]
P --> S["Specialist distribution"]
P --> D["Development distribution"]
A --> F1["Agents on every host"]
G --> F2["Gateway tier"]
S --> F3["Special use"]
Each distribution is another thing to build, scan, test and upgrade. Keep the family small, share one pipeline and one release family across all of them, and merge distributions whose contents are almost identical.
38Build Options That Affect the Result
A handful of switches change what the produced binary looks like, and it helps to know what each one trades.
Debug information
Including debugging information makes the binary larger but allows engineers to step through code with a debugger. Use it for development builds only.
Generate only
Producing the source without compiling lets you inspect, review or modify the project, then build it later under controlled conditions.
Compile only
Building from already generated and reviewed source ensures that the reviewed code, not a fresh generation, is what ships.
Strict version checking
By default the builder checks that its version fits the components. Turning the check off removes a safety net and should be reserved for short experiments.
Verbose output
More detailed messages help when a build fails, at the cost of noisier logs. Turn it on while diagnosing a problem.
Target platform
Choosing the operating system and processor type of the result lets one build machine serve the whole fleet.
Good defaults for production
- Debug information off to keep the binary small.
- Strict version checking left on.
- Builds produced only by the pipeline.
- Reviewed, generated source compiled in a controlled step where review is required.
Risky shortcuts
- Disabling version checks to get a build to pass.
- Shipping a development build with debug information.
- Building on a laptop for a different architecture without testing.
- Regenerating code during release, so the shipped code is not the reviewed code.
Option names and behaviour can change between builder releases. Run the builder’s help output for the exact version you use before copying options into your pipeline.
39Documenting and Onboarding Your Team
A custom distribution is only as useful as the number of people who understand how to use and change it.
A distribution that only one person understands is a risk. Good documentation turns it into a shared tool. The goal is not long documents; it is a few short, honest pages that answer the questions new people ask most often, and that are updated whenever the distribution changes.
A readme that explains the why
Say what the distribution is for, who owns it, and which release family it is based on. A newcomer should understand its purpose in two minutes.
A component register
List every component with its reason for inclusion, its owner and its stability level. This also makes cleanup easy during reviews.
A how-to for common changes
Explain step by step how to add a component, test it and release it, so contributors can help without asking each time.
A change log
Record each release, what changed and why, so that anyone investigating a behaviour change can find its cause quickly.
Decision records for unusual choices
Write a short note for every replacement, disabled check or unusual component, explaining the reason and when it can be revisited.
Think of the instruction booklet that comes with a piece of furniture. Nobody wants a novel, but everyone is grateful for clear pictures, a parts list and a note about the tricky screw. A short, good booklet saves the whole family from guesswork.
Store the documentation in the same repository as the manifest and review it in the same change. Documents that live elsewhere drift out of date quickly.
40How Components Are Wired Together Inside the Binary
A little knowledge of the wiring explains why a missing component stops the Collector at start-up instead of failing quietly later.
Every component in the Collector is created by a small piece of code called a factory. A factory knows the component’s type name, such as the name you write in a runtime configuration, and it knows how to create an instance of the component when the Collector needs it. The generated components file made by OCB collects the factories of every component you listed into registries, one registry for each kind: receivers, processors, exporters, extensions and connectors.
When the Collector starts, it reads the runtime configuration and looks up each named component in the matching registry. If a name is found, the factory builds the component. If a name is not found, the Collector stops immediately with an error saying that the component type is unknown. This early, loud failure is deliberate. It is much better to learn about a missing component at start-up than to discover hours later that a pipeline has been silently doing nothing.
flowchart LR
M["Manifest: list of components"] --> G["Generated components file"]
G --> R["Registries: receivers, processors, exporters, extensions, connectors"]
C["Runtime configuration names a component"] --> L{"Is it in the registry?"}
R --> L
L -->|"Yes"| F["Factory creates the component"]
L -->|"No"| E["Collector stops: unknown component"]
Imagine a theatre with a list of actors who are actually in the building. The director’s script names actors for each scene. If the script names an actor who is not on the list, the show cannot start, and the stage manager says so at once. The manifest is the list of actors in the building, and the runtime configuration is the script.
Validating your runtime configuration against the finished binary is a precise test of whether your manifest is complete. Because lookup happens at start-up, the validation step in your pipeline will catch almost every missing-component mistake before production does.
Validation proves that components exist and that their settings parse. It does not prove that a pipeline behaves well under load or that a destination is reachable. Keep smoke tests and load tests in your pipeline as well.
41Deciding Whether OCB Is Worth It for You
A short scoring exercise can turn a vague feeling into a clear decision.
Because a custom distribution brings ongoing work, it deserves a deliberate decision. The table below lists common reasons and the questions that test whether each reason is real. Score each row honestly with a simple yes or no. A single strong yes, with an owner ready to carry the maintenance, is often enough. Several weak yes answers rarely are.
| Reason | Test question | Strength of the reason |
|---|---|---|
| Smaller attack surface or easier security review | Does your organisation require reviewing everything that runs in production? | Strong if the answer is yes |
| Component not available in any official distribution | Have you searched the registry and confirmed that no existing component can do the job? | Strong if confirmed |
| Smaller binary or faster start | Have you measured the difference on your own infrastructure and does it matter? | Strong only with measured benefit |
| Resource-constrained devices | Do your devices have strict storage or memory limits? | Strong if yes |
| Control over versions and timing | Do you need to move to new releases on your own schedule? | Moderate |
| It seems more professional | Is there any measurable benefit at all? | Weak, avoid |
Name the concrete benefit
Write one sentence stating what will be better, such as the review time or the image size, and by roughly how much.
Name the owner
Identify the person or team who will upgrade, scan and fix the distribution for as long as it is in use.
Estimate the ongoing effort
Think about regular upgrades, security responses and support questions, and judge whether the benefit is worth that effort.
Try a small pilot
Build one distribution for one role and measure the real result before committing the whole organisation.
42Choosing Community Components Wisely
Many of the components you will want come from the wider community, and their quality and upkeep vary.
The core Collector is maintained by the project’s core team, but the large collection of community components is contributed and maintained by many people and companies. Each has its own pace of development and its own stability level, which the documentation states. When you build a custom distribution, you are choosing which of those components your organisation will rely on, so a little due diligence goes a long way.
Stability level
Read the component’s documented stability. Stable components change slowly and carefully; experimental ones may change settings or behaviour between releases.
Maintenance activity
Look at how recently the component received fixes and how quickly reported problems are answered. An abandoned component becomes your problem.
Who owns it upstream
Components usually list their maintainers. Knowing who they are helps you judge reliability and know whom to ask or help.
Dependencies it brings
Some components pull in large supporting libraries. Check whether the extra weight and risk are justified by the benefit.
Platform support
Confirm that the component works on every operating system and processor type you publish.
Configuration surface
A component with a huge number of settings is harder to review and to use safely. Prefer simpler ones when they meet your need.
Problem
Teams request new community components frequently, and some are experimental or poorly maintained.
Decision
Require each new component to pass a short checklist covering stability, maintenance, ownership, dependencies and platform support, and assign an internal owner who will watch upstream changes.
Consequence
The distribution stays predictable and upgrades stay manageable, at the cost of a small delay when adding a component. Urgent experiments can use a separate development build instead of the shared production one.
If you depend on a community component, helping to fix its bugs upstream is often cheaper than carrying your own patched copy through every future upgrade.
43A One-Page Quick Reference
When you only have a minute, this table recaps the whole journey from idea to running Collector.
| Stage | What you do | What to check | What can go wrong |
|---|---|---|---|
| Decide | Name the benefit and the owner | Is there a measurable reason and someone to maintain it? | Building a custom Collector for no clear reason |
| Choose components | List components from real pipelines plus supporting helpers | Each has a pipeline, an owner and a stability level | Including things just in case, or forgetting helpers |
| Write the manifest | Fill in the dist section and component entries with pinned versions | Every version is in one release family | Mixed versions and mistyped module addresses |
| Build | Run OCB with pinned tools in a pipeline | The build succeeds from the manifest alone | Missing Go, blocked network, wrong versions |
| Verify | List components, validate configurations, run a smoke test | The compiled-in list matches the manifest | A missing component or provider found too late |
| Package | Use a multi-stage container build for each target platform | The image starts on the real target architecture | Wrong architecture or mismatched binary name |
| Secure | Scan, produce a bill of materials, sign the artefacts | No serious known vulnerabilities and a record of contents | Unscanned dependencies and unknown contents |
| Release | Canary first, then gradual rollout with rollback ready | Queue, error and resource metrics look normal | Changing the whole fleet at once |
| Maintain | Rebuild and upgrade on a schedule | The distribution stays close to a supported release family | Forgotten builds that slowly become liabilities |
Print it or pin it next to your pipeline definition. Each time you change the distribution, walk down the rows and confirm that every stage still has an answer in your pipeline, your documentation or your team’s habits.
Pilots follow a short checklist before every flight, even though they have flown hundreds of times. The checklist does not make them better pilots; it makes sure that a tired or busy moment never lets an important step slip through. This table plays the same role for your Collector builds.
44Maturity and Ecosystem
A tutorial should be honest about the moving parts, so here is how to stay safe on shifting ground.
The Collector, its builder and its components are actively developed. Names of settings, supported Go versions, installation methods and even the list of official distributions can change between releases. The ideas in this tutorial, choosing components deliberately, keeping versions together, building in a pipeline, verifying before release, and owning upgrades, are lasting. Specific commands and flags are not, so confirm them against the documentation for the exact version you use.
Builder documentation
Describes installation, the manifest sections, the dist fields, building, and container packaging.
Distributions page
Lists the official distributions and the community-listed vendor distributions, with a note that vendors are not endorsed by the project.
OpenTelemetry Registry
A searchable list of components with their module addresses and documentation, used when writing a manifest.
Custom Collector guide
Explains the workflow from installation to a running custom distribution, and how to develop components.
Follow the project’s release notes, and treat each upgrade as a small project with its own testing. Component stability levels change over time, so re-check them whenever you add or upgrade a component.
45Frequently Asked Questions
It is a command-line tool that reads a short manifest listing the components you want, generates a small Go project around them, and compiles a custom Collector containing exactly those components.
Not for the standard case of assembling existing components, because you only write a manifest. You need Go installed, since OCB uses it to compile, and Go knowledge only becomes necessary when you write your own components.
You can, and many teams do. A custom distribution is attractive when you want a smaller binary, a smaller attack surface, easier reviews, or a component that is not in any official distribution.
A dist section describing the distribution, lists of receivers, processors, exporters, extensions and connectors with their module addresses and versions, and optionally providers and replacements.
The manifest decides which components exist inside the binary. The runtime configuration decides which of them are used and how when the Collector starts. A component missing from the manifest cannot be used.
Components are built against a particular release family of the core. Mixing families can cause build failures or subtle runtime misbehaviour. Keep the builder, core and components together.
Yes. Write it as a Go module, reference it in the manifest using a local path or replacement during development, and replace that with a pinned published version when it is ready.
Use a multi-stage build: the first stage has Go and OCB and produces the binary, and the final stage is a minimal image that receives only the binary. Match the processor architecture and keep names consistent.
It can be, because fewer components mean fewer places for flaws. But you must also track and ship security fixes yourself, so the benefit only holds if someone owns that work.
On a regular schedule tied to upstream releases, and immediately when a serious security issue affects a component you use. Small, frequent upgrades are easier than large, rare ones.
They let you substitute a different module or version for a component. They are useful for development and urgent fixes, but each one is a fork you own, so record why it exists and remove it when possible.
Ask the binary to list its compiled-in components and compare them with the manifest, validate sample configurations against it, run a smoke test, and keep a bill of materials with each release.
46Summary and Key Takeaways
We began with a suitcase packed with everything and a small bag packed with only what the trip needs. The OpenTelemetry Collector Builder lets you choose the small bag. You list the receivers, processors, exporters, extensions and connectors you need in a manifest, pin their versions, and let OCB generate and compile a custom Collector. In return you get a smaller binary, a smaller attack surface, easier reviews, and the freedom to add your own components. In exchange you take on the work of keeping versions aligned, building in a pipeline, verifying every release, scanning for vulnerabilities and upgrading regularly. Done with discipline, a custom distribution is a precise, reviewable tool. Done carelessly, it becomes an unmaintained fork. The difference is not in the tool but in the habits around it.
Key Takeaways
- OCB is a factory, not a Collector — it turns a manifest into a custom Collector binary and is not needed once the binary exists.
- The manifest decides what exists — runtime configuration only chooses among components that were compiled in.
- Choose by working backwards — include what real pipelines use, plus supporting components like memory protection and health checks.
- Keep the family together — builder, core and components should share one release family, and upgrade together.
- Automate and verify — build only in a pipeline from a version-controlled manifest, and gate releases on component listing, configuration validation and smoke tests.
- Own the security work — pin versions, scan, keep a bill of materials and ship fixes on schedule, or prefer an official distribution.
- Treat replacements as debt — every substitution is a fork you own, so document and remove it when possible.