Automatically Updating Podman Containers

It is a good practice to update software, especially when you get new features and/or added security in the new updates.

In this article, I will show you how to enable automatic updates for the containers managed by Podman.

For demonstration purposes, I will use the caddy image from Docker Hub.

Determine the source for fetching image

To use a container image, Podman needs to pull that image from somewhere. This "somewhere" is referred to as the auto-update policy.

The auto-update policies are as following:

  • registry: When the auto-update policy is set to the string registry, Podman will pull the image from a remote registry like Docker Hub and Quay.io.
  • local: When the auto-update policy is set to the string local, Podman will fetch image from locally built images. This update policy comes in handy when you are a developer and wish to test local changes before pushing them to a remote registry.
✍🏻
I am running a root-less container. I have tried specifying commands if you use a root-full container wherever I can, but me being a human, that may have been missed.

Simply use the sudo when you encounter an error related to privileges (only if you have a root-full container).

Enabling auto-updates

Now that you are aware of what an "auto-update policy" is, we can now proceed with this tutorial.

All that you need to do to enable automatic updates for a container managed by Podman is to add the following label:

io.containers.autoupdate=AUTO_UPDATE_POLICY

Substitute the string AUTO_UPDATE_POLICY with either registry or with local and you're good to go!

"But how will the container auto-update when Podman does not have a daemon?"

systemd integration

When I said that "You only need to add the io.containers.autoupdate label to your container," you see... I lied misspoke.

The container that needs to be automatically updated must be managed by systemd. "Why are you shoving systemd down my throat?" Well because Podman has a daemon-less architecture. And the container needs to be managed somehow.

If you want your container to be started automatically on boot, you already are using systemd to do so.

In the article linked below, I discuss how you can integrate a Podman container--be it a root-full container or a root-less container--with systemd (with the intention of auto-starting it on boot as well).

How to Autostart Podman Containers?
Podman is awesome but it doesn’t autostart containers after system reboots. Here’s how to fix that.

Regardless, I will give you a quick overview of how to manage Podman containers using systemd.

Step 0: Create a container

Make sure that you have an existing container. It does not matter if the container is running or stopped.

You can check what containers you have by running the following command:

podman container list

For this tutorial, I have pulled an older image of Caddy Server (version 2.5.2-alpine) and have renamed it to alpine. Renaming this image will help demonstrate the update process. You can check it yourself because the image ID of tag 2.5.2-alpine and alpine are same ;)

Using this image, I created a container that is named prathams-caddy.

Below is how it looks on my computer:

$ podman images
REPOSITORY               TAG           IMAGE ID      CREATED      SIZE
docker.io/library/caddy  2.5.2-alpine  d83af79bf9e2  2 weeks ago  45.5 MB
docker.io/library/caddy  alpine        d83af79bf9e2  2 weeks ago  45.5 MB

$ podman container list
CONTAINER ID  IMAGE                   COMMAND               CREATED        STATUS            PORTS       NAMES
99d1838dd999  localhost/caddy:alpine  caddy run --confi...  5 seconds ago  Up 6 seconds ago              prathams-caddy

As you can see, I have a container called prathams-caddy and it is running the caddy image (which is at an older version).

The container prathams-caddy was created with the label io.containers.autoupdate set to registry. If you have an existing container without this label, do not worry; you don't need to re-create your container. This will be covered in the next step.

DigitalOcean – The developer cloud
Helping millions of developers easily build, test, manage, and scale applications of any size – faster than ever before.

Get started on DigitalOcean with a $100, 60-day credit for new users.

Step 1: Generate a systemd service file for your container

Well, to manage your Podman container via systemd, it needs to be turned into a service. Realistically speaking, you want your container to start at boot and want to stop it when you turn off the system. It makes sense to run your container as a systemd service.

"But isn't it a too much work to write a systemd service file for each container I have?" It is. And developers of Podman have thought of this. The only manual work you need to to do is run a command for each of your containers.

If you have a root-full container (a container with root privileges), run the following command:

sudo podman generate systemd -f --new --name CONTAINER_NAME

If your container is a root-less container (a container without root privileges), run the following command:

podman generate systemd -f --new --name CONTAINER_NAME

Substitute the string CONTAINER_NAME with the name of your container and a file with the name container-CONTAINER_NAME.service will be created.

For my Caddy Server container, I will do the following:

$ podman generate systemd -f --new --name prathams-caddy
/home/pratham/container-prathams-caddy.service

As evident from the output, the file container-prathams-caddy.service was created. It will be created in the current working directory.

But this is for containers that already have a value set for the label io.containers.autoupdate. What about containers that already exist without this label? You don't have to re-create your containers with this label.

In that case, edit the systemd service file and add the following line to the ExecStart field like so:

[...]
ExecStart=/usr/bin/podman run \
    [...]
    --label io.containers.autoupdate=registry
[...]

Essentially, your systemd service file is just invoking the podman run command. All you are doing is adding the label io.containers.autoupdate to the podman run command. Neat?

Step 2: Move the systemd service file

Now that a systemd service is already created for us, we need to enable it. But before it is enabled, the service file needs to be moved in one of the following directories:

  • /etc/systemd/system/: If the container is root-full and needs to be started with superuser privileges.
  • ~/.config/systemd/user/: If the container is root-less, place it in the corresponding directory of the user that is intended to start it.

The container prathams-caddy is a root-less container so I will move it accordingly.

$ mv -v container-prathams-caddy.service ~/.config/systemd/user/
renamed 'container-prathams-caddy.service' -> '/home/pratham/.config/systemd/user/container-prathams-caddy.service'

Step 3: Enable the systemd service

Now that the service file is placed in an appropriate directory, we can proceed to enable it. But first, systemd needs to be made aware of our newly created service without rebooting our computer.

If the service needs superuser privileges, reload systemd using the following command:

sudo systemctl daemon-reload

If the service is starting a root-less container, run the following command:

systemctl --user daemon-reload

Once that is done, we can simply use the systemctl enable command to enable our service. Use either command based on your requirements:

# for a root-full container
sudo systemctl enable SERVICE_NAME.service

# for a root-less container
systemctl --user enable SERVICE_NAME.service

Once enabled, you can check the status of your service. Do not be alarmed if it says inactive (dead). This is because our service starts at boot and we haven't booted up the computer after enabling the service.

$ systemctl --user enable container-prathams-caddy.service
Created symlink /home/pratham/.config/systemd/user/default.target.wants/container-prathams-caddy.service → /home/pratham/.config/systemd/user/container-prathams-caddy.service.

$ systemctl --user status container-prathams-caddy.service
○ container-prathams-caddy.service - Podman container-prathams-caddy.service
     Loaded: loaded (/home/pratham/.config/systemd/user/container-prathams-caddy.service; enabled; vendor preset: enabled)
     Active: inactive (dead)
       Docs: man:podman-generate-systemd(1)

Now is the best time to stop the container (if it is running) and podman container rm it and reboot.

$ podman stop prathams-caddy
prathams-caddy

$ podman container rm prathams-caddy
99d1838dd9990b2f79b4f2c83bc9bc16dfbaf3fdeeb6c6418ddd6e641535ce21

Step 4 (optional): Enable user lingering

If you created a systemd service for a root-less container, it is best to enable user lingering for your particular user.

This can be achieved by running the following command:

sudo loginctl enable-linger

So will my container auto-update now?

"I added the io.containers.autoupdate label to my container(s). I also manage my container(s) with systemd now. Will my container automatically update the image now?"

Well no... But only one step remains... that ought to count for something, right? Right? right...?

All that needs to be done now is to enable the podman-auto-update service. Do so with the following command:

sudo systemctl enable podman-auto-update.service

With the podman-auto-update service enabled, systemd will check if any image needs to be updated. If there are updates, the images if fetched first. Then the container is restarted. The old image is kept in case the update needs to be rolled back for n number of reasons.

💡
Though the podman-auto-update.service will be enabled system wide, Podman is not the first class citizen for many non-Fedora distributions. Therefore, you might need to run the following command to enable it for non-root users too: systemctl --user enable --now podman-auto-update.service
Cloud Backup: Easy, Secure Online Backup - Backblaze
Never lose a photo, video, or file again. Cloud backup made easy and automatic. Backblaze unlimited online backup for $7 per month.

Auto updates? No thank you.

If auto-updates are not your thing, you may also be pleased to know that you can manually update containers with just one command, provided they are managed by systemd.

That command is the podman auto-update command. And if you just want to check for updates, pass in the --dry-run option so that no containers are actually upgraded.

Let's check if I can upgrade my caddy image from '2.5.2-alpine' to '2.6.1-alpine' using the podman auto-update command.

$ podman container list
CONTAINER ID  IMAGE                   COMMAND               CREATED        STATUS            PORTS       NAMES
a712a3c8846b  docker.io/library/caddy:alpine  caddy run --confi...  2 seconds ago  Up 2 seconds ago              prathams-caddy

$ podman auto-update --dry-run
UNIT                              CONTAINER                      IMAGE         POLICY      UPDATED
container-prathams-caddy.service  a712a3c8846b (prathams-caddy)  caddy:alpine  registry    pending

As you can see in the UPDATED column of the output of podman auto-update command, it says pending. This indicates that an update is available.

To update the container, remove the --dry-run option.

Conclusion

The process of enabling automatic updates for your Podman containers can feel a bit involving, but trust me, this will pay off in the long run. All of your containers that are managed will be automatically updated at midnight (if there are any updates). And, if the container faces any problems, systemd will roll it back to an older image, so your container keeps on running.

If you found this useful, please comment down below and tell us your thoughts! <3