In this post, I wanted to test podman autoupdate and how the "self healing" (rollback) action works,
(you can check this post to see how to setup local repository and modify a wordpress image How to Set Up a Local Podman Registry and Customize Podman Images)
- 1. Change wordpress container
- 2. Start the service with the new image
- 3. Modify the Containerfile
- 4. Testing Autoupdate
- 5. Testing "self-healing" or "auto-rollback"
- 6. Setting systemd podman auto-update execution
1. Change wordpress container
I currently run the docker.io wordpress image as you can see below
[|=| raspi in ~/pods/p42_wordpress ]$ podman ps
CONTAINER ID IMAGE STATUS NAMES
414c230b5e8c docker.io/library/mariadb:latest Up 5 days mariadb
f95dbc9e18a6 docker.io/library/wordpress:latest Up 5 days systemd-wordpress
39954e773035 docker.io/library/registry:2 Up 42 minutes local-registry
[|=| raspi in ~/pods/p42_wordpress ]$
To change to my local image and make podman autoupdate to work, I have modified the lines entries for Image and AutoUpdate
[|=| raspi in ~/pods/p42_wordpress ]$ cat ~/.config/containers/systemd/wordpress.container
[Unit]
Description=WordPress Web Server
After=mariadb.service
[Container]
Image=localhost:5000/p42_wordpress:v1
AutoUpdate=registry
Environment=WORDPRESS_DB_HOST=mariadb:3306
Environment=WORDPRESS_DB_USER=wordpress
WORDPRESS_DB_PASSWORD=wordpress
WORDPRESS_DB_NAME=wordpress
Volume=/home/solifugo/pods/wordpress/wp-content:/var/www/html/wp-content
PublishPort=8042:80
Network=wp.network
[Service]
Restart=always
[Install]
WantedBy=multi-user.target default.target
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user daemon-reload
[|=| raspi in ~/pods/p42_wordpress ]$
2. Start the service with the new image
To make sure we are using the local image, we will execute the following:
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user stop wordpress.service
[|=| raspi in ~/pods/p42_wordpress ]$ podman rm -f wordpress
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user daemon-reload
We can now start the service with local image:
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user start wordpress.service
[|=| raspi in ~/pods/p42_wordpress ]$ podman ps
CONTAINER ID IMAGE STATUS NAMES
39954e773035 docker.io/library/registry:2 Up About an hour local-registry
de197041e7b9 docker.io/library/mariadb:latest Up 7 minutes mariadb
72cef8edcee3 localhost:5000/p42_wordpress:v1 Up About a minute systemd-wordpress
[|=| raspi in ~/pods/p42_wordpress ]$
3. Modify the Containerfile
Let's add a "version" file or a simple comment so we can verify the change later.
[|=| raspi in ~/pods/p42_wordpress ]$ cat Containerfile
# Use the official WordPress image as a base
FROM docker.io/library/wordpress:latest
# Example: Increase the upload size by creating a custom PHP config
RUN echo 'file_uploads = On\nmemory_limit = 256M\nupload_max_filesize = 64M\npost_max_size = 64M\nmax_execution_time = 300' > /usr/local/etc/php/conf.d/uploads.ini
# NEW: Add a simple version file we can check
RUN echo "Update Test - Version 2.0" > /image_version.txt
[|=| raspi in ~/pods/p42_wordpress ]$
We can now Build it and and Push the "New" v1 (We are going to overwrite the :v1 tag for simplicity)
[|=| raspi in ~/pods/p42_wordpress ]$ podman build -t localhost:5000/p42_wordpress:v1 .
STEP 1/3: FROM docker.io/library/wordpress:latest
STEP 2/3: RUN echo 'file_uploads = On\nmemory_limit = 256M\nupload_max_filesize = 64M\npost_max_size = 64M\nmax_execution_time = 300' > /usr/local/etc/php/conf.d/uploads.ini
--> Using cache 6213e109406f3ce3ac791b8a8b2d57cf3d678b7c4bb8ede40be427c149b86b18
--> 6213e109406f
STEP 3/3: RUN echo "Update Test - Version 2.0" > /image_version.txt
COMMIT localhost:5000/p42_wordpress:v1
--> fe462c1e2d14
Successfully tagged localhost:5000/p42_wordpress:v1
fe462c1e2d14c4e87261be851e6b76cf686ff4dbedf4dc050b77a0ea9ef537cc
[|=| raspi in ~/pods/p42_wordpress ]$
[|=| raspi in ~/pods/p42_wordpress ]$ podman push localhost:5000/p42_wordpress:v1
Getting image source signatures
Copying blob 38c51b789feb skipped: already exists
[...]
Copying blob 9926eecc266a done |
Copying blob bd9ddc54bea9 skipped: already exists
Copying blob 1fb5b7dba217 skipped: already exists
Copying blob ae1a66031d13 skipped: already exists
Copying config fe462c1e2d done |
Writing manifest to image destination
[|=| raspi in ~/pods/p42_wordpress ]$
4. Testing Autoupdate
Now we can see how we have an update pending:
[|=| raspi in ~/pods/p42_wordpress ]$ podman auto-update --dry-run
UNIT IMAGE POLICY UPDATED
wordpress.service localhost:5000/p42_wordpress:v1 registry pending
mariadb.service docker.io/library/mariadb:latest registry false
[|=| raspi in ~/pods/p42_wordpress ]$
Let's execute the update and confirm we can see the new file added in the image:
[|=| raspi in ~/pods/p42_wordpress ]$ podman auto-update
Trying to pull localhost:5000/p42_wordpress:v1...
Getting image source signatures
Copying blob 9860aa0d13b7 skipped: already exists
[...]
Copying blob 723c4da029f2 skipped: already exists
Copying config fe462c1e2d done |
Writing manifest to image destination
UNIT IMAGE POLICY UPDATED
mariadb.service docker.io/library/mariadb:latest registry false
wordpress.service localhost:5000/p42_wordpress:v1 registry true
[|=| raspi in ~/pods/p42_wordpress ]$ podman exec systemd-wordpress cat /image_version.txt
Update Test - Version 2.0
[|=| raspi in ~/pods/p42_wordpress ]$
5. Testing "self-healing" or "auto-rollback"
One of the best things about podman autoupdate, is the fact that will rollback an update if it is unable to complete the deployment after the update
Let's modify the local image again this time adding a break point as below:
[|=| raspi in ~/pods/p42_wordpress ]$ cat Containerfile
# Use the official WordPress image as a base
FROM docker.io/library/wordpress:latest
# Example: Increase the upload size by creating a custom PHP config
RUN echo 'file_uploads = On\nmemory_limit = 256M\nupload_max_filesize = 64M\npost_max_size = 64M\nmax_execution_time = 300' > /usr/local/etc/php/conf.d/uploads.ini
# BROKEN STEP: Force the container to fail on startup
# This tries to run a non-existent script
ENTRYPOINT ["/bin/bash", "-c", "exit 1"]
# NEW: Add a simple version file we can check
RUN echo "Update Test - Version 3.0" > /image_version.txt
[|=| raspi in ~/pods/p42_wordpress ]$
[|=| raspi in ~/pods/p42_wordpress ]$ podman build -t localhost:5000/p42_wordpress:v1 .
STEP 1/4: FROM docker.io/library/wordpress:latest
STEP 2/4: RUN echo 'file_uploads = On\nmemory_limit = 256M\nupload_max_filesize = 64M\npost_max_size = 64M\nmax_execution_time = 300' > /usr/local/etc/php/conf.d/uploads.ini
--> Using cache 6213e109406f3ce3ac791b8a8b2d57cf3d678b7c4bb8ede40be427c149b86b18
--> 6213e109406f
STEP 3/4: ENTRYPOINT ["/bin/bash", "-c", "exit 1"]
--> Using cache 009309cf75edc7d7d12c7898cf6a464a90f472c7e8c9762f24d0a7488ae6608f
--> 009309cf75ed
STEP 4/4: RUN echo "Update Test - Version 3.0" > /image_version.txt
COMMIT localhost:5000/p42_wordpress:v1
--> 3a3adcb35052
Successfully tagged localhost:5000/p42_wordpress:v1
3a3adcb35052464966b9c87f4f2f9f41d7e920e8b79b944a6346291cd6ca158d
[|=| raspi in ~/pods/p42_wordpress ]$
[|=| raspi in ~/pods/p42_wordpress ]$ podman push localhost:5000/p42_wordpress:v1
Getting image source signatures
[...]
Copying blob 3c09e98b8858 done |
Copying blob d905cab7558a skipped: already exists
Copying blob 69a4f4da7ad4 skipped: already exists
Copying blob 3b5472ea1c23 skipped: already exists
Copying blob 843bf501e50b skipped: already exists
Copying config 3a3adcb350 done |
Writing manifest to image destination
[|=| raspi in ~/pods/p42_wordpress ]$
To make sure podman is aware of the issue, we can add Health Checks and make sure podman notifies systemd that health check is passed.
Remember that the health commands are executed inside the container, so the port will be 80 and not 8042 that is the host published port.
[|=| raspi in ~/pods/p42_wordpress ]$ cat ~/.config/containers/systemd/wordpress.container
[Unit]
Description=WordPress Web Server
After=mariadb.service
[Container]
Image=localhost:5000/p42_wordpress:v1
AutoUpdate=registry
#NEW Health Checks commands
HealthCmd=curl --fail http://localhost:80
HealthInterval=5s
HealthRetries=1
# Force Podman to wait for the health check before saying "I'm done"
Notify=healthy
Environment=WORDPRESS_DB_HOST=mariadb:3306 WORDPRESS_DB_USER=wordpress WORDPRESS_DB_PASSWORD=wordpress WORDPRESS_DB_NAME=wordpress
Volume=/home/solifugo/pods/wordpress/wp-content:/var/www/html/wp-content
PublishPort=8042:80
Network=wp.network
[Service]
Type=notify
# Disable the immediate restart loop so it doesn't "Repeat too quickly"
Restart=no
# Give the health check time to actually fail
TimeoutStartSec=40
[Install]
WantedBy=multi-user.target default.target
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user daemon-reload
[|=| raspi in ~/pods/p42_wordpress ]$ podman ps
CONTAINER ID IMAGE STATUS NAMES
39954e773035 docker.io/library/registry:2 Up 2 hours local-registry
de197041e7b9 docker.io/library/mariadb:latest Up About an hour mariadb
375d7658f685 localhost:5000/p42_wordpress:v1 Up 4 minutes (healthy) systemd-wordpress
[|=| raspi in ~/pods/p42_wordpress ]$ podman auto-update --dry-run
UNIT IMAGE POLICY UPDATED
wordpress.service localhost:5000/p42_wordpress:v1 registry pending
mariadb.service docker.io/library/mariadb:latest registry false
[|=| raspi in ~/pods/p42_wordpress ]$
When we execute the update, podman will rollback the update and restart the container again
[|=| raspi in ~/pods/p42_wordpress ]$ podman auto-update
Trying to pull localhost:5000/p42_wordpress:v1...
Getting image source signatures
[...]
Copying blob 843bf501e50b skipped: already exists
Copying config 3a3adcb350 done |
Writing manifest to image destination
UNIT IMAGE POLICY UPDATED
mariadb.service docker.io/library/mariadb:latest registry false
wordpress.service localhost:5000/p42_wordpress:v1 registry rolled back
[|=| raspi in ~/pods/p42_wordpress ]$
[|=| raspi in ~/pods/p42_wordpress ]$ podman ps
CONTAINER ID IMAGE STATUS NAMES
39954e773035 docker.io/library/registry:2 Up 2 hours local-registry
de197041e7b9 docker.io/library/mariadb:latest Up 2 hours mariadb
9cb996a3112a localhost:5000/p42_wordpress:v1 Up 9 seconds (healthy) systemd-wordpress
[|=| raspi in ~/pods/p42_wordpress ]$
6. Setting systemd podman auto-update execution
Podman comes with a pre-configured systemd timer that runs podman auto-update.
Just make sure you edit the timer and enable it (by default would be executed every day midnight)
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user edit podman-auto-update.timer
Successfully installed edited file '/home/solifugo/.config/systemd/user/podman-auto-update.timer.d/override.conf'.
[|=| raspi in ~/pods/p42_wordpress ]$ cat /home/solifugo/.config/systemd/user/podman-auto-update.timer.d/override.conf
[Timer]
OnCalendar=
OnCalendar=Mon *-*-* 03:00:00
[|=| raspi in ~/pods/p42_wordpress ]$
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user enable --now podman-auto-update.timer
Created symlink '/home/solifugo/.config/systemd/user/timers.target.wants/podman-auto-update.timer' → '/usr/lib/systemd/user/podman-auto-update.timer'.
[|=| raspi in ~/pods/p42_wordpress ]$
[|=| raspi in ~/pods/p42_wordpress ]$ systemctl --user list-timers podman-auto-update.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Mon 2026-03-02 03:10:04 GMT 5 days - - podman-auto-update.timer podman-auto-update.service
1 timers listed.
Pass --all to see loaded but inactive timers, too.
[|=| raspi in ~/pods/p42_wordpress ]$
Top comments (0)