docker-orchestrate supports running commands on the host machine and inside containers before and after deployments and container stop operations. These hooks let you perform tasks like running migrations, notifying monitoring systems, or gracefully draining traffic.
Deploy commands run on the host machine before and after deployments. They exist at two levels: project-level (once per deployment invocation) and per-service (once per service deployment).
Project-level commands bracket the entire deployment. They always run, even when deploying a single service with docker orchestrate deploy web.
x-pre-deploy-host-command: |
echo "Deploy starting for {{.ProjectName}}"
x-post-deploy-host-command: |
curl -X POST https://hooks.example.com/deploy-complete
services:
web:
image: myapp:latestx-pre-deploy-host-commandruns on the host before any service is deployedx-post-deploy-host-commandruns on the host after all services deploy successfully- Template variable available:
.ProjectName
Per-service commands bracket an individual service's deployment. They are skipped when a service is skipped due to an unchanged config hash.
services:
web:
image: myapp:latest
deploy:
replicas: 3
x-pre-deploy-host-command: |
docker compose run --rm migrate
x-post-deploy-host-command: |
echo "{{.ServiceName}} deployed in {{.ProjectName}}"
update_config:
order: start-firstx-pre-deploy-host-commandruns on the host before the service deploy startsx-post-deploy-host-commandruns on the host after the service deploys successfully- Template variables available:
.ServiceName,.ProjectName - One-shot services also receive per-service deploy hooks
When deploying a project, hooks execute in this order:
- Project
x-pre-deploy-host-command(once) - For each service in deploy order:
- Service
x-pre-deploy-host-command - Container operations (cleanup, build, pull, rolling update, scale)
- Service
x-post-deploy-host-command(only on success)
- Service
- Project
x-post-deploy-host-command(once, only if all services succeed)
- If a pre-deploy command fails (non-zero exit), the deployment aborts immediately
- Post-deploy commands only run after a successful deployment -- they are skipped on failure
- The project-level post-deploy command does not run if any service deployment fails
Stop commands run when a container is being terminated, such as during a rolling update or scale-down. They allow you to drain connections, deregister from service discovery, or perform cleanup.
Four types of stop commands execute in this order when stopping a container:
x-pre-stop-host-command-- runs on the host before stoppingx-pre-stop-command-- runs as a script inside the container- Compose spec
pre_stophooks -- run as commands inside the container - Container stop + remove
x-post-stop-host-command-- runs on the host after stopping
services:
web:
image: myapp:latest
deploy:
update_config:
x-pre-stop-host-command: |
curl -f http://{{.ContainerIP}}:8080/shutdown
x-pre-stop-command: |
#!/bin/sh
echo "Stopping service gracefully..."
kill -TERM 1
x-post-stop-host-command: |
echo "Container {{.ContainerShortID}} has been stopped"The x-pre-stop-command field runs a script inside the container before it is stopped. This is useful for graceful shutdowns or cleanup tasks that need access to the container's filesystem or processes.
services:
app:
image: myapp:latest
deploy:
update_config:
x-pre-stop-command: |
#!/bin/bash
# Graceful shutdown
pkill -TERM -P 1
sleep 2
# Cleanup
rm -f /tmp/app.lockHow the script runs:
- The script is written to
/tmp/pre-stop.shinside the container - docker-orchestrate waits for it to complete before stopping the container
- If the script has a shebang (e.g.,
#!/bin/bash), that interpreter is used - Otherwise, the container's
Config.Shellproperty is used - Falls back to
/bin/shif neither is available
The container must have /bin/sh (or the shell specified in Config.Shell) and any interpreter specified in the shebang available.
docker-orchestrate supports the standard compose spec pre_stop and post_start lifecycle hooks. These run commands inside the container via Docker exec.
Pre-stop hooks execute inside the container before it is stopped, after any x-pre-stop-host-command and x-pre-stop-command have completed.
services:
web:
image: myapp:latest
pre_stop:
- command: ["nginx", "-s", "quit"]
- command: ["sh", "-c", "echo shutting down"]
user: www-data
working_dir: /app
environment:
GRACEFUL: "true"
deploy:
replicas: 3
update_config:
parallelism: 1
order: start-firstEach hook supports these fields:
| Field | Required | Description |
|---|---|---|
command |
Yes | The command to execute (list of strings) |
user |
No | The user to run the command as |
privileged |
No | Whether to run in privileged mode (default: false) |
working_dir |
No | The working directory for the command |
environment |
No | Environment variables for the command |
Hooks run sequentially. Errors are logged but do not block the container stop. If a hook fails, subsequent hooks in the list are skipped.
Post-start hooks execute inside the container after it starts, before healthchecks are evaluated. In the rolling update path, post-start hooks are handled automatically by the compose CLI. In the scale-up path, docker-orchestrate executes them explicitly.
services:
web:
image: myapp:latest
post_start:
- command: ["sh", "-c", "echo 'Container started'"]
- command: ["sh", "-c", "/app/setup.sh"]
user: appuser
working_dir: /app
environment:
INIT_MODE: "true"
deploy:
replicas: 3
update_config:
parallelism: 1
order: start-firstPost-start hooks support the same fields as pre-stop hooks. If a post-start hook fails, the container is treated as failed: the pre-stop cleanup sequence runs and the container is terminated, similar to a healthcheck failure.
The complete order of operations during a project deployment:
- Project
x-pre-deploy-host-command(on the host, once) - Service
x-pre-deploy-host-command(on the host, per service) - Container operations (per container in rolling update / scale-up):
- Container start
- Compose spec
post_starthooks (commands inside the container) - Docker healthcheck (or
x-healthcheck-wait) +x-healthcheck-host-command x-wait-after-healthydelay (if configured)- ...service runs...
x-pre-stop-host-command(on the host)x-pre-stop-command(script inside the container)- Compose spec
pre_stophooks (commands inside the container) - Container stop + remove
x-post-stop-host-command(on the host)
- Service
x-post-deploy-host-command(on the host, per service, only on success) - Project
x-post-deploy-host-command(on the host, once, only if all services succeed)
By default, all host commands run synchronously -- docker-orchestrate waits for them to complete before proceeding. You can run commands in detached mode so they execute in the background without blocking the deployment.
Detached mode is available for both deploy commands and stop commands:
# Project-level detached deploy commands
x-pre-deploy-host-command: |
./notify-deploy-start.sh
x-pre-deploy-host-command-detached: true
x-post-deploy-host-command: |
./notify-deploy-complete.sh
x-post-deploy-host-command-detached: true
services:
web:
image: myapp:latest
deploy:
# Per-service detached deploy commands
x-pre-deploy-host-command-detached: false
x-post-deploy-host-command-detached: false
update_config:
# Detached stop commands
x-pre-stop-host-command: |
./cleanup-script.sh {{.ContainerID}}
x-pre-stop-host-command-detached: true
x-post-stop-host-command: |
curl -X POST http://monitoring.example.com/notify
x-post-stop-host-command-detached: true- Detached commands are guaranteed to be started (forked) before docker-orchestrate proceeds
- Detached commands continue running even if docker-orchestrate exits
- Only boolean values (
trueorfalse) are allowed - Default is
false(synchronous execution)
All host commands are Go templates with access to context-specific variables:
| Variable | Description | Available in |
|---|---|---|
.ContainerID |
Full container ID | Stop commands, healthcheck commands |
.ContainerShortID |
First 12 characters of the container ID | Stop commands, healthcheck commands |
.ContainerIP |
Internal IP address of the container | Stop commands, healthcheck commands |
.ProjectName |
Name of the compose project | All commands |
.ServiceName |
Name of the service | Per-service and stop commands |
Container-specific variables (.ContainerID, .ContainerShortID, .ContainerIP) are empty in deploy commands, which run before or after container operations rather than targeting a specific container.
Host commands execute on the host machine using /bin/sh by default. To use a different interpreter, add a shebang as the first line:
services:
web:
image: myapp:latest
deploy:
update_config:
x-pre-stop-host-command: |
#!/usr/bin/env bash
echo "Using bash-specific features"
declare -A mymap- Deployment Configuration --
update_configfields and deployment order - Healthchecks -- health validation that runs between post-start and pre-stop