8.6 KiB
Docker and Compose
Run commands from the project root. A Linux Docker engine is required for the documented deployment and integration tests.
docker build -f docker/Dockerfile -t panda-rpki:v0.1.0 .
The image defaults to an unprivileged user and includes CA certificates,
rsync and /usr/bin/time. Compose uses a read-only root filesystem and a
temporary /tmp. Host input mounts are read-only; state and outputs are writable.
Single anchor
mkdir -p state output
export INPUT_DIR="$PWD/input" STATE_DIR="$PWD/state" OUTPUT_DIR="$PWD/output"
export TAL_FILE=anchor.tal TA_FILE=anchor.cer
export PUID="$(id -u)" PGID="$(id -g)"
docker compose -f docker/compose.yaml run --build --rm validator
Supply absolute host paths as above. Relative Compose paths are resolved from
the Compose file's directory, which is docker/. Build context is explicitly
the project root. PANDA_RPKI_RRDP_SYNC_MODE defaults to auto.
All five regional anchors
Follow Prepare all five RIR trust anchors to download and
check each TAL and matching certificate under input/, then run:
mkdir -p state output
export INPUT_DIR="$PWD/input" STATE_DIR="$PWD/state" OUTPUT_DIR="$PWD/output"
export PUID="$(id -u)" PGID="$(id -g)"
export AFRINIC_TAL_FILE=afrinic.tal AFRINIC_TA_FILE=afrinic.cer
export APNIC_TAL_FILE=apnic.tal APNIC_TA_FILE=apnic.cer
export ARIN_TAL_FILE=arin.tal ARIN_TA_FILE=arin.cer
export LACNIC_TAL_FILE=lacnic.tal LACNIC_TA_FILE=lacnic.cer
export RIPE_TAL_FILE=ripe.tal RIPE_TA_FILE=ripe.cer
docker compose -f docker/compose.all5.yaml run --build --rm validator
| Template variable | Default | Applies to |
|---|---|---|
PANDA_RPKI_WORKERS |
8 | all5 and daemon object workers |
PANDA_RPKI_REPO_WORKERS |
8 | all5 and daemon transport workers |
PANDA_RPKI_WORKER_QUEUE_CAPACITY |
256 | all5 object queue |
PANDA_RPKI_REPO_QUEUE_CAPACITY |
256 | all5 daemon repository queue |
PANDA_RPKI_HTTP_TIMEOUT_SECS |
600 | all5 HTTP timeout (native CLI default is 300) |
PANDA_RPKI_RRDP_SYNC_MODE |
auto | single-anchor and all5 |
The all5 CCR is OUTPUT_DIR/all5.ccr; the single-anchor CCR is
OUTPUT_DIR/result.ccr. Reuse STATE_DIR and select new OUTPUT_DIR values
to retain multiple cycles. These templates take no bundled RIR input files.
All-five daemon service
The all-five daemon template combines the five regional TAL/TA pairs with the
continuous daemon controller. Prepare the same input/ directory used by the
all-five one-shot example, then run:
mkdir -p data/all5-daemon
export INPUT_DIR="$PWD/input" DAEMON_DIR="$PWD/data/all5-daemon"
export AFRINIC_TAL_FILE=afrinic.tal AFRINIC_TA_FILE=afrinic.cer
export APNIC_TAL_FILE=apnic.tal APNIC_TA_FILE=apnic.cer
export ARIN_TAL_FILE=arin.tal ARIN_TA_FILE=arin.cer
export LACNIC_TAL_FILE=lacnic.tal LACNIC_TA_FILE=lacnic.cer
export RIPE_TAL_FILE=ripe.tal RIPE_TA_FILE=ripe.cer
export PUID="$(id -u)" PGID="$(id -g)"
docker compose -f docker/compose.all5-daemon.yaml up -d --build
docker compose -f docker/compose.all5-daemon.yaml logs -f validator
The template uses a 60-second interval by default, keeps 10 completed runs,
and leaves the daemon running until it is stopped. It writes each run below
DAEMON_DIR/runs/ and keeps shared protocol state below DAEMON_DIR/state/.
The default diagnostic format is text, with a source file and line appended
to each diagnostic record; select json explicitly for machine consumers.
Set PANDA_RPKI_INTERVAL_SECS only when a different interval is intended. Stop
the service without deleting its data with:
docker compose -f docker/compose.all5-daemon.yaml stop
Upgrade a daemon deployment
An upgrade replaces the image and recreates the container. It does not replace
the host data directory. Keep the same DAEMON_DIR, Compose project, TAL/TA
inputs and controller settings so the new image can resume the existing
protocol state. Do not run two writable daemons against the same state root.
Run the following from the deployment directory that owns the Compose file. Use a unique image tag for every candidate so the image used by a run is auditable:
export COMPOSE_FILE="${COMPOSE_FILE:-docker/compose.all5-daemon.yaml}"
export COMPOSE_PROJECT_NAME=panda-rpki-all5
export PANDA_RPKI_IMAGE=panda-rpki:2026-09-11-logging
export SOURCE_DIR=/path/to/panda-rpki-oss
# Keep the existing INPUT_DIR, DAEMON_DIR, TAL/TA variables and settings.
docker compose -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" ps
test "$(jq -r .state "$DAEMON_DIR/daemon-status.json")" = sleeping
# Build from the source tree before stopping the running service.
docker build -f "$SOURCE_DIR/docker/Dockerfile" -t "$PANDA_RPKI_IMAGE" "$SOURCE_DIR"
docker image inspect "$PANDA_RPKI_IMAGE" --format '{{.Id}}'
# Save configuration and create a consistent stopped-state backup.
backup="upgrade-backup-$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$backup"
cp "$COMPOSE_FILE" "$backup/compose.yaml"
if test -f .env; then cp .env "$backup/env"; fi
docker compose -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" stop
cp -a "$DAEMON_DIR/state" "$backup/state"
cp -a "$DAEMON_DIR/daemon-status.json" "$DAEMON_DIR/lifecycle.json" "$backup/"
# Recreate the same service with the new image; bind-mounted data is retained.
docker compose -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" up -d --no-build --force-recreate
docker inspect "$(docker compose -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" ps -q validator)" \
--format 'image={{.Config.Image}} running={{.State.Running}}'
After the first upgraded run, verify that the run sequence advanced, the run
completed, and the new log/outputs exist. The exact run directory is printed by
the daemon status and can be selected with find:
latest_run="$(find "$DAEMON_DIR/runs" -mindepth 1 -maxdepth 1 -type d -name 'run_*' | sort | tail -1)"
test -s "$latest_run/run-summary.json"
test -s "$latest_run/validator.log"
test -s "$latest_run/result.ccr"
grep -Eq '\[src/[^]]+\.rs:[0-9]+\]$' "$latest_run/validator.log"
jq . "$latest_run/run-summary.json"
The upgrade process preserves completed run directories until normal retention
removes them. Archive important runs separately if they must outlive
PANDA_RPKI_RETAIN_RUNS.
Roll back
Stop the upgraded service before changing the image. Restore the previous
Compose file and .env, or set PANDA_RPKI_IMAGE to the previously verified
tag, then recreate the service with the same project and data directory:
docker compose -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" stop
cp "$backup/compose.yaml" "$COMPOSE_FILE"
if test -f "$backup/env"; then cp "$backup/env" .env; fi
unset PANDA_RPKI_IMAGE
docker compose -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" up -d --no-build --force-recreate
If the new binary changed the state schema or wrote incompatible state, stop the service and move the current state aside before restoring the matching stopped-state backup:
mv "$DAEMON_DIR/state" "$DAEMON_DIR/state-incompatible-$(date -u +%Y%m%dT%H%M%SZ)"
cp -a "$backup/state" "$DAEMON_DIR/state"
Never delete DAEMON_DIR or use docker compose down -v as part of a routine
upgrade. Check state compatibility
before deploying a binary with storage changes.
Single-anchor daemon service
mkdir -p data/daemon
export INPUT_DIR="$PWD/input" DAEMON_DIR="$PWD/data/daemon"
export TAL_FILE=anchor.tal TA_FILE=anchor.cer
export PUID="$(id -u)" PGID="$(id -g)"
export PANDA_RPKI_INTERVAL_SECS=600 PANDA_RPKI_RETAIN_RUNS=10
docker compose -f docker/compose.daemon.yaml up -d --build
docker compose -f docker/compose.daemon.yaml logs -f validator
# Stop gracefully; persistent host data remains available.
docker compose -f docker/compose.daemon.yaml stop
Defaults: interval 60 seconds, retain 10, PANDA_RPKI_RUN_TIMEOUT_SECS=0
(disabled), log level info, log format text. The daemon template passes
PANDA_RPKI_LOG_LEVEL and PANDA_RPKI_LOG_FORMAT into the container.
It restarts unless stopped and allows 40 seconds for shutdown, exceeding the
controller's default 30-second grace plus termination wait.
For multiple anchors, append TAL/TA pairs after -- in the daemon service's
command. For other validator options, edit that same list. A finite run can
be invoked with docker compose run --rm validator daemon ... using the
daemon CLI; use --max-runs before --.
Compose variables are expanded into arguments; only the two documented log
environment variables are read directly by the binary. For single-anchor/all5
logs, pass them with docker compose run -e PANDA_RPKI_LOG_LEVEL=debug ....