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 stringregistry
, 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 stringlocal
, 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.
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).
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.
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.
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