🔥 Missed the Bindplane Launch Week? Get caught up on everything we announced! 🔥Explore now
OpenTelemetry

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...

Adnan Rahic
Adnan Rahic
Share:

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.

github-repo

Next, create a new repo in your local env.

bash
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
github-repo-setup

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

created-github-repo

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.

yaml
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:

yaml
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:

  1. Build your custom collector for all platforms
  2. Package it into .tar.gz, .zip, .deb, and .rpm
  3. Store them as GitHub Actions artifacts

You should have two files created and ready to add to Git.

bash
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.

bash
1git add .github manifest.yaml
2git commit -m "add a manifest and workflow"
3git push origin main
repo-with-manifest-and-action-workflow

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.

create-release

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

empty-release

Opening the Actions will show the build running.

workflow-running

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

built-artifacts

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

build-artifacts-in-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.

bash
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.

bash
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.

yaml
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.
agent-install-secrets

Now, go ahead and run the collector binary.

bash
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.

bash
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.

bindplane-agents-list

You can open the collector config as well.

collector-config

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.

yaml
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
repo-name

The metadata.name value also needs to match the value of dist.name in your manifest.yaml.

Apply the custom Agent Type.

bash
1bindplane apply -f /path/to/agent/type/file.yaml

Finally, sync the Agent Type to load it into Bindplane.

bash
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.

agent-type-in-bindplane

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

3-platforms

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

linux-agent-install

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.

bash
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.

bash
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.

agent-connected-after-install

6. Configure and manage your custom collector from the Bindplane UI

You can now create a configuration for the collector.

connect-config-to-collector-from-bindplane

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

build-config-1

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.

telgen

And, a Dev Null destination.

devnull

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

config-ready

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

apply-config-to-agent

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

start-config-rollout

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.

incompatible-sources

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

FeatureValue
OpAMP out-of-the-boxFull Bindplane remote config and monitoring
Declarative manifestNo Go code, no manual dependency resolution
GitHub-native CI/CDPush → Build → Package → Manage
Multi-platform packagingBuild once, run anywhere
UI-aware Bindplane integrationOnly shows supported components

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.

Adnan Rahic
Adnan Rahic
Share:

Related posts

All posts

Get our latest content
in your inbox every week

By subscribing to our Newsletter, you agreed to our Privacy Notice

Community Engagement

Join the Community

Become a part of our thriving community, where you can connect with like-minded individuals, collaborate on projects, and grow together.

Ready to Get Started

Deploy in under 20 minutes with our one line installation script and start configuring your pipelines.

Try it now