voodu apply
Stream context, plan, reconcile.
Synopsis
voodu apply -f voodu.hcl -r prod-1 [flags]What it does
- Tar the working directory (build mode) or skip (image mode).
- Stream the tarball over SSH to
voodu receive-packon the remote. - Controller diffs the manifest against embedded etcd.
- Builds the image (or skips — tarball hash is content-addressed).
- Swaps
currentsymlink, runsreleasehooks, recreates containers. - Reconciles ingress and Caddy routes.
Flags
| Flag | Default | Description |
|---|---|---|
-f, --file | — | Manifest file or directory. Repeat for multiple. |
-r, --remote | — | SSH alias from voodu remote list. |
--prune | false | Opt-in. Delete resources in the same (scope, kind) that aren't declared in this apply. Default is upsert-only — siblings stay put. |
-y, --auto-approve | false | Skip the interactive confirmation prompt (also VOODU_AUTO_APPROVE=1). |
--force | false | Rebuild build-mode deployments even when the tarball hash matches an existing release (also VOODU_FORCE_REBUILD=1). |
-v, --verbose | false | Show raw docker build output instead of collapsing to a spinner. |
Examples
# Standard apply
voodu apply -f voodu.hcl -r prod-1
# Multi-file
voodu apply -f infra/web.voodu -f infra/redis.voodu -r prod-1
# Multi-remote loop
for r in prod-1 prod-2 prod-3; do
voodu apply -f voodu.hcl -r $r
done
# CI gate
voodu diff -f voodu.hcl --detailed-exitcode -r prod-1
# exit 2 = changes pending, exit 0 = no-op
# Opt-in cleanup of stale siblings (full source-of-truth apply)
voodu apply -f voodu.hcl --prune -r prod-1Variable interpolation
${VAR} and ${VAR:-default} resolve on your machine before the tarball ships. Two sources:
- Your shell env (
os.Environ()). env_from'd config buckets — when a resource declaresenv_from = ["scope/name"], the CLI fetches that bucket from the controller before parsing. So${SLACK_WEBHOOK_URL}inon_deploy.success.urlcan come fromvoodu config set -s prod -n shared SLACK_WEBHOOK_URL=.... No per-devexportneeded.
Shell wins over bucket on collision — ad-hoc override works for testing without touching the bucket.
deployment "prod" "api" {
env_from = ["prod/shared"]
on_deploy {
success { url = "${SLACK_WEBHOOK_URL}" } # resolved from prod/shared
}
}Caveat: bucket-fed interpolation is local-apply only. With -r <remote> the SSH-forward path keeps shell-only.
Output
→ packing context (1.4 MB)
→ streaming over ssh ubuntu@prod-1
→ controller: planning ...
+ app/prod/api replicas=3 image=ghcr.io/myorg/api:1.7
~ ingress/prod/api tls.email=ops@example.com
- cronjob/prod/old-cleanup
→ build → swap current → reconcile caddy
✓ apply complete in 11.8s
✓ https://api.example.com · 3/3 healthy