DrydockDrydock
ConfigurationContainer Actions

Container Actions

Start, stop, restart, update, and delete containers directly from drydock.

Overview

Drydock provides direct container management actions through both the UI and API. These actions let you control containers without leaving the drydock interface.

Available actions

ActionAPI endpointDescription
StartPOST /api/v1/containers/:id/startStart a stopped container
StopPOST /api/v1/containers/:id/stopStop a running container
RestartPOST /api/v1/containers/:id/restartRestart a container
UpdatePOST /api/v1/containers/:id/updatePull new image and recreate container
DeleteDELETE /api/v1/containers/:idRemove container from drydock tracking

Feature flags

Container actions can be individually toggled with environment variables:

Env varRequiredDescriptionSupported valuesDefault value when missing
DD_SERVER_FEATURE_CONTAINERACTIONSEnable start, stop, restart, and update actionstrue, falsetrue
DD_SERVER_FEATURE_DELETEEnable container deletiontrue, falsetrue
When a feature flag is disabled, the corresponding buttons are hidden in the UI and the API endpoints return 403 Forbidden.
Container action endpoints currently use an authentication-only, single-operator trust model. Any authenticated user can start, stop, restart, update, or delete any container. Run drydock behind trusted SSO/access controls until fine-grained RBAC is available.

Trigger configuration aliases

Container updates are executed by action triggers (Docker, Docker Compose, Command). These triggers can be configured with three environment variable prefixes that are treated identically:

PrefixStatus
DD_ACTION_*Current — recommended for action triggers
DD_NOTIFICATION_*Current — recommended for notification triggers
DD_TRIGGER_*Deprecated — removal in v1.7.0

When the same trigger is defined under multiple prefixes, the merge priority is: DD_NOTIFICATION_* > DD_ACTION_* > DD_TRIGGER_*.

Container labels follow the same pattern: dd.action.include / dd.action.exclude replace the deprecated dd.trigger.include / dd.trigger.exclude.

Action triggers (Docker, Docker Compose, Command) default to AUTO=oninclude, meaning they only auto-update containers that have an explicit dd.action.include label matching the trigger name. Notification triggers default to AUTO=true.

See Triggers for full trigger configuration reference and the migration CLI for automated prefix rewriting.

Update action

The update action triggers the Docker or Docker Compose trigger for the selected container. It will:

  1. Pull the latest image
  2. Backup the current image
  3. Run lifecycle hooks (if configured)
  4. Stop and remove the current container
  5. Create and start the new container
  6. Monitor health (if auto-rollback is enabled)

See Lifecycle Hooks and Backup & Rollback for related configuration.

Global concurrency cap

By default, drydock runs updates concurrently across containers. Two existing layers of serialization apply:

  • Per-container lock — prevents the same container from being updated twice in parallel.
  • Per-compose-project lock — serializes services within the same compose stack so docker compose up orchestration is safe.

If you need a broader limit — for example, to stay inside Docker Hub pull-rate budgets or to keep host restart load predictable — set DD_UPDATE_MAX_CONCURRENT:

Env varRequiredDescriptionDefault
DD_UPDATE_MAX_CONCURRENTMax simultaneous update lifecycles across the entire controller instance0 (unlimited)

Semantics:

  • 0 or absent → unlimited (default; no change from current behavior on upgrade).
  • 1 → strictly serial; only one update lifecycle runs at a time.
  • N (positive integer) → at most N update lifecycles run concurrently.
  • Negative or non-integer values → drydock fails fast at startup with a descriptive error.

The global cap layers on top of the per-container and per-compose-project locks — it does not replace them. A compose stack already serializes its own members via the per-project lock; the global cap is an additional gate that limits how many stacks (or bare containers) can update at the same time.

Operations waiting on the global cap remain in queued status, which the UI already renders correctly as the Queued → Updating → Updated progression.

Scope: per controller instance. Distributed agent hosts have independent counters by design — there is no cross-host coordination.

Self-update operations (drydock updating itself) bypass the global cap — they take per-container locks but never wait on the global semaphore. This prevents a full update queue from starving an admin-triggered self-update.
services:
  drydock:
    image: codeswhat/drydock
    environment:
      # Allow at most 3 container updates to run simultaneously.
      - DD_UPDATE_MAX_CONCURRENT=3

Health-gate SSE heartbeat

When drydock waits for a new container to pass its health gate (images with long healthcheck intervals, like vaultwarden's 60 s check), the UI receives no SSE events between the health-gate phase (start of wait) and health-gate-passed (end of wait). The health-gate heartbeat fixes this by re-emitting the same health-gate phase event at a configurable interval, keeping the UI informed in near-real-time without relying on REST reconciliation.

Env varRequiredDescriptionDefault
DD_UPDATE_HEALTH_GATE_HEARTBEAT_MSInterval (ms) between health-gate SSE heartbeats during container health polling10000 (10 s)

Semantics:

  • Absent or empty → use the 10 s default.
  • 0 → disable heartbeats entirely (the UI will only receive the start health-gate event and the eventual health-gate-passed or rollback event).
  • Positive integer ≥ 1000 → emit a heartbeat every N milliseconds.
  • Values below 1000 or non-integer values → drydock fails fast at startup with a descriptive error.

Heartbeats re-emit phase: 'health-gate' (the same phase already displayed by the UI) — they do not introduce a new phase and cannot regress phase rank. The heartbeat stops immediately when the health gate resolves (success, timeout, or unhealthy), so it cannot race the terminal health-gate-passed event.

services:
  drydock:
    image: codeswhat/drydock
    environment:
      # Emit a health-gate heartbeat every 5 seconds.
      - DD_UPDATE_HEALTH_GATE_HEARTBEAT_MS=5000

Why isn't my container auto-updating?

Drydock evaluates each container against a stack of policy and trigger gates and reports the result as a pill on the row (and as updateEligibility on the API payload). When auto-update doesn't fire on a container with an available update, the pill identifies the active blocker — Below threshold, Trigger filtered, No trigger, Agent mismatch, Snoozed, etc. See Update Eligibility & Blockers for the full reason reference and how to clear each gate.

Preview

Before updating, you can preview what will change using the dry-run endpoint:

POST /api/v1/containers/:id/preview

This returns the proposed changes without executing them.

Metrics

All container actions are tracked via Prometheus counters. See Monitoring for details.

Example — disable all actions

services:
  drydock:
    image: codeswhat/drydock
    environment:
      - DD_SERVER_FEATURE_CONTAINERACTIONS=false
      - DD_SERVER_FEATURE_DELETE=false

On this page