Skip to main content

Broker image

The broker image holds the andromeda binary and very little else. Its runtime layer is the distroless gcr.io/distroless/cc-debian13 image, pinned by digest, which brings glibc, libgcc_s, CA certificates and timezone data from Debian 13. There is no shell, no package manager, and neither wget nor curl. The only program you can run inside the container is andromeda itself.

That changes a few habits. A health check can't call curl, so the broker probes itself. You can't docker exec into a shell either, so to look around you attach a second container that has one. Install with Docker runs the image together with the PostgreSQL image.

Users and files​

The broker runs as uid 10001 and gid 10001. That uid has no entry in the image's /etc/passwd, so the image sets HOME to /var/lib/andromeda, which is also the working directory.

PathWhat it holds
/usr/local/bin/andromedaThe broker
/etc/andromedaEmpty, owned by the broker's user, for the files you mount
/var/lib/andromedaThe home and working directory, owned by the broker's user
/usr/share/doc/andromedaThe licence texts of the broker and the material it embeds

Mount configuration files, certificates and contexts under /etc/andromeda, and make sure uid 10001 can read them. Without --configuration (or -c), the broker looks for a file under its home directory, at /var/lib/andromeda/.config/andromeda/andromeda.toml. Naming the file you mounted, as in --configuration /etc/andromeda/andromeda.toml, is clearer and doesn't depend on HOME. The image carries no configuration file of its own, so without one the broker runs on its defaults and the environment.

Health check​

andromeda health asks a running broker whether it is ready. It exits with 0 when the broker is ready and 1 when it isn't, so it works as a container health check without any other tool in the image.

It reads the same configuration the broker reads, which means the environment, the file given with --configuration, and --host and --port when they come before health, as in andromeda --configuration /etc/andromeda/andromeda.toml health. From that configuration it works out which endpoint answers readiness.

management.modeWhat it probes
"separate-port", the default/readyz on the management listener, http://127.0.0.1:1086/readyz unless you moved it
"shared-port"/readyz on the API listener
"disabled"/ngsi-ld/v1/health on the API listener

All three answer 503 while a health indicator is down, and Monitoring explains what each one weighs.

A listener bound to 0.0.0.0 or :: is probed on the loopback address of the same family. A listener with tls transport is probed over HTTPS, but the probe doesn't check the certificate, because it dials an IP address that a certificate rarely names. It sends no credentials and looks only at the status code, the same stance a Kubernetes HTTPS probe takes. A listener that requires client certificates therefore refuses it. If you rely on the health check, keep the management listener on plaintext, or make its client certificates optional.

When the broker is ready, the command prints Broker ready: followed by the URL it probed. Otherwise it writes the reason to standard error. The broker refused the connection, gave no answer within 5 seconds, or answered with a status other than success, such as a 503 while the database is down.

In Docker and Compose​

The image declares andromeda health as its Docker health check. It runs every 30 seconds with a 5-second timeout, gives the broker 20 seconds to start, and marks the container unhealthy after 3 failures in a row. docker ps shows the result, and another Compose service can wait for the broker with depends_on and condition: service_healthy.

The image's check runs andromeda health without any flags. When your Compose file starts the broker with a configuration file, repeat the file in the service's health check, so the probe reads the same listener and management settings the broker serves with.

andromeda:
command: ["--configuration", "/etc/andromeda/andromeda.toml"]
healthcheck:
test: ["CMD", "andromeda", "--configuration", "/etc/andromeda/andromeda.toml", "health"]

Keep the exec form shown here. The image has no shell, so a CMD-SHELL health check can't run in it.

On Kubernetes​

Kubernetes ignores the health check an image declares. Point httpGet probes at the management port instead, since they need no process started inside the container.

livenessProbe:
httpGet:
path: /livez
port: 1086
readinessProbe:
httpGet:
path: /readyz
port: 1086

Debugging a running container​

Most questions about a running broker can be answered from outside its container.

  • docker exec <container> andromeda configuration show

    Prints the configuration the broker runs with, file and environment merged, with secrets redacted.

  • docker exec <container> andromeda health

    Says whether the broker is ready, and names the endpoint it asked.

  • docker cp <container>:/etc/andromeda ./andromeda-etc

    Copies out the configuration, certificates and contexts you mounted.

  • docker inspect <container> and docker logs <container>

    Show the environment the container started with, and the broker's log.

When you do need a shell next to the broker, start a small container that joins the broker's process and network namespaces and runs as the broker's own user and group.

docker run --rm -it --user 10001:10001 \
--pid=container:<container> --network=container:<container> \
busybox:1.37

The broker is process 1 in there. Because the shell runs as the same user, it can read /proc/1/environ and the broker's files under /proc/1/root without any added capability. It also shares the broker's network, so wget -qO- http://127.0.0.1:1086/readyz reaches the management listener.

On Kubernetes, kubectl debug -it <pod> --image=busybox:1.37 --target=<container> starts the same kind of container in the pod. Its default general profile adds the SYS_PTRACE capability, which some namespaces' pod security forbids.

Debugging under restricted pod security

Pass --profile=restricted and add --custom with a file that sets securityContext.runAsUser and securityContext.runAsGroup to 10001. The debugging container then runs as the broker's user, which is what lets it read the broker's process without SYS_PTRACE.

If it goes wrong​

  • docker exec <container> sh fails

    The image has no shell. Run andromeda subcommands directly with docker exec, or attach a debugging container as shown above.

  • The container stays unhealthy although the broker serves requests

    The health check probes a listener the broker doesn't use. Repeat the broker's --configuration in the health check, as shown for Compose. If the management listener requires client certificates, the probe is refused, so make them optional on that listener.

  • The broker can't read a mounted file

    The broker runs as uid 10001. Make the file readable by that uid, or by everyone, before you mount it.