The startup field accepts env-var templates, so an environment variable set
at container launch (docker run -e ENABLE_SIDECAR=enabled ...) decides
whether a service auto-starts — no config edit or wrapper script needed.
processes:
- name: app
command: /bin/sh
args: ["-c", "sleep 300"]
on-failure: shutdown
- name: sidecar
command: /bin/sh
args: ["-c", "sleep 300"]
startup: "{{.ENABLE_SIDECAR}}"
on-failure: shutdownstartup: "{{.ENABLE_SIDECAR}}"— expands from gopherd's own environment at config load (independent ofpass-env, which only controls what children inherit).- Unset or empty expands to
disabled— the service is defined but not auto-started, and can still be started via the control socket. ENABLE_SIDECAR=enabled(oroneshot) auto-starts it; any other value is a config error.startup: "{{.ENABLE_SIDECAR:-enabled}}"flips the default: on unless the var says otherwise.- Scheduled jobs gate the same way:
scheduleis allowed alongsidestartup: disabled, so"{{.ENABLE_BACKUP:-disabled}}"ships a cron job off by default andENABLE_BACKUP=scheduledarms it.
Hot reload (SIGHUP / gopherd reload) re-expands the template, picking up
env changes made between reloads.
With gopherd as the image entrypoint, the gate is a plain -e at launch — the
runtime puts the variable into gopherd's environment, where the startup
template reads it at config load:
FROM your-base-image
COPY gopherd /sbin/gopherd
COPY gopherd.yml /etc/gopherd/gopherd.yml
ENTRYPOINT ["/sbin/gopherd"]docker run myimage # sidecar stays disabled
docker run -e ENABLE_SIDECAR=enabled myimage # sidecar auto-startsSame image, two roles — no config edit, no second Dockerfile. With Compose:
services:
app:
image: myimage
environment:
ENABLE_SIDECAR: enabledKubernetes is the same idea via the container's env: list. Note that
pass-env is not needed for the gate itself; set it only if the children
should also see the variable.
ENABLE_SIDECARunset:appruns,sidecarreportsdisabled;gopherd sidecar startstill starts it.ENABLE_SIDECAR=enabled: both services auto-start.
Both read the environment at config load and again on reload. They differ in what an unmet gate means:
startup: "{{.VAR}}"switches auto-start on or off by presence. The service stays defined: status showsdisabledand a manualstartover the control socket still works.condition-env-equalscompares against a value and, when unmet, drops the service from the loaded config. It is absent fromstatus, cannot be started, and edges pointing at it vanish so dependents run without it. See service-conditions.
Pick startup when an operator should be able to start the service by
hand anyway, condition-env-equals when the service simply does not
belong in this container.
Run level. One test launches with the variable empty and asserts
status sidecar reports disabled, then proves "disabled ≠ removed" by
starting it over the control socket. The other launches with
ENABLE_SIDECAR=enabled and asserts both services reach running. SIGTERM
then yields a clean exit 0.
go test ./documentation/service-gating/ -v