Skip to content

Installation

  • JDK 21 to build and run.
  • On deploy targets, daemontools (svc, svstat) if you use the war/jar/node/docker service commands.

dc-agent is a Maven multi-module project built with the bundled wrapper (./mvnw). A plain build produces thin jars; the runnable agent jar comes from the agent-shaded profile:

Build the agent
./mvnw package -Pagent-shaded
# -> dc-agent-app/target/dc-agent.jar

The agent is configured entirely through environment variables (defaults in parentheses):

Start the agent
CONFIG_DIR=./config \
WEB_SERVER_PORT=8051 \
java -jar dc-agent-app/target/dc-agent.jar
Variable Default Purpose
WEB_SERVER_PORT 8051 TCP port the agent listens on
WEB_SERVER_CONTEXT /dc-agent Context path prefix for every endpoint
WEB_SERVER_IDLE_TIMEOUT 10m How long a connection may stay silent (Jetty’s own default is 30 s). A zip-archive-version call waits silently for up to one minute plus its waitTimeout; its config is refused unless that fits. A proxy in front needs the same read timeout
CONFIG_DIR ./config Directory holding per-task config files
OPT_DIR ./opt Working directory for the agent
TEMP_DIR /tmp Scratch directory for uploads; its path must be owned by root (a sticky /tmp is fine), see Security
DOCKER_DELETE_TEMP_DIR true Delete the docker-<name>-… work directory under TEMP_DIR after each docker push / docker check; set false only to inspect the extracted task while debugging
CONTAINER_RUNTIME podman What docker in the run scripts really is: podman (the podman-docker wrapper) or docker. Only affects securityContext.passwdEntry; the agent checks it against docker --version. Set docker on hosts with real Docker
SERVICES_DEFINITION_DIR /etc/service.d Where Docker service definitions are written
SERVICES_DIR /service daemontools service root
SERVICES_LOG_DIR /var/log daemontools log root
DAEMONTOOLS_SVC_PATH /usr/bin/svc Path to the svc binary
DAEMONTOOLS_SVSTAT_PATH /usr/bin/svstat Path to the svstat binary
UI_ADMIN_ENABLED false Enables the /ui/api/* admin endpoints
CONTROL_PLANE_ENABLED false Enables the /control-plane/api/* endpoints
CONTROL_PLANE_TOKEN REPLACE_THIS_TEST_CONTROL_PLANE_TOKEN Bearer token for the control-plane channel. Required with CONTROL_PLANE_ENABLED=true: the agent refuses to start when it is empty or the default
APP_INSTANCE_NAME dc-agent Instance name reported by /app-status
APP_STATUS_TOKEN (built-in random) Bearer token guarding /app-status; set your own in production

In production the agent itself is typically run as a daemontools service. A minimal run script:

/service/dc-agent/run
#!/bin/sh
exec 2>&1
cd /opt/dc-agent || exit 1
export CONFIG_DIR=/opt/dc-agent/config
export WEB_SERVER_PORT=8051
exec java -jar /opt/dc-agent/dc-agent.jar

Check status and control it with svstat /service/dc-agent and svc -d/svc -u /service/dc-agent.

The agent speaks plain HTTP. Terminate TLS in front of it (nginx, HAProxy, …) and forward the /dc-agent/ path through unchanged:

nginx
server {
listen 443 ssl;
server_name dc-agent.example.com;
# ssl_certificate / ssl_certificate_key ...
location /dc-agent/ {
proxy_pass http://127.0.0.1:8051;
proxy_set_header Host $host;
client_max_body_size 512m; # uploads can be large
}
}

Create one config file per task under CONFIG_DIR. For a save-artifact endpoint named sbp-android, create config/sbp-android.json:

config/sbp-android.json
{
"type": "SAVE_ARTIFACT",
"apiKeys": { "REPLACE_WITH_A_LONG_RANDOM_SECRET": "gitlab-ci" },
"dir": "/opt/sbp-android",
"extension": "apk"
}

Then upload:

Terminal window
curl --fail \
--data-binary @app-release.apk \
-H "api-key: REPLACE_WITH_A_LONG_RANDOM_SECRET" \
https://dc-agent.example.com/dc-agent/save-artifact/sbp-android/1.0.0

See Configuration for the config file format and the api-key model.