The motivation is to deploy an updated version of a container without service interruption. We want to keep things lightweight and only use rootless Podman.
Say we want to replace a service container hi-0
by hi-1
. To keep the service
always available during such a deployment, a reverse proxy forwards access to
the service container(s) via their identical network alias "greet":
flowchart TD
localhost:8080 ---|:81| proxy[Container reverse-proxy]
proxy ---|greet:8282| hi0[Container hi-0]
proxy ---|greet:8282| hi1[Container hi-1]
At any given time, at least one service container is available by making sure their lifetimes overlap:
____________________________________
Container hi-0 Stop
____________________________________
Start Container hi-1
^^^^^^^^^^^^
Overlap
The following shows how to do such a deployment interactively.
-
Run the reverse proxy on a network with
podman network create test-net podman run --detach --name reverse-proxy --network test-net \ --publish 127.0.0.1:8080:81 \ docker.io/caddy:2 caddy reverse-proxy --from :81 --to greet:8282
This Caddy reverse proxy forwards port 81 to the DNS name "greet", port 8282.
-
Start version A of your service with
podman run --detach --name hi-0 --network test-net --network-alias greet \ docker.io/hashicorp/http-echo:1.0 -listen=:8282 -text='Hi from A'
This container responds with a greeting to requests on port 8282. Most importantly, we give it the network alias "greet".
Testing with
curl localhost:8080
should now return "Hi from A".To see the following update in action, you could keep a test loop running in a separate shell session with
while true; do curl --fail --max-time 0.2 localhost:8080; sleep 0.01s; done
-
Start version B of your service with
podman run --detach --name hi-1 --network test-net --network-alias greet \ docker.io/hashicorp/http-echo:1.0 -listen=:8282 -text='Hi from B'
At this point, both service versions are running at the same time with the same network alias.
-
Stop version A of your service with
podman stop hi-0
Testing with
curl localhost:8080
should now return "Hi from B". With that, the update is deployed.
You can clean up above experiments with
podman rm --force hi-0 hi-1 reverse-proxy
podman network rm test-net
Run the whole demo automatically with the script scripts/demo.sh
.
Above also works with Docker, just replace podman
by docker
in the commands.
Above can be automated in Docker Compose with Kerek (see example there).