November 6, 2018
A while ago I stumbled upon podman, which touts itself as an alternative to
Docker. Not only does
podman not use any big fat daemons™ but it makes it rather easy to run
containers in a user-namespace, i.e. with greatly restricted privileges on your system. The fun
thing is: you are still
root within the container!
To be honest, I have not investigated Docker’s user-namespace capabilities much. But the fact that
podman has an almost identical cli to Docker greatly reduces the hurdles to just installing and
trying it out. There’s even jokes that you should simply put
alias docker=podman in your
lack of a daemon #
The fact that it is just a couple of forking processes and does not use an almighty daemon to fire
up containers behind the scenes already fascinated me about
rkt when I began reading up on CoreOS
and their environment. There was (or still is?) an issue with running
rkt on CentOS 7 though, so I
just never tried it. And while
podman is not directly equivalent to
rkt, it is a lot closer in
principle than Docker.
Most of us already do have this powerful supervisor running on our systems:
systemd. Many still
seem to hate it and sure: deploying a simple scheduled command is a lot trickier than just using a
crontab and at times
systemd seems to violate the KISS principle by trying to do too much. But
I am not going to go down this rabbit hole.
The point is: why should we use yet another supervisor (the Docker daemon in this case) to launch
our services? Well: with Docker you don’t really have a choice, since the container itself is
started by the daemon and not the commandline tool. But with
conmon and the final
runc are direct descendants of your executed command. (There are more
advantages that arise
from this model. See the linked ASG2018 talk by Dan Walsh above.)
supervise rootless containers #
Now combine the fact that you can run containers without being
podman on the one hand
--user mode on the other hand and you’ve got yourself a nice service supervisor.
Let’s assume you want to run a PostgreSQL container on a specific port. Doing so manually in a rootless container would look like this:
podman pull postgres:11-alpine podman run --rm -it --net host postgres:11-alpine postgres -p 5000
[Unit] Description=Postgres 11 container on port %i After=network.target [Service] Type=simple Restart=always ExecStartPre=-/usr/bin/podman create --net host --name %n postgres:11-alpine postgres -p %i ExecStart=/usr/bin/podman start -a --sig-proxy %n [Install] WantedBy=multi-user.target
This does not recreate the container on every restart and simply proxies the signals to the
container to stop or restart instead of running seperate
podman commands. PostgreSQL might not be
the best example in this case because usually you would really want to persist your databases
somehow. But this could be solved by adding appropriate volume mounts with
-v ... to the
container. If this was some sort of NodeJS backend taking a
PORT environment variable and if you
added configuration via an
EnvironmentFile=... line, this might make more sense.
Anyhow, you get the idea.
Put this unit in
~/.config/systemd/user/postgres@.service, reload your daemon and you can start
containers on various ports:
systemctl --user daemon-reload systemctl --user start email@example.com firstname.lastname@example.org
You should now see both containers in
podman ps and you should be able to connect locally:
$ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b6faebb5cd0b docker.io/library/postgres:11-alpine docker-entrypoint.s... 31 seconds ago Up 30 seconds ago email@example.com 7d698833cd08 docker.io/library/postgres:11-alpine docker-entrypoint.s... About an hour ago Up About an hour ago firstname.lastname@example.org $ psql -h localhost -p 5000 -U postgres psql (10.5, server 11.0) WARNING: psql major version 10, server major version 11. Some psql features might not work. Type "help" for help. postgres=#
Do this with a proper backend service as noted above, use a dedicated user and run a load-balancing proxy in front of it. Tada!
Right now, I really miss a feature like Docker’s
docker-compose.yml files. However I hear that
such a feature is planned. Until then building dependencies through
possibly the use of
podman might be a viable alternative.