GHOSTby AlphaBravo
CatalogWhy GhostContactAccount
Ghost Container Registry — Secure, signed, FIPS-ready images·Built by AlphaBravo
Catalog/tempo/Guides

grafana tempo

FIPS 140-3Developer tools

Grafana Tempo is an open source, easy-to-use, and high-scale distributed tracing backend.

OverviewGuidesTags

Quick Start

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

Authentication

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.

Verify Signature

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.

Using This Image

Reference this image in your Dockerfile as a base layer:

FIPS 140-3 Compliance

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:

StandardFIPS 140-3
Crypto moduleVendor-configured validated modules
CryptographyValidated modules only
Use caseGovernment, regulated industries, compliance workloads

Additional Notes

Prerequisites

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:

  • Public image: registry.ghost-prod.alphabravo.io/ghost-base/tempo:<tag>
  • Mirrored image: <your-namespace>/dhi-tempo:<tag>

For the examples, you must first use docker login registry.ghost-prod.alphabravo.io to authenticate to the registry to pull the images.

What's included in this Tempo image

This Docker Hardened Tempo image includes the Grafana Tempo distributed tracing backend in a single, security-hardened package:

  • tempo binary (/opt/tempo/tempo) for trace ingestion, storage, and querying
  • Support for multiple tracing protocols: OpenTelemetry (gRPC and HTTP), Jaeger (Thrift HTTP and gRPC), and Zipkin
  • TraceQL query language for trace-first queries
  • Metrics generation from traces via the metrics-generator component
  • Local and object storage backends (S3, GCS, Azure) for trace data
  • TLS certificates for secure communication

On this page

Quick StartAuthenticationVerify SignatureUsing This ImageFIPS ComplianceAdditional Notes
  • CIS benchmark compliance (runtime), FIPS 140 + STIG + CIS compliance (FIPS variant)
  • Start a Tempo instance

    Note: Tempo requires a YAML configuration file to start. The standalone Docker command below verifies the image runs correctly. See the common use cases section for complete configuration examples.

    Run the following command and replace <tag> with the image variant you want to run (for example, 2).

    $ docker run --rm registry.ghost-prod.alphabravo.io/ghost-base/tempo:<tag> --help
    

    Tempo-specific configuration

    The Tempo binary accepts several configuration flags to customize its behavior for different deployment scenarios.

    Specify a configuration file

    The -config.file flag points Tempo to a YAML configuration file that defines receivers, storage backends, and server settings. This flag is required for all deployments.

    $ docker run --rm \
      -v $(pwd)/tempo.yaml:/etc/tempo.yaml \
      registry.ghost-prod.alphabravo.io/ghost-base/tempo:2 \
      -config.file=/etc/tempo.yaml
    

    Set the target module

    The -target flag controls which Tempo module to run. By default, Tempo runs in all mode (single binary), but you can run individual modules for a scalable, microservice-style deployment.

    Available targets include all, distributor, ingester, querier, query-frontend, compactor, and metrics-generator.

    $ docker run --rm \
      -v $(pwd)/tempo.yaml:/etc/tempo.yaml \
      registry.ghost-prod.alphabravo.io/ghost-base/tempo:2 \
      -config.file=/etc/tempo.yaml \
      -target=distributor
    

    This configuration is particularly useful in high-availability setups where different Tempo instances handle specific responsibilities for improved performance and reliability.

    Override configuration with command-line flags

    Individual configuration values can be overridden at the command line using dot-notation paths that correspond to the YAML configuration structure:

    $ docker run --rm \
      -v $(pwd)/tempo.yaml:/etc/tempo.yaml \
      registry.ghost-prod.alphabravo.io/ghost-base/tempo:2 \
      -config.file=/etc/tempo.yaml \
      -server.http-listen-port=3200 \
      -distributor.receivers.otlp.protocols.grpc.endpoint=0.0.0.0:4317
    

    Common Tempo use cases

    Run Tempo with local storage for development

    Tempo stores trace data on local disk or object storage. The following example shows a minimal configuration for local development.

    Create a Tempo configuration file:

    # tempo.yaml
    stream_over_http_enabled: true
    
    server:
      http_listen_port: 3200
    
    distributor:
      receivers:
        otlp:
          protocols:
            grpc:
              endpoint: "0.0.0.0:4317"
            http:
              endpoint: "0.0.0.0:4318"
    
    storage:
      trace:
        backend: local
        local:
          path: /var/tempo/traces
        wal:
          path: /var/tempo/wal
    

    Start Tempo with the configuration:

    $ docker run -d --name tempo \
      -p 3200:3200 \
      -p 4317:4317 \
      -p 4318:4318 \
      -v $(pwd)/tempo.yaml:/etc/tempo.yaml \
      -v tempo-data:/var/tempo \
      registry.ghost-prod.alphabravo.io/ghost-base/tempo:2 \
      -config.file=/etc/tempo.yaml
    

    Verify Tempo is running:

    $ curl http://localhost:3200/ready
    

    A successful response returns ready. Note that the ingester requires approximately 15 seconds to warm up after starting. During this period, the /ready endpoint returns a "not ready" status, which is expected behavior.

    Deploy Tempo with Grafana for trace visualization

    The following Docker Compose configuration deploys Tempo alongside Grafana with Tempo pre-configured as a datasource.

    Create the Grafana datasource configuration:

    # grafana-datasources.yaml
    apiVersion: 1
    datasources:
      - name: Tempo
        type: tempo
        access: proxy
        url: "http://tempo:3200"
        isDefault: true
    

    Create the Docker Compose file:

    # compose.yaml
    services:
      tempo:
        image: registry.ghost-prod.alphabravo.io/ghost-base/tempo:2
        command: ["-config.file=/etc/tempo.yaml"]
        ports:
          - "3200:3200"   # Tempo API
          - "4317:4317"   # OTLP gRPC
          - "4318:4318"   # OTLP HTTP
        volumes:
          - ./tempo.yaml:/etc/tempo.yaml
          - tempo-data:/var/tempo
    
      grafana:
        image: registry.ghost-prod.alphabravo.io/ghost-base/grafana:12-debian13-dev
        ports:
          - "3000:3000"
        environment:
          GF_AUTH_ANONYMOUS_ENABLED: "true"
          GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
        volumes:
          - ./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml
        depends_on:
          - tempo
    
    volumes:
      tempo-data:
    

    Start the stack:

    $ docker compose up -d
    

    Access Grafana at http://localhost:3000 and navigate to Explore > Tempo to query traces.

    Accept traces from multiple protocols

    Configure Tempo to accept traces from OpenTelemetry, Jaeger, and Zipkin protocols simultaneously. This is useful when migrating from one tracing system to another or when different services in your stack use different instrumentation libraries.

    Create the Tempo configuration file:

    # tempo-multi.yaml
    stream_over_http_enabled: true
    
    server:
      http_listen_port: 3200
    
    distributor:
      receivers:
        otlp:
          protocols:
            grpc:
              endpoint: "0.0.0.0:4317"
            http:
              endpoint: "0.0.0.0:4318"
        jaeger:
          protocols:
            thrift_http:
              endpoint: "0.0.0.0:14268"
            grpc:
              endpoint: "0.0.0.0:14250"
        zipkin:
          endpoint: "0.0.0.0:9411"
    
    storage:
      trace:
        backend: local
        local:
          path: /var/tempo/traces
        wal:
          path: /var/tempo/wal
    

    Start Tempo with all protocol ports exposed:

    $ docker run -d --name tempo \
      -p 3200:3200 \
      -p 4317:4317 \
      -p 4318:4318 \
      -p 9411:9411 \
      -p 14268:14268 \
      -v $(pwd)/tempo-multi.yaml:/etc/tempo.yaml \
      -v tempo-data:/var/tempo \
      registry.ghost-prod.alphabravo.io/ghost-base/tempo:2 \
      -config.file=/etc/tempo.yaml
    

    The following table lists the available ingestion endpoints:

    ProtocolPortEndpoint
    OTLP gRPC4317localhost:4317
    OTLP HTTP4318http://localhost:4318/v1/traces
    Jaeger Thrift HTTP14268http://localhost:14268/api/traces
    Zipkin9411http://localhost:9411/api/v2/spans
    Tempo API / Query3200http://localhost:3200

    Deploy Tempo in Kubernetes

    First follow the authentication instructions for DHI in Kubernetes.

    Tempo is typically deployed as a StatefulSet or Deployment in Kubernetes with persistent storage for trace data.

    Note: The Ghost hardened image uses the string nonroot as the user, which causes a CreateContainerConfigError with Kubernetes' runAsNonRoot validation. You must explicitly set runAsUser: 65532 in the security context to resolve this.

    The following example shows a Deployment configuration for Tempo:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: tempo
      namespace: tracing
    spec:
      template:
        spec:
          containers:
          - name: tempo
            image: registry.ghost-prod.alphabravo.io/ghost-base/tempo:<tag>
            args:
            - -config.file=/etc/tempo.yaml
            ports:
            - containerPort: 3200
              name: http
            - containerPort: 4317
              name: otlp-grpc
            - containerPort: 4318
              name: otlp-http
            securityContext:
              runAsUser: 65532
            volumeMounts:
            - name: config
              mountPath: /etc/tempo.yaml
              subPath: tempo.yaml
            - name: data
              mountPath: /var/tempo
          volumes:
          - name: config
            configMap:
              name: tempo-config
          - name: data
            persistentVolumeClaim:
              claimName: tempo-data
          imagePullSecrets:
          - name: <secret name>
    

    When deploying with Helm, include the securityContext.runAsUser override:

    $ helm upgrade --install tempo grafana/tempo \
      -n tracing --create-namespace \
      --set tempo.repository=registry.ghost-prod.alphabravo.io/ghost-base/tempo \
      --set tempo.tag=2 \
      --set securityContext.runAsUser=65532
    

    Official Docker image (DOI) vs Ghost hardened image (DHI)

    FeatureDOI (grafana/tempo)DHI (registry.ghost-prod.alphabravo.io/ghost-base/tempo)
    User10001:10001 (numeric UID)nonroot (runtime/FIPS)
    ShellNoNo (runtime/FIPS)
    Package managerNoNo (runtime/FIPS)
    Binary path/tempo/opt/tempo/tempo
    EntrypointENTRYPOINT /tempoENTRYPOINT /opt/tempo/tempo
    Uncompressed size155 MB145 MB (runtime) / 215 MB (FIPS)
    Zero CVE commitmentNoYes
    FIPS variantNoYes (FIPS + STIG + CIS)
    Base OSDistroless (no OS labels)Ghost hardened images (Debian 13)
    Compliance labelsNoneCIS (runtime), FIPS+STIG+CIS (fips)
    ENV: SSL_CERT_FILE/etc/ssl/certs/ca-certificates.crt/etc/ssl/certs/ca-certificates.crt
    Architecturesamd64, arm64amd64, arm64 (runtime) / amd64 (FIPS)

    Image variants

    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 Tempo in production. These images typically:

    • Run as a nonroot user
    • Do not include a shell or a package manager
    • Contain only the tempo binary (/opt/tempo/tempo) and TLS certificates
    • Include CIS benchmark compliance (com.docker.dhi.compliance: cis)

    FIPS variants include fips in the variant name and tag. They come in both runtime and build-time variants. These variants use cryptographic modules that have been validated under FIPS 140, a U.S. government standard for secure cryptographic operations. FIPS variants also include STIG and CIS compliance (com.docker.dhi.compliance: fips,stig,cis). For example, usage of MD5 fails in FIPS variants. Use FIPS variants in regulated environments such as FedRAMP, government, and financial services.

    To view the image variants and get more information about them, select the Tags tab for this repository, and then select a tag.

    Note: This image currently does not provide dev variants. For debugging, use Docker Debug to attach to running containers.

    Note: Tempo is part of the Grafana observability stack. For a complete tracing pipeline, you may also want to use Ghost hardened images for related components such as Grafana Alloy (trace collector) and Grafana (visualization).

    Migrate to a Ghost hardened image

    To migrate your application to a Ghost hardened image, you must update your Dockerfile or Kubernetes manifests. At minimum, you must update the base image in your existing deployment to a Ghost hardened image. This and a few other common changes are listed in the following table of migration notes:

    ItemMigration note
    Base imageReplace your base images in your Dockerfile or Kubernetes manifests with a Ghost hardened image.
    Package managementNon-dev images, intended for runtime, don't contain package managers. Use package managers only in images with a dev tag.
    Non-root userBy default, non-dev images, intended for runtime, run as the nonroot user. Ensure that necessary files and directories are accessible to the nonroot user.
    Multi-stage buildUtilize images with a dev tag for build stages and non-dev images for runtime. For binary executables, use a static image for runtime.
    TLS certificatesGhost hardened images contain standard TLS certificates by default. There is no need to install TLS certificates.
    PortsNon-dev hardened images run as a nonroot user by default. Tempo uses ports 3200, 4317, 4318, 9411, and 14268, all above 1024, so no privileged port issues arise.
    Entry pointGhost hardened images may have different entry points than upstream Tempo images. Inspect entry points for Ghost hardened images and update your deployment if necessary.
    No shellBy default, non-dev images, intended for runtime, don't contain a shell. Use dev images in build stages to run shell commands and then copy artifacts to the runtime stage.
    Data directoryEnsure the /var/tempo directory is writable by the nonroot user. When using Docker volumes this is handled automatically. For bind mounts, set ownership to UID 65532.

    The following steps outline the general migration process.

    1. Find hardened images for your app. The Tempo hardened image may have several variants. Inspect the image tags and find the image variant that meets your needs.
    2. Update the image references in your Kubernetes manifests or Compose files. Update the image references in your Tempo deployment manifests to use the hardened images. If using Helm, update your values file accordingly.
    3. For custom deployments, update the runtime image in your Dockerfile. If you're building custom images based on Tempo, ensure that your final image uses the hardened Tempo image as the base.
    4. Verify data directory permissions. Ensure the /var/tempo data directory is writable by the nonroot user (UID 65532). For Docker volumes this is automatic. For bind mounts, run chown -R 65532:65532 ./tempo-data.
    5. Test trace ingestion and querying. After migration, test that trace ingestion from all configured protocols and TraceQL queries continue to function correctly with the hardened images.

    Troubleshoot migration

    General debugging

    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.

    Permissions

    By default image variants intended for runtime, run as the nonroot user. Ensure that necessary files and directories are accessible to the nonroot user. You may need to copy files to different directories or change permissions so your application running as the nonroot user can access them.

    Tempo requires write access to the /var/tempo directory for trace data and WAL files. When using bind mounts, ensure correct ownership:

    $ chown -R 65532:65532 ./tempo-data
    

    No shell

    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.

    Entry point

    Ghost hardened images may have different entry points than upstream Tempo images. Use docker inspect to inspect entry points for Ghost hardened images and update your Kubernetes deployment if necessary.