Skip to main content

Module deploy

Module deploy 

Source
Expand description

Blue/green deploy: the runtime-agnostic step sequence for a zero-downtime color swap.

A blue/green service runs two interchangeable slots, blue and green, on their own ports. At any moment one is live (Caddy routes to it) and the other is idle. A deploy readies the new version on the idle slot, proves it healthy, swaps the Caddy upstream over with a graceful reload (no dropped connections), then stops the old slot. Because the old slot lingers through the swap, rollback is just the reverse upstream swap — no rebuild.

The sequence is identical regardless of how a slot is realized — that’s the whole point. A slot is “an immutable artifact + a port”, and the two runtimes only differ in how that artifact is produced:

  • podman: the artifact is an image; readying the idle slot is a Step::PullImage, and each color is its own quadlet/container. Immutable for free, so this is the baseline and covers every language.
  • native: the artifact is the idle color’s own working dir (a synced, separately-built copy of the source), so a Python/C++/Node/Rust process keeps serving from its slot while the new code builds in the other. Readying the idle slot is a Step::Build in that slot’s dir.

Either way the swap below is the same five moves, which is why this lives in one runtime-agnostic builder.

Structs§

ColorSwap
Everything color_swap_steps needs, assembled by the caller from the per-runtime render. Keeping this a plain data struct (rather than threading the registry/exposure through) makes the swap logic a pure function the tests can pin without a live host.
NativeColorUnit
Inputs to native_color_unit. workdir is the color’s isolated slot dir; port is the slot’s allocated host port; run is the service’s [service].run command, executed unchanged in the slot dir.

Functions§

color_port_var
Env-var name carrying one color slot’s host port: SERVICE_PORT_HTTP_BLUE from the base SERVICE_PORT_HTTP. The two slots can’t share a host port (only one process binds it), so a blue/green install allocates a pair and the renders below reference the color-specific one.
color_quadlet_filename
Quadlet filename for one color slot: <service>-<color>.container. systemd’s generator turns that into the <service>-<color>.service unit that color_unit names, so the two stay in lockstep.
color_swap_steps
Build the ordered step list for a zero-downtime color swap.
color_unit
systemd unit name (without the .service suffix) for one color slot.
expand_color_quadlets
Expand a podman quadlet bundle for a blue/green service: replace the single main <service>.container with its two color variants (<service>-blue.container, <service>-green.container), leaving every aux quadlet (a bundled DB, a network, a volume) untouched — only the routable app container is doubled. The main container is identified by filename, the same convention the bundle renderer uses to inject ExecStartPre, so both slots inherit those hooks.
native_color_unit
Render one color slot’s systemd unit for a native (non-container) service.
podman_color_quadlet
Rewrite a podman main-container quadlet into one color slot’s variant: rename the container and point every published host port at the color-specific env var. The image, volumes, env file, and health command are untouched — both slots are the same artifact, differing only in identity and port. Aux quadlets (a bundled DB) are never colorized; only the routable app container is.