Skip to content

container

The container module manages containers using Docker or Podman. The runtime is auto-detected, or can be specified explicitly.

container "myapp" {
image "registry.example.com/myapp:latest"
state "running"
runtime "podman"
install-runtime #true
restart "always"
network "host"
command "nginx -g 'daemon off;'"
ports {
- "8080:80"
- "8443:443"
}
environment {
DATABASE_URL "postgres://db:5432/app"
LOG_LEVEL "info"
}
volumes {
- "/data/myapp:/app/data"
}
}

Unknown parameters are rejected at check time, so a typo (privledged) fails loudly instead of being silently dropped. So are mistyped ones: ports "8080:80" written as a string rather than a list block would otherwise produce a container with no published ports and no error. Values glidesh cannot act on — an unsupported runtime, for instance — are rejected the same way.

StateMeaning
"running" (default)A long-lived container is up and matches the plan
"stopped"The container exists but is not running
"absent"No container with this name exists
"run-once"Run the container in the foreground to completion — a job, not a service
ParameterTypeDescription
(positional)stringContainer name
imagestringContainer image reference
statestringSee States
runtimestring"docker" or "podman" (default: auto-detect). Any other value is rejected
install-runtimebooleanAuto-install the runtime if not found. Installing happens during apply, never during check
commandstringCommand to run in the container. Appended verbatim, so its own quoting is preserved
entrypointstringOverride the image entrypoint
pullstring"always", "missing", or "never"
restartstringRestart policy: "always", "on-failure", "no"
portslistPort mappings (host:container)
environmentmapEnvironment variables
volumeslistVolume mounts (host:container)
labelsmapContainer labels
networkstring"host", "bridge", "none", "container:<name>", or a custom network name (auto-created if it doesn’t exist)
network-aliaslistExtra DNS names on the attached network
dnslistDNS servers
add-hostlistExtra /etc/hosts entries (name:ip)
hostnamestringContainer hostname
userstringUser (or uid:gid) to run as
workdirstringWorking directory inside the container
stop-signalstringSignal sent on stop
initbooleanRun an init process as PID 1
read-onlybooleanMount the root filesystem read-only
tmpfslisttmpfs mount paths
ParameterTypeDescription
ipcstringIPC namespace: "host", "private", "shareable", "container:<name>"
pidstringPID namespace
utsstringUTS namespace
cgroupnsstringcgroup namespace
usernsstringUser namespace
privilegedbooleanRun with full host privileges
cap-addlistLinux capabilities to add
cap-droplistLinux capabilities to drop
security-optlistSecurity options (e.g. "seccomp=unconfined")
deviceslistHost devices to expose (host:container[:perms])
gpusstringGPU access. Emits --gpus on Docker; on Podman it becomes a CDI device (allnvidia.com/gpu=all)
shm-sizestringSize of /dev/shm (e.g. "16g")
memorystringMemory limit
cpusstringCPU limit
ulimitsmapulimits, as namesoft[:hard]
sysctlsmapKernel parameters
extra-argslistRaw flags passed to run verbatim, unquoted. The escape hatch for anything without a first-class parameter

Shared-memory workloads (CUDA IPC in particular) need the host IPC namespace — without it, a client mapping another process’s GPU buffers fails with cudaErrorMapBufferObjectFailed:

container "vllm" {
image "vllm/vllm-openai:latest"
ipc "host"
privileged #true
gpus "all"
shm-size "16g"
ulimits {
memlock "-1"
stack "67108864"
}
}

subscribe orders steps; it does not wait for the service a step started to become usable. These parameters make a container task block until it is actually ready, so the next step can rely on it.

ParameterTypeDescription
healthcheckblockContainer healthcheck: cmd, interval, timeout, retries, start-period. Bare numbers are seconds. cmd "NONE" disables the image’s healthcheck
waitstring"healthy" (runtime health status), "running", or "none" (default). "healthy" requires a healthcheck — from a healthcheck block or baked into the image — and errors without one
wait-timeoutintegerSeconds to wait before failing (default: 300)
wait-intervalintegerSeconds between probes (default: 3)
ready-cmdstringProbe run on the target host, not inside the container. Ready on exit code 0. Implies wait "running"
step "Serve the model" {
container "vllm" {
image "vllm/vllm-openai:latest"
ipc "host"
gpus "all"
ports { - "8000:8000" }
healthcheck {
cmd "curl -sf http://localhost:8000/health"
interval 10
start-period 60
retries 3
}
wait "healthy"
wait-timeout 900
}
}
step "Warm the cache" subscribe="Serve the model" {
shell "curl -sf http://localhost:8000/v1/models"
}

Use ready-cmd when the image has no shell or no HTTP client to run a healthcheck with:

container "lmcache" {
image "lmcache/vllm-openai:latest"
ipc "host"
ready-cmd "curl -sf http://localhost:8000/health"
wait-timeout 900
}

When readiness is not reached in time, the task fails with the container’s last 30 log lines attached.

A readiness condition that can never hold is reported as a plan error rather than waited out. wait "healthy" on a container with no healthcheck fails as soon as there is a container to inspect — during apply on the first run, at check time on every run after that — rather than polling to wait-timeout first. Because glidesh cannot know whether an image carries its own HEALTHCHECK until the container exists, a first-run --dry-run cannot catch this.

state "run-once" runs the container in the foreground and waits for it to exit, instead of detaching. This covers work that used to need a raw shell invocation of docker run — pulling model weights, running a migration, seeding a volume.

ParameterTypeDescription
checkstringGuard command. If it exits 0 the job is already done and is skipped
removebooleanAdd --rm (default: #true)
timeoutintegerSeconds before the run is abandoned
retriesintegerAttempts before failing (default: 1)
delayintegerSeconds between attempts
success_codesstring, integer, or listExit codes treated as success (default: 0)
step "Fetch model weights" {
container "hf-download" {
state "run-once"
image "python:3.12-slim"
entrypoint "/bin/bash"
command #"-c "pip install -q huggingface_hub && hf download zai-org/GLM-4.6 --local-dir /models/GLM-4.6""#
volumes { - "/srv/models:/models" }
environment {
HF_TOKEN "${hf-token}"
}
check "test -d /srv/models/GLM-4.6"
timeout 7200
retries 3
delay 30
}
}

restart is rejected with state "run-once" — a job that restarts is not a job.

Every parameter that reaches the runtime is folded into a hash stored on the container as the sh.glide.param-hash label. On the next run:

  • Container missing → create and start it.
  • Hash differs → stop, remove, and recreate with the new spec.
  • Hash matches, container stopped or pausedstart / unpause it, keeping the existing container.
  • Hash matches, container running → nothing to do (then the readiness gate, if any, is evaluated).

The hash is computed from the generated run arguments rather than a hand-maintained list, so any parameter you set affects drift detection.

Lists whose order the runtime ignores — ports, volumes, devices, dns, add-host, network-alias, tmpfs, cap-add, cap-drop — are compared order-insensitively, so reordering their entries is a cosmetic edit rather than a recreate. extra-args and security-opt are compared in order, since order can change what they mean.

Removal is verified: if the existing container cannot be removed, the task fails with that reason rather than letting the follow-up run fail with the runtime’s opaque “name is already in use”.

Readiness parameters (wait, wait-timeout, wait-interval, ready-cmd) are glidesh-side and deliberately excluded from the hash — changing a probe must not recreate a healthy container.

When network is set to a name other than host, bridge, none, default, or a container:/ns: reference, the module automatically creates the network if it doesn’t already exist. This lets containers on the same custom network communicate by container name.

container "redis" {
image "redis:7"
network "app-net"
}
container "webapp" {
image "myapp:latest"
network "app-net"
environment {
REDIS_URL "redis://redis:6379"
}
}

See the container-app example for a basic containerized deployment, and the gpu-inference example for GPU flags, one-shot jobs, and readiness gating.