# Docker and Compose Run commands from the project root. A Linux Docker engine is required for the documented deployment and integration tests. ```bash 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 ```bash 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](trust-anchors.md) to download and check each TAL and matching certificate under `input/`, then run: ```bash 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: ```bash 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: ```bash 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: ```bash 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`: ```bash 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: ```bash 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: ```bash 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](command-line-reference.md#state-and-network) before deploying a binary with storage changes. ## Single-anchor daemon service ```bash 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](command-line-reference.md#daemon); 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 ...`.