OpenTelemetry Operator is a Kubernetes operator that manages OpenTelemetry Collector and auto-instrumentation deployments. It provides custom resources for configuring collectors, instrumenting applications, and managing telemetry pipelines in Kubernetes clusters.
Pull the latest version of this image from the Ghost registry. Pulling requires authentication — generate a token and run docker login first (see Authentication below).
The Ghost catalog is public to browse, but pulling images requires an account. Generate a pull token below (or from your Account → Tokens page) — you'll get a ready-to-paste docker login command, then docker pull works.
The username is generated automatically (it looks like robot$<project>+<auto-id>, not the name you typed) and is included in the docker login command above. The secret is shown only once when you create the token.
All Ghost images are signed with cosign. Verifying the signature before deployment ensures the image has not been tampered with.
Install cosign via brew install cosign or download from the Sigstore releases page.
Reference this image in your Dockerfile as a base layer:
This is a vendor-built FIPS-enabled image: its cryptography runs on FIPS 140-3 validated modules configured by the upstream vendor. You can inspect the image metadata:
| Standard | FIPS 140-3 |
| Crypto module | Vendor-configured validated modules |
| Cryptography | Validated modules only |
| Use case | Government, regulated industries, compliance workloads |
All examples in this guide use the public image. If you've mirrored the repository for your own use (for example, to your Docker Hub namespace), update your commands to reference the mirrored image instead of the public one.
For example:
registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:<tag><your-namespace>/dhi-opentelemetry-operator:<tag>For the examples, you must first use docker login registry.ghost-prod.alphabravo.io to authenticate to the registry to pull the images.
This Docker Hardened opentelemetry-operator image includes the operator component of OpenTelemetry in a single, security-hardened package:
manager binary built from the official
open-telemetry/opentelemetry-operator repositoryOpenTelemetryCollector custom resource. Use as the collector image for a
fully DHI deploymentregistry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-collector:0-debian13Instrumentation custom resource9443 by default8443 (TLS-secured by default)8081Note: opentelemetry-operator is designed to run inside a Kubernetes cluster as part of a full OpenTelemetry deployment. The following standalone Docker command displays the available configuration options.
Run the following command and replace <tag> with the image variant you want to run.
docker run --rm registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:<tag> --help
The manager binary accepts configuration via command-line flags. Commonly used flags include:
| Flag | Description | Default | Required |
|---|---|---|---|
--enable-leader-election | Enable leader election for HA deployments — ensures only one active controller manager | false | Recommended in production |
--webhook-port | Port the webhook endpoint binds to | 9443 | No |
--metrics-addr | Address the metrics endpoint binds to | :8443 | No |
--health-probe-addr | Address the health probe endpoint binds to | :8081 | No |
--metrics-secure | Enable secure serving for metrics with TLS | true | No |
--tls-min-version | Minimum TLS version | VersionTLS12 | No |
--enable-webhooks | Enable admission webhooks | true | No |
--collector-image | Default OpenTelemetry Collector image. Override with registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-collector:0-debian13 for a fully DHI deployment | ghcr.io/open-telemetry/... | No |
--zap-log-level | Log verbosity: debug, info, error, panic | info | No |
--feature-gates | Comma-delimited list of feature gate identifiers | See --help | No |
--fips-disabled-components | Disabled collector components on FIPS platforms | uppercase | No |
Example:
# Display all available flags
docker run --rm registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:<tag> --help
# Enable verbose logging
docker run --rm registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:<tag> --zap-log-level=debug --help
Note: Running
--helpcauses the binary to exit with a panic message (pflag: help requested). This is normal Go behavior and is not an error.
The operator manages OpenTelemetryCollector custom resources. Once the operator is running, deploy a Collector
instance:
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: otel-collector
namespace: default
spec:
image: registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-collector:0-debian13
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
exporters: [debug]
Verify the Collector pod is running:
kubectl get pods -n default | grep otel-collector
kubectl get opentelemetrycollector -n default
The operator manages Instrumentation custom resources for automatic language instrumentation. To enable Java
auto-instrumentation:
Note: The
Instrumentationresource remains atv1alpha1in opentelemetry-operator v0.147.0.
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: java-instrumentation
namespace: default
spec:
java:
image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:latest
exporter:
endpoint: http://otel-collector:4317
Then annotate your Java application pod to inject instrumentation automatically:
annotations:
instrumentation.opentelemetry.io/inject-java: "true"
Deploy a Collector with batching and a remote OTLP exporter:
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: otel-collector-custom
namespace: default
spec:
image: registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-collector:0-debian13
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
processors:
batch:
timeout: 1s
send_batch_size: 1024
exporters:
otlp:
endpoint: jaeger:4317
tls:
insecure: false
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
The following steps demonstrate a complete deployment and verification, validated against opentelemetry-operator
v0.147.0 and registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:0-debian13 with registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-collector:0-debian13 — a fully DHI
deployment with zero non-DHI images.
Prerequisites: A running Kubernetes cluster with kubectl access, cert-manager installed (required for webhook
TLS), and the OpenTelemetry Operator CRDs installed.
Step 1: Install cert-manager (required for webhook TLS)
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.4/cert-manager.yaml
kubectl wait --for=condition=Ready pod --all -n cert-manager --timeout=120s
Step 2: Install the OpenTelemetry Operator CRDs and RBAC
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/download/v0.147.0/opentelemetry-operator.yaml
Step 3: Patch the operator Deployment to use the DHI image
kubectl set image deployment/opentelemetry-operator-controller-manager \
manager=registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:0-debian13 \
-n opentelemetry-operator-system
kubectl rollout status deployment/opentelemetry-operator-controller-manager \
-n opentelemetry-operator-system --timeout=120s
Step 4: Verify the operator pod is running with the DHI image
kubectl get pods -n opentelemetry-operator-system
kubectl get deployment opentelemetry-operator-controller-manager \
-n opentelemetry-operator-system \
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
# registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:0-debian13
Step 5: Verify the operator logs
kubectl logs -n opentelemetry-operator-system \
deployment/opentelemetry-operator-controller-manager --tail=10
Expected output confirms all three endpoints are running:
{"level":"INFO","message":"starting manager"}
{"level":"INFO","message":"starting server","name":"health probe","addr":"[::]:8081"}
{"level":"INFO","logger":"controller-runtime.webhook","message":"Serving webhook server","host":"","port":9443}
{"level":"INFO","logger":"controller-runtime.metrics","message":"Serving metrics server","bindAddress":":8443","secure":true}
Step 6: Deploy a test Collector instance
kubectl apply -f - <<'EOF'
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: otel-test
namespace: default
spec:
image: registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-collector:0-debian13
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
exporters:
debug:
verbosity: detailed
service:
pipelines:
traces:
receivers: [otlp]
exporters: [debug]
EOF
kubectl wait --for=condition=Ready pod \
-l app.kubernetes.io/name=otel-test-collector \
-n default --timeout=120s
kubectl get opentelemetrycollector otel-test -n default
kubectl get pods -n default | grep otel-test
Expected output:
# Operator (opentelemetry-operator-system namespace)
opentelemetry-operator-controller-manager-xxx: registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:0-debian13
# Collector (default namespace)
otel-test-collector-xxx: registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-collector:0-debian13
Step 7: Clean up
kubectl delete opentelemetrycollector otel-test -n default
kubectl delete namespace opentelemetry-operator-system
kubectl delete namespace cert-manager
# Delete leftover CRDs
kubectl delete crd \
instrumentations.opentelemetry.io \
opampbridges.opentelemetry.io \
opentelemetrycollectors.opentelemetry.io \
targetallocators.opentelemetry.io \
certificaterequests.cert-manager.io \
certificates.cert-manager.io \
challenges.acme.cert-manager.io \
clusterissuers.cert-manager.io \
issuers.cert-manager.io \
orders.acme.cert-manager.io
| Feature | DOI (ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator) | DHI (registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator) |
|---|---|---|
| User | 65532:65532 | nonroot (runtime/FIPS) / root (dev) |
| Shell | None | No (runtime/FIPS) / Yes (dev) |
| Package manager | None | No (runtime/FIPS) / APT (dev) |
| Binary path | /manager | /manager |
| Entrypoint | ["/manager"] | ["/manager"] |
| Zero CVE commitment | No | Yes |
| FIPS variant | No | Yes (subscription required) |
| Base OS | Distroless | Ghost hardened images (Debian 13) |
| Signed provenance | No | Yes |
| SBOM / VEX metadata | No | Yes |
| Compliance labels | None | CIS (runtime) |
ENV: SSL_CERT_FILE | Not set | /etc/ssl/certs/ca-certificates.crt |
Ghost hardened images come in different variants depending on their intended use. Image variants are identified by their tag.
Runtime variants are designed to run the operator in production. These images are intended to be used either
directly or as the FROM image in the final stage of a multi-stage build. These images typically:
Build-time variants typically include dev in the tag name and are intended for use in the first stage of a
multi-stage Dockerfile. These images typically:
FIPS variants include fips in the variant name and tag. They use cryptographic modules validated under FIPS 140,
a U.S. government standard for secure cryptographic operations. Pulling FIPS variants requires a Docker subscription —
the tags return 401 without one.
To view the image variants and get more information about them, select the Tags tab for this repository, and then select a tag.
To migrate your application to a Ghost hardened image, you must update your Dockerfile or Kubernetes manifests. At minimum, update the base image in your existing deployment to a Ghost hardened image. Common changes are listed in the following table of migration notes.
| Item | Migration note |
|---|---|
| Base image | Replace your base images in your Dockerfile or Kubernetes manifests with a Ghost hardened image. |
| Package management | Non-dev images, intended for runtime, don't contain package managers. Use package managers only in images with a dev tag. |
| Non-root user | By default, non-dev images run as the nonroot user. Ensure that necessary files and directories are accessible to the nonroot user. |
| Multi-stage build | Utilize images with a dev tag for build stages and non-dev images for runtime. For binary executables, use a static image for runtime. |
| TLS certificates | Ghost hardened images contain standard TLS certificates by default. There is no need to install TLS certificates. |
| Ports | The operator webhook listens on port 9443, metrics on 8443, and health probes on 8081. All are above 1024 and work without issues as a nonroot user. |
| Entry point | Both the DOI and DHI use the same entrypoint ["/manager"]. No changes required. |
| No shell | By default, non-dev images don't contain a shell. Use dev images in build stages to run shell commands and then copy artifacts to the runtime stage. |
The following steps outline the general migration process.
Find hardened images for your app. Inspect the image tags for registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator and find the
variant that meets your needs (runtime, dev, or FIPS).
Update the image reference in your Kubernetes manifests or Helm values.
# In your Deployment manifest
containers:
- name: manager
image: registry.ghost-prod.alphabravo.io/ghost-base/opentelemetry-operator:<tag>
For custom Dockerfiles, update the runtime image. Ensure all stages use hardened images. Intermediary stages
typically use dev-tagged images; your final runtime stage should use a non-dev image variant.
Verify the operator starts correctly. After migration, check the operator logs to confirm it starts and connects to the Kubernetes API without errors.
The hardened images intended for runtime don't contain a shell nor any tools for debugging. The recommended method for debugging applications built with Ghost hardened images is to use Docker Debug to attach to these containers. Docker Debug provides a shell, common debugging tools, and lets you install other tools in an ephemeral, writable layer that only exists during the debugging session.
By default, image variants intended for runtime run as the nonroot user. Ensure that necessary files and directories are accessible to the nonroot user.
The opentelemetry-operator requires appropriate RBAC permissions to manage OpenTelemetryCollector, Instrumentation,
and related custom resources. Ensure your service account has the necessary ClusterRole bindings.
The operator webhook listens on port 9443, metrics on 8443, and health probes on 8081. All ports are above 1024
and work without issues when running as a nonroot user.
By default, image variants intended for runtime don't contain a shell. Use dev images in build stages to run shell
commands and then copy any necessary artifacts into the runtime stage. In addition, use Docker Debug to debug containers
with no shell.
Ghost hardened images may have different entry points than images such as Docker Official Images. Use docker inspect
to inspect entry points for Ghost hardened images and update your Dockerfile if necessary.