Custom OpenTelemetry Collectors: Build, Run, and Manage at Scale
A while back I decided to start writing a “human-only-written” tutorial series about OpenTelemetry...

I tried thinking back to when the last time I read an actual tutorial that did not include a bunch of em (—) dashes, semicolons, normal dashes, and an unnervingly large quantity of the phrases like “XYZ-thing Alert 🚨” and “Exciting News!”.
Well, hold on to your suspenders folks, here we go again. Part 2 is up and it’s a controversial one. 👇
Have you tried building your own, custom, OpenTelemetry Collector distribution? Did you like it? 😂
I bet you’re NOT smiling. Let alone laughing out loud at that statement like I am right now! I tried, and boy did I have a hard time. Because, believe it or not, I do not know Go... at all.
I do have a nice solution to the current norm of building custom OpenTelemetry Collectors, if you have the patience to stick around and read for the next 4 minutes. I’ll do my best to be respectful of your time and cut it down to the bare bones you need to be successful yourself.
As a normal human I find this hard…
There are a few missing steps in the existing resources and docs around using the OpenTelemetry Collector Builder (OCB). I felt like stumbling through a dark forest and barely making it out the other side. The OCB is an amazing tool for Go developers. That’s the kicker though. A lot of us are not seasoned engineers, let alone experienced Go developers.
That’s why I wanted to write this tutorial. I’ll show you a hands-on guide with the open-source OpenTelemetry Distribution Builder (ODB) from Bindplane. You’ll learn how to build a custom, OpAMP-enabled collector using a manifest.yaml
file and GitHub Actions.
Building custom OpenTelemetry collectors is a real need
Custom OpenTelemetry Collectors are no longer a niche thing. As more devs run collectors in intricate Kubernetes environments, or in containers in general, even in the edge, trimming down the binary is becoming standard practice.
Why build a custom collector?
The upstream OpenTelemetry Collector Contrib ships with a lot of components. That’s great for getting started, but in production you don’t need all of them. Simply put, more components equals bigger binaries and more attack surface.
A custom built collector solves that. You define exactly what is needed:
- Only receivers, processors, exporters, and extensions you use
- Minimal footprint
- No unnecessary dependencies
The OpenTelemetry Distribution Builder (ODB)
ODB is Bindplane’s open-source builder for creating custom collectors.
You feed it a manifest.yaml
and it gives you binaries and packages for every platform you need.
What you get:
- Multi-platform builds: Linux, Windows, macOS, AMD64, ARM64
- Multiple formats:
.tar.gz
,.zip
,.deb
,.rpm
- No Go coding, no manual dependency resolution
- OpAMP support (Bindplane-compatible out-of-the-box)
Step 1 — Create a GitHub repo
Start by creating a blank GitHub repo to store the manifest.yaml
and run GitHub Action Workflows.

Next, create a new repo in your local env.
1echo "# otel-distro-builder-github-action" >> README.md
2git init
3git add README.md
4git commit -m "first commit"
5git branch -M main
6git remote add origin git@github.com:<YOUR_ACCOUNT_NAME>/otel-distro-builder-github-action.git
7git push -u origin main

The repo is now ready to add a manifest.yaml
.

Step 2 — Write a manifest.yaml
The manifest.yaml
is where you define what goes in your collector.
Here’s a suggested example that I’ve vetted with my colleagues at Bindplane that contribute to the OpenTelemetry project. It’s minimal, but still includes quality-of-life modules like OpAMP support and common processors.
1dist:
2 module: github.com/<YOUR-USERNAME>/my-custom-opentelemetry-distro
3 name: my-custom-opentelemetry-distro
4 description: Custom-built OpenTelemetry Collector.
5 output_path: ./_build
6 version: v0.0.1
7conf_resolver:
8 default_uri_scheme: "env"
9receivers:
10 - gomod: go.opentelemetry.io/collector/receiver/nopreceiver v0.128.0
11 - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.128.0
12 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.128.0
13 - gomod: github.com/observiq/bindplane-otel-collector/receiver/telemetrygeneratorreceiver v1.79.0
14exporters:
15 - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.128.0
16 - gomod: go.opentelemetry.io/collector/exporter/nopexporter v0.128.0
17 - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.128.0
18 - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.128.0
19 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter v0.128.0
20 - gomod: github.com/observiq/bindplane-otel-collector/exporter/googlecloudstorageexporter v1.79.0
21extensions:
22 - gomod: go.opentelemetry.io/collector/extension/zpagesextension v0.128.0
23 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/ackextension v0.128.0
24 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/asapauthextension v0.128.0
25 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/awsproxy v0.128.0
26 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension v0.128.0
27 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/bearertokenauthextension v0.128.0
28 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/jaegerencodingextension v0.128.0
29 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/otlpencodingextension v0.128.0
30 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/zipkinencodingextension v0.128.0
31 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/headerssetterextension v0.128.0
32 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckextension v0.128.0
33 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/httpforwarderextension v0.128.0
34 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/jaegerremotesampling v0.128.0
35 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/oauth2clientauthextension v0.128.0
36 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/dockerobserver v0.128.0
37 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/ecsobserver v0.128.0
38 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/ecstaskobserver v0.128.0
39 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/hostobserver v0.128.0
40 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/observer/k8sobserver v0.128.0
41 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/oidcauthextension v0.128.0
42 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/opampextension v0.128.0
43 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/pprofextension v0.128.0
44 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/sigv4authextension v0.128.0
45 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/filestorage v0.128.0
46 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/storage/dbstorage v0.128.0
47 - gomod: github.com/observiq/bindplane-otel-collector/extension/bindplaneextension v1.79.0
48processors:
49 - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.128.0
50 - gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.128.0
51 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.128.0
52 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/cumulativetodeltaprocessor v0.128.0
53 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/deltatorateprocessor v0.128.0
54 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/filterprocessor v0.128.0
55 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/groupbyattrsprocessor v0.128.0
56 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/groupbytraceprocessor v0.128.0
57 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sattributesprocessor v0.128.0
58 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/logdedupprocessor v0.128.0
59 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricsgenerationprocessor v0.128.0
60 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricstransformprocessor v0.128.0
61 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/probabilisticsamplerprocessor v0.128.0
62 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/redactionprocessor v0.128.0
63 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/remotetapprocessor v0.128.0
64 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourcedetectionprocessor v0.128.0
65 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor v0.128.0
66 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/routingprocessor v0.128.0
67 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/spanprocessor v0.128.0
68 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/sumologicprocessor v0.128.0
69 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor v0.128.0
70 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor v0.128.0
71 - gomod: github.com/observiq/bindplane-otel-collector/processor/datapointcountprocessor v1.79.0
72 - gomod: github.com/observiq/bindplane-otel-collector/processor/logcountprocessor v1.79.0
73 - gomod: github.com/observiq/bindplane-otel-collector/processor/lookupprocessor v1.79.0
74 - gomod: github.com/observiq/bindplane-otel-collector/processor/maskprocessor v1.79.0
75 - gomod: github.com/observiq/bindplane-otel-collector/processor/metricextractprocessor v1.79.0
76 - gomod: github.com/observiq/bindplane-otel-collector/processor/metricstatsprocessor v1.79.0
77 - gomod: github.com/observiq/bindplane-otel-collector/processor/removeemptyvaluesprocessor v1.79.0
78 - gomod: github.com/observiq/bindplane-otel-collector/processor/resourceattributetransposerprocessor v1.79.0
79 - gomod: github.com/observiq/bindplane-otel-collector/processor/samplingprocessor v1.79.0
80 - gomod: github.com/observiq/bindplane-otel-collector/processor/snapshotprocessor v1.79.0
81 - gomod: github.com/observiq/bindplane-otel-collector/processor/spancountprocessor v1.79.0
82 - gomod: github.com/observiq/bindplane-otel-collector/processor/throughputmeasurementprocessor v1.79.0
83 - gomod: github.com/observiq/bindplane-otel-collector/processor/topologyprocessor v1.79.0
84 - gomod: github.com/observiq/bindplane-otel-collector/processor/unrollprocessor v1.79.0
85connectors:
86 - gomod: go.opentelemetry.io/collector/connector/forwardconnector v0.128.0
87 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/countconnector v0.128.0
88 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/datadogconnector v0.128.0
89 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/exceptionsconnector v0.128.0
90 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/failoverconnector v0.128.0
91 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/grafanacloudconnector v0.128.0
92 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/roundrobinconnector v0.128.0
93 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/routingconnector v0.128.0
94 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/servicegraphconnector v0.128.0
95 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.128.0
96providers:
97 - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.34.0
98 - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.34.0
99 - gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.34.0
100 - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.34.0
101 - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.34.0
102# When adding a replace, add a comment before it to document why it's needed and when it can be removed
103replaces:
104 # See https://github.com/google/gnostic/issues/262
105 - github.com/googleapis/gnostic v0.5.6 => github.com/googleapis/gnostic v0.5.5
106 # See https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/12322#issuecomment-1185029670
107 - github.com/docker/go-connections v0.4.1-0.20210727194412-58542c764a11 => github.com/docker/go-connections v0.4.0
108 # see https://github.com/mattn/go-ieproxy/issues/45
109 - github.com/mattn/go-ieproxy => github.com/mattn/go-ieproxy v0.0.1
110 # see https://github.com/openshift/api/pull/1515
111 - github.com/openshift/api => github.com/openshift/api v0.0.0-20230726162818-81f778f3b3ec
112 - github.com/observiq/bindplane-otel-collector/internal/version => github.com/observiq/bindplane-otel-collector/internal/version v0.0.0-20250306153219-6fe3f849c29f
💡 The opampextension
is the key — it’s what lets Bindplane discover and manage your collector.
Step 3 — Automate the build with GitHub Actions
Use the OpenTelemetry Distribution Builder GitHub Action to do the heavy lifting.
Here’s a .github/workflows/multi.yaml
you can drop in:
1name: Matrixed OpenTelemetry Distribution Build
2
3on:
4 push:
5 tags:
6 - "v*" # Runs when a version tag is pushed (e.g., v1.0.0)
7 workflow_dispatch: # Enables manual triggering from the GitHub UI
8
9permissions:
10 contents: write # This is required for creating/modifying releases
11
12jobs:
13 build:
14 # Configure build matrix to run multiple platform builds in parallel
15 strategy:
16 matrix:
17 # Define the platforms we want to build for
18 platform: [linux/amd64, linux/arm64, darwin/arm64, windows/amd64]
19 # Map platform identifiers to simpler names for artifact handling
20 include:
21 - platform: linux/amd64
22 os: linux
23 arch: amd64
24 artifact_name: linux-amd64
25 - platform: linux/arm64
26 os: linux
27 arch: arm64
28 artifact_name: linux-arm64
29 - platform: darwin/arm64
30 os: darwin
31 arch: arm64
32 artifact_name: darwin-arm64
33
34 - platform: windows/amd64
35 os: windows
36 arch: amd64
37 artifact_name: windows-amd64
38 runs-on: ubuntu-latest
39 steps:
40 - uses: actions/checkout@v4
41
42 # Build the OpenTelemetry distribution for each platform
43 - name: Build and Package
44 uses: observiq/otel-distro-builder@main
45 with:
46 os: ${{ matrix.os }}
47 arch: ${{ matrix.arch }}
48
49 # Upload platform-specific artifacts with a unique name
50 # These artifacts are available for download in the GitHub Actions UI
51 - name: Upload Artifacts
52 uses: actions/upload-artifact@v4
53 with:
54 name: distribution-artifacts-${{ matrix.artifact_name }}
55 path: |
56 ${{ startsWith(matrix.platform, 'linux') && format('{0}/artifacts/*.deb', github.workspace) || '' }}
57 ${{ startsWith(matrix.platform, 'linux') && format('{0}/artifacts/*.rpm', github.workspace) || '' }}
58 ${{ startsWith(matrix.platform, 'linux') && format('{0}/artifacts/*.apk', github.workspace) || '' }}
59 ${{ startsWith(matrix.platform, 'windows') && format('{0}/artifacts/*.zip', github.workspace) || '' }}
60 ${{ (startsWith(matrix.platform, 'linux') || startsWith(matrix.platform, 'darwin')) && format('{0}/artifacts/*.tar.gz', github.workspace) || '' }}
61 ${{ format('{0}/artifacts/*.sbom.json', github.workspace) || '' }}
62 ${{ format('{0}/artifacts/*_checksums.txt', github.workspace) || '' }}
63 retention-days: 5 # Artifacts are kept for 5 days then automatically deleted
64
65 # Create a single release containing all platform artifacts
66 release:
67 needs: build # Wait for all platform builds to complete
68 runs-on: ubuntu-latest
69 permissions:
70 contents: write # Required permission for creating releases
71 steps:
72 # Download all platform-specific artifacts into a single directory
73 - name: Download All Artifacts
74 uses: actions/download-artifact@v4
75 with:
76 path: all-artifacts
77 pattern: distribution-artifacts-* # Match all our platform-specific artifacts
78 merge-multiple: true # Combine all artifacts into a single directory
79
80 # Create a GitHub Release and attach all platform artifacts
81 # This makes all platform builds available for download from the Releases page
82 - name: Create Release
83 uses: softprops/action-gh-release@v2
84 with:
85 files: all-artifacts/**/*
Every new version release will:
- Build your custom collector for all platforms
- Package it into .tar.gz, .zip, .deb, and .rpm
- Store them as GitHub Actions artifacts
You should have two files created and ready to add to Git.
1git status
2
3[Output]
4On branch main
5Your branch is up to date with 'origin/main'.
6
7Untracked files:
8 (use "git add <file>..." to include in what will be committed)
9 .github/
10 manifest.yaml
Commit these changes and push them to your repo.
1git add .github manifest.yaml
2git commit -m "add a manifest and workflow"
3git push origin main

Create a new release. Make sure to use the same release tag as you specified in your manifest.yaml
. In the sample manifest.yaml
above I used v0.0.1
which means I need to set the same tag in the release.

Once the release is created, you’ll see it’s initially empty.

Opening the Actions
will show the build running.

Give it about 5 minutes to complete. Go get a coffee. ☕

Once the builds are done, you’ll see artifacts saved and added to the release.

Step 4 — Download and run your collector
Let me show you how to run your custom collector in a Linux VM. Grab an artifact from the Release and extract it.
1wget https://github.com/adnanrahic/otel-distro-builder-github-action/releases/download/v0.0.1/my-custom-opentelemetry-distro_otelcol_v0.0.1_linux_amd64.tar.gz
2
3tar -xvzf my-custom-opentelemetry-distro_otelcol_v0.0.1_linux_amd64.tar.gz
You’ll also get a skeleton collector_config.yaml
for the custom collector bundled in the tar as well.
1ls -l
2
3[Condensed Output]
4-rw-r--r-- collector_config.yaml
5-rwxr-xr-x my-custom-opentelemetry-distro
6-rw-r--r-- my-custom-opentelemetry-distro_otelcol_v0.0.1_linux_amd64.tar.gz
7drwxr-xr-x service
Let’s edit it slightly, and also add Bindplane’s OpAMP configuration by following this guide. Paste this into the config file.
1# To limit exposure to denial of service attacks, change the host in endpoints below from 0.0.0.0 to a specific network interface.
2# See https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/security-best-practices.md#safeguards-against-denial-of-service-attacks
3
4extensions:
5 health_check:
6 pprof:
7 endpoint: 0.0.0.0:1777
8 zpages:
9 endpoint: 0.0.0.0:55679
10
11 # Add an OpAMP connection to Bindplane.
12 # Use the credentials from your account, and
13 # follow the guide from the screenshot below.
14 opamp:
15 instance_uid: 01K42T4MGFFDZMXBY7C5C2APX9 # Generated ULID
16 capabilities:
17 reports_effective_config: true
18 server:
19 ws:
20 # Bindplane Cloud OpAMP Endpoint
21 endpoint: wss://app.bindplane.com/v1/opamp
22 headers:
23 Authorization: Secret-Key <YOUR_SECRET_KEY>
24 X-Bindplane-Labels: <YOUR_LABEL=YOUR_VALUE>
25 tls:
26 insecure: false
27
28receivers:
29 telemetrygeneratorreceiver/logs:
30 generators:
31 - additional_config:
32 body: 'foo: bar'
33 severity: 9
34 type: logs
35 payloads_per_second: 1
36
37 otlp:
38 protocols:
39 grpc:
40 endpoint: 0.0.0.0:4317
41 http:
42 endpoint: 0.0.0.0:4318
43
44processors:
45 batch:
46
47exporters:
48 debug:
49 verbosity: detailed
50 nop: null
51
52service:
53
54 pipelines:
55
56 traces:
57 receivers: [otlp]
58 processors: [batch]
59 exporters: [debug, nop]
60
61 metrics:
62 receivers: [otlp]
63 processors: [batch]
64 exporters: [debug, nop]
65
66 logs:
67 receivers: [telemetrygeneratorreceiver/logs, otlp]
68 processors: [batch]
69 exporters: [debug, nop]
70
71 extensions: [health_check, pprof, zpages, opamp]
Note: If you’re on the Growth or Enterprise plans of Bindplane, and want to connect the collector Bindplane, use the secret key after the-s
and the labels after the-k
. The collector will work as expected with or without connecting to Bindplane. But, you will not get the management capabilities and benefits of OpAMP.

Now, go ahead and run the collector binary.
1./my-custom-opentelemetry-distro --config collector_config.yaml
You’ll see logs like this show as the terminal output confirming the telemetrygeneratorreceiver
is creating some dummy logs to validate your config is working.
12025-09-02T08:44:44.255Z info service@v0.128.0/service.go:282 Everything is ready. Begin running and processing data. {"resource": {"service.instance.id": "8c4d008a-700d-49d6-b6ed-41cd1e03cf18", "service.name": "my-custom-opentelemetry-distro", "service.version": "v0.0.1"}}
2
32025-09-02T08:44:44.454Z info Logs {"resource": {"service.instance.id": "8c4d008a-700d-49d6-b6ed-41cd1e03cf18", "service.name": "my-custom-opentelemetry-distro", "service.version": "v0.0.1"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "logs", "resource logs": 1, "log records": 1}
4
52025-09-02T08:44:44.455Z info ResourceLog #0
6Resource SchemaURL:
7ScopeLogs #0
8ScopeLogs SchemaURL:
9InstrumentationScope
10LogRecord #0
11ObservedTimestamp: 2025-09-02 08:44:44.253813518 +0000 UTC
12Timestamp: 2025-09-02 08:44:44.253813518 +0000 UTC
13SeverityText:
14SeverityNumber: Info(9)
15Body: Str(foo: bar)
16Trace ID:
17Span ID:
18Flags: 0
Within seconds, your custom collector will appear in Bindplane’s Agents list.

You can open the collector config as well.

Bindplane is picking up the collector metadata and the config you added as well. The OpAMP Extension currently doesn't support remote configuration, which means you cannot modify the Collector configuration through the Bindplane UI. You can still view the current Collector configuration as YAML on the Collector page, but the "Choose Another Configuration" button will not be available.
Let me walk you through adding your custom collector to Bindplane as an Agent Type and enabling remote configurations.
Step 5 — Remotely manage your custom collector with OpAMP
You can enable remote collector management by adding your custom collector as an Agent Type in Bindplane as outlined in this docs guide. Let me walk you through it step-by-step. 🚶♀️
1. Install the Bindplane CLI
The Bindplane CLI lets you manage Bindplane resources including Agent Types. Follow the OS-specific installation steps here.
2. Create an API Key & set a default
profile
Create an API Key to access resources in Bindplane with the CLI. Follow the steps here.
3. Create an Agent Type in Bindplane
In Bindplane, an Agent Type represents an OpenTelemetry Collector Distribution. For example, the BDOT v1 and v2 collectors are both Agent Types.
1apiVersion: bindplane.observiq.com/v1
2kind: AgentType
3metadata:
4 name: my-custom-opentelemetry-distro
5 displayName: My Custom OpenTelemetry Distro
6 description: My custom OpenTelemetry collector distro.
7spec:
8 repositoryLink: https://github.com/<YOUR_GITHUB_USERNAME>/<YOUR_REPO_NAME>
9 platformArchSet:
10 - platform: darwin
11 arch: arm64
12 - platform: linux
13 arch: amd64
14 - platform: linux
15 arch: arm64
16 - platform: windows
17 arch: amd64
This is where you need to be careful. The repositoryLink
needs to match the link of the repo where you ran the GitHub action. In my example it was:
1https://github.com/adnanrahic/otel-distro-builder-github-action

The metadata.name
value also needs to match the value of dist.name
in your manifest.yaml
.
Apply the custom Agent Type.
1bindplane apply -f /path/to/agent/type/file.yaml
Finally, sync the Agent Type to load it into Bindplane.
1bindplane sync agent-versions --agent-type my-custom-opentelemetry-distro --version v0.0.1
Note that the version matches the release.
5. Install your custom collector from the Bindplane UI
Now since you’ve added a custom Agent Type and synced a version, you can choose to install it from the Bindplane UI.

Since you built it for Mac, Windows, and Linux, you’ll see all three options when selecting platform.

I want to install it in my Linux VM, so I’ll select Linux and click next.

I’ll get this generic one-line install command. Running this in my VM will start my custom collector and hook it up to Bindplane via OpAMP.
1sudo sh -c "$(curl -fsSlL 'https://raw.githubusercontent.com/observIQ/bindplane-otel-collector/refs/heads/main/scripts/generic-install/install_unix.sh')" install_unix.sh -d 'my-custom-opentelemetry-distro' -u 'https://github.com/adnanrahic/otel-distro-builder-github-action' -e 'wss://app.bindplane.com/v1/opamp' -s '<YOUR_SECRET_KEY>' -v '0.0.1' -l 'install_id=937a3445-8962-441a-90f0-ee120c67edb7'
2
3[Output]
4Using repository URL: https://github.com/adnanrahic/otel-distro-builder-github-action
5Auto-detected package type: deb
6Downloading: https://github.com/adnanrahic/otel-distro-builder-github-action/releases/download/v0.0.1/my-custom-opentelemetry-distro_v0.0.1_linux_amd64.deb
7 % Total % Received % Xferd Average Speed Time Time Time Current
8 Dload Upload Total Spent Left Speed
9 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
10100 46.9M 100 46.9M 0 0 38.4M 0 0:00:01 0:00:01 --:--:-- 98.4M
11Selecting previously unselected package my-custom-opentelemetry-distro.
12(Reading database ... 76875 files and directories currently installed.)
13Preparing to unpack .../my-custom-opentelemetry-distro_0.0.1.deb ...
14Unpacking my-custom-opentelemetry-distro (0.0.1) ...
15Setting up my-custom-opentelemetry-distro (0.0.1) ...
16Created symlink /etc/systemd/system/multi-user.target.wants/my-custom-opentelemetry-distro.service → /lib/systemd/system/my-custom-opentelemetry-distro.service.
17Creating supervisor config...
18Managing service state...
19Starting my-custom-opentelemetry-distro service...
20Service is running
21Installation complete!
22Installation directory: /opt/my-custom-opentelemetry-distro
23Supervisor config: /opt/my-custom-opentelemetry-distro/supervisor_config.yaml
This will start the collector as a systemd
service.
1sudo systemctl status my-custom-opentelemetry-distro
2
3[Output]
4● my-custom-opentelemetry-distro.service - An OpenTelemetry Collector service named 'my-custom-opentelemetry-distro'.
5 Loaded: loaded (/lib/systemd/system/my-custom-opentelemetry-distro.service; enabled; preset: enabled)
6 Active: active (running) since Tue 2025-09-02 12:36:56 UTC; 2min 51s ago
7 Main PID: 17005 (supervisor)
8 Tasks: 7 (limit: 4681)
9 Memory: 8.5M
10 CPU: 249ms
11 CGroup: /system.slice/my-custom-opentelemetry-distro.service
12 └─17005 /opt/my-custom-opentelemetry-distro/supervisor --config=/opt/my-custom-opentelemetry-distro/supervisor_config.yaml
13
14Sep 02 12:36:56 my-custom-opentelemetry-distro systemd[1]: Started my-custom-opentelemetry-distro.service - An OpenTelemetry Collector service named 'my-opentelemetry-distro.service - An OpenTelemetry Collector service named 'my-custom-opentelemetry-distro'.
Because the OpAMP connection works via websockets, it’ll update the UI right away and show you the collector running.

6. Configure and manage your custom collector from the Bindplane UI
You can now create a configuration for the collector.

Click the Create Configuration
button to create and manage a config in Bindplane and apply it to your custom collector remotely.

Give it a name, select the Agent Type for your custom collector, and select the platform where your custom collector is running. For my example, it’s Linux. Add a Telemetry Generator source.

And, a Dev Null destination.

This will finalize your config creation. You still need to connect it to your custom collector.

Click the Add Agents
button. Select your custom collector, and hit save.

Now, you can start a rollout to apply the config remotely.

What’s awesome here is that Bindplane reads the collector’s capabilities directly from the build. You'll only be able to configure components you included in the manifest.
Let me show you by adding a new source.

The compatible sources will show up at the top. You’ll also see which sources are incompatible. This is a huge quality-of-life improvement and convenience across your entire team when creating and managing collector configs.
Step 6 — Iterate with confidence
With this setup you can:
- Update the
manifest.yaml
to add or remove modules - Create a new release
- GitHub Actions builds a new version
- Deploy or upgrade in your environment
- Bindplane instantly manages the updated agent
You now have a BYOC (Bring Your Own Collector) workflow that's fully automated, versioned, and controlled by you.
Why this works so well
Future goals
Moving forward I would love to abstract away the manifest.yaml
as well. In an ideal world I would want to give the OpenTelemetry Distro Builder a sample collector config file. It should then be able to create a manifest.yaml
from my config. This process would abstract away everything except for the specific receivers, exporters, extensions, and processors I really need.
More on this by the end of the year. 😉
Final thoughts
Custom collectors aren’t just for power users anymore. With ODB and GitHub Actions, you can build exactly what you need, package it for every platform, and manage it at scale with Bindplane. All without touching a Go compiler. 🔥
It’s clean. It’s fast. And it’s production-ready.
