How to update container images with Podman
Podman is a daemon-less engine for developing, managing, and running Open Container Initiative (OCI)-compliant containers. This is the fourth article in a series about using Podman based on things I do in my real work environment. Previously, I showed how to display networking information with Podman, including containers and pod IP addresses.
Before reading this article, make sure you've read the first three parts:
- Create fast, easy, and repeatable containers with Podman and shell scripts
- How to use Podman to get information about your containers
- How Podman can extract a container's external IP address
This article demonstrates how to update container images. Keeping running containers and pods current with the most up-to-date image changes is important. To follow along with this article, first run the shell scripts I used in the "Setting things up" section of the first article in this series.
Inspect images before updating
Before updating any images, it's important to understand what changes from one image version to another. Tracking these changes allows you to understand their impact on your environment. In certain scenarios, it might be useful to use more in-depth inspection tools like Skopeo, which allows you to inspect "a remote image showing its properties including its layers, without requiring you to pull the image to the host." You could also check the image's Dockerfile to get update information. However, the Podman command-line interface (CLI) alone can help you gather some of this information.
This example shows the images I have been using since the first article:
$ podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/wordpress latest 054741915cf1 6 weeks ago 629 MB
docker.io/library/mysql latest bbf6571db497 6 weeks ago 521 MB
docker.io/library/httpd latest ea28e1b82f31 6 weeks ago 148 MB
k8s.gcr.io/pause 3.5 ed210e3e4a5b 10 months ago 690 kB
I'll use the httpd image for this demonstration. In the CREATED column, Podman reports that the image with the latest tag was created six weeks ago. You can get the image history to check what was done to this image when it was created:
$ podman image history httpd
ID CREATED CREATED BY SIZE COMMENT
ea28e1b82f31 6 weeks ago /bin/sh -c #(nop) CMD ["httpd-foreground"] 0 B
<missing> 6 weeks ago /bin/sh -c #(nop) EXPOSE 80 0 B
<missing> 6 weeks ago /bin/sh -c #(nop) COPY file:c432ff61c4993e... 3.58 kB
<missing> 6 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGWINCH 0 B
<missing> 6 weeks ago /bin/sh -c set -eux; savedAptMark="$(apt... 61 MB
<missing> 6 weeks ago /bin/sh -c #(nop) ENV HTTPD_PATCHES= 0 B
<missing> 6 weeks ago /bin/sh -c #(nop) ENV HTTPD_SHA256=20e01d... 0 B
<missing> 6 weeks ago /bin/sh -c #(nop) ENV HTTPD_VERSION=2.4.51 0 B
<missing> 6 weeks ago /bin/sh -c set -eux; apt-get update; apt... 2.69 MB
<missing> 6 weeks ago /bin/sh -c #(nop) WORKDIR /usr/local/apache2 0 B
<missing> 6 weeks ago /bin/sh -c mkdir -p "$HTTPD_PREFIX" && ch... 3.07 kB
<missing> 6 weeks ago /bin/sh -c #(nop) ENV PATH=/usr/local/apa... 0 B
<missing> 6 weeks ago /bin/sh -c #(nop) ENV HTTPD_PREFIX=/usr/l... 0 B
<missing> 6 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0 B
<missing> 6 weeks ago /bin/sh -c #(nop) ADD file:ece5ff85ca549f0... 83.9 MB
Pay attention to the HTTPD_VERSION=2.4.51 environment variable. To get more detailed information about this image, view it using the inspect
subcommand. The output is very verbose, so I've abbreviated it here:
$ podman image inspect httpd
[
{
"Id": "ea28e1b82f314092abd3f90a69e57d6ccf506382821ee0b8d9b48c3e47440c1f",
"Digest": "sha256:fba8a9f4290180ceee5c74638bb85ff21fd15961e6fdfa4def48e18820512bb1",
"RepoTags": [
"docker.io/library/httpd:latest"
],
"RepoDigests": [ "docker.io/library/httpd@sha256:24d492e04f02881adcc1d7543b0251754a2be6a24c75aae7a008fdae767b7337", "docker.io/library/httpd@sha256:fba8a9f4290180ceee5c74638bb85ff21fd15961e6fdfa4def48e18820512bb1"],
"Parent": "",
"Comment": "",
"Created": "2021-12-02T10:03:55.933654778Z",
"Config": {
"ExposedPorts": {
"80/tcp": {}
},
"Env": [
"PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HTTPD_PREFIX=/usr/local/apache2", "HTTPD_VERSION=2.4.51",
[…]
"Version": "20.10.7",
"Author": "",
"Architecture": "amd64",
"Os": "linux",
"Size": 147627312,
"VirtualSize": 147627312,
"GraphDriver": {
"Name": "overlay",
"Data": {
"LowerDir": "/home/localuser/.local/share/containers/storage/overlay/e20054c1032fd3c5f8d8b35d8c75b806d8f813c90621b8304d543c7edf26b2f6/diff:/home/localuser/.local/share/containers/storage/overlay/1121e686efcde8973c70358a33725d8e9616f13eab864334568ee5aea0578295/diff:/home/localuser/.local/share/containers/storage/overlay/
[...]
Next, proceed with an image update.
[ Learn more about moving legacy applications to containers and Kubernetes. ]
Manually update container images
To update an image, run the same command used to pull an image, podman pull
. Its syntax is:
podman pull [options] IMAGE [IMAGE...]
To run a specific image version, set the desired image tag. I will run the latest version for the httpd image for this demonstration, so Podman pulls the newest httpd version using the latest tag.
If you don't specify any tag, Podman pulls the image using the latest tag by default:
$ podman pull docker.io/library/httpd:latest
Trying to pull docker.io/library/httpd:latest...
Getting image source signatures
[...]
Copying blob 67283bbdd4a0 done
Copying config dabbfbe0c5 done
Writing manifest to image destination
Storing signatures
dabbfbe0c57b6e5cd4bc089818d3f664acfad496dc741c9a501e72d15e803b34
Now, when you check your pulled images again, you'll see the httpd image has changed its ID, and the CREATE column shows that it was created "4 weeks ago." That means this newly pulled image has two weeks of update differences from the previous version:
$ podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/httpd latest dabbfbe0c57b 4 weeks ago 148 MB
docker.io/library/wordpress latest 054741915cf1 6 weeks ago 629 MB
docker.io/library/mysql latest bbf6571db497 6 weeks ago 521 MB
<none> <none> ea28e1b82f31 6 weeks ago 148 MB
k8s.gcr.io/pause 3.5 ed210e3e4a5b 10 months ago 690 kB
But what has changed between one image and another? Check the image history to find out:
$ podman image history httpd
ID CREATED CREATED BY SIZE COMMENT
dabbfbe0c57b 4 weeks ago /bin/sh -c #(nop) CMD ["httpd-foreground"] 0 B
<missing> 4 weeks ago /bin/sh -c #(nop) EXPOSE 80 0 B
<missing> 4 weeks ago /bin/sh -c #(nop) COPY file:c432ff61c4993e... 3.58 kB
<missing> 4 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGWINCH 0 B
<missing> 4 weeks ago /bin/sh -c set -eux; savedAptMark="$(apt... 61.1 MB
[...]
<missing> 4 weeks ago /bin/sh -c #(nop) ENV HTTPD_PREFIX=/usr/l... 0 B
<missing> 4 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0 B
<missing> 4 weeks ago /bin/sh -c #(nop) ADD file:09675d11695f65c... 83.9 MB
Remember that HTTPD_VERSION=2.4.51 environment variable that I asked you to pay attention to? You can see that it was changed in this updated image to HTTPD_VERSION=2.4.52, which means that Apache was updated between versions.
But this updated image was not used by any running container. What happens when I update the image of a running container? Check it out.
Manually apply image updates to a running container
I'll use the same httpd image pulled from the docker.io registry as above. I'll run it as a rootfull container to make use of the older image again, since I pulled it for the root user before. Here is the older pulled image:
$ sudo podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/wordpress latest 054741915cf1 6 weeks ago 629 MB
docker.io/library/mysql latest bbf6571db497 6 weeks ago 521 MB
docker.io/library/httpd latest ea28e1b82f31 6 weeks ago 148 MB
registry.access.redhat.com/ubi8/pause latest 20b34168e325 2 months ago 3.49 MB
k8s.gcr.io/pause 3.5 ed210e3e4a5b 10 months ago 690 kB
Here is the running rootfull container that uses the older image:
$ sudo podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b85600da6d86 docker.io/library/httpd:latest httpd-foreground 4 min ago Up 3 minutes ago 0.0.0.0:8081->80/tcp httpd
A simple curl
to the running container webserver shows the Apache version provided by this image:
$ sudo curl -v http://localhost:8081
* Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
> GET / HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Tue, 18 Jan 2022 18:00:14 GMT
< Server: Apache/2.4.51 (Unix)
< Last-Modified: Tue, 07 Dec 2021 21:29:58 GMT
< ETag: "74-5d295133b0ae6"
< Accept-Ranges: bytes
< Content-Length: 116
< Content-Type: text/html
<
<html>
<header>
<title>Enable SysAdmin</title>
</header>
<body>
<p>Hello World!</p>
</body>
</html>
* Connection #0 to host localhost left intact
The Server: Apache/2.4.51 (Unix) output shows the same version as in the HTTPD_VERSION=2.4.51 environment variable for this image, proving that it is still running with the old image. I'll pull the latest image version again while the container remains running:
$ sudo podman pull docker.io/library/httpd:latest
Trying to pull docker.io/library/httpd:latest...
Getting image source signatures
Copying blob 41c22baa66ec done
[...]
Copying blob d982c879c57e done
Copying config dabbfbe0c5 done
Writing manifest to image destination
Storing signatures
dabbfbe0c57b6e5cd4bc089818d3f664acfad496dc741c9a501e72d15e803b34
In the UP column, you can see that the container didn't stop at any time, which is good because the webserver continued to provide its services:
$ sudo podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b85600da6d86 docker.io/library/httpd:latest httpd-foreground 4 minutes ago Up 4 minutes ago 0.0.0.0:8081->80/tcp httpd
Verify that the httpd image was updated, changed its IMAGE ID, and shows in the CREATED column that it was created "4 weeks ago." This means I now have the most up-to-date image version:
$ sudo podman image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/httpd latest dabbfbe0c57b 4 weeks ago 148 MB
docker.io/library/wordpress latest 054741915cf1 6 weeks ago 629 MB
docker.io/library/mysql latest bbf6571db497 6 weeks ago 521 MB
<none> <none> ea28e1b82f31 6 weeks ago 148 MB
registry.access.redhat.com/ubi8/pause latest 20b34168e325 2 months ago 3.49 MB
k8s.gcr.io/pause 3.5 ed210e3e4a5b 10 months ago 690 kB
But when I run a simple curl
against the running container again, I see the Apache version didn’t change at all:
$ sudo curl -v http://localhost:8081
* Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
> GET / HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Tue, 18 Jan 2022 18:04:12 GMT
< Server: Apache/2.4.51 (Unix)
< Last-Modified: Tue, 07 Dec 2021 21:29:58 GMT
< ETag: "74-5d295133b0ae6"
< Accept-Ranges: bytes
< Content-Length: 116
< Content-Type: text/html
<
<html>
<header>
<title>Enable SysAdmin</title>
</header>
<body>
<p>Hello World!</p>
</body>
</html>
* Connection #0 to host localhost left intact
[ Learn more about Red Hat OpenShift Container Platform. ]
When inspecting the running httpd container, it's possible to see that it is still mapping the HTTPD_VERSION=2.4.51 environment variable, which explains why it keeps using the Apache 2.4.51 version:
$ sudo podman inspect httpd --format "{{.Image}} {{.ImageName}} {{.Config.Env}}"
ea28e1b82f314092abd3f90a69e57d6ccf506382821ee0b8d9b48c3e47440c1f docker.io/library/httpd:latest [PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin TERM=xterm container=podman HTTPD_PREFIX=/usr/local/apache2 HTTPD_VERSION=2.4.51 HTTPD_SHA256=20e01d81fecf077690a4439e3969a9b22a09a8d43c525356e863407741b838f4 HTTPD_PATCHES= HOME=/root HOSTNAME=b85600da6d86]
That happens because simply pulling and updating container images won't automatically update running containers that use these images. That's a different step. To manually make a running container use the updated image, stop the container and start it again. I created the create_web.sh
script in this example in the first article of this series:
$ sudo podman stop httpd
httpd
$ sudo podman rm -a
b85600da6d86cdd9cce0edf782025718de4e3fa9c3203005c579418ec9c99737
$ sudo ./create_web.sh
7b932bbe6367b2af96d2d7e4dc059d56873737d1e4b1c343912e10574f6ce8cc
The container is now running again, and it's using the updated image:
$ sudo podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b932bbe6367 docker.io/library/httpd:latest httpd-foreground 5 seconds ago Up 4 seconds ago 0.0.0.0:8081->80/tcp httpd
To verify that it’s true, check the newly running container for the HTTPD_VERSION environment variable:
$ sudo podman inspect httpd --format "{{.Image}} {{.ImageName}} {{.Config.Env}}"
dabbfbe0c57b6e5cd4bc089818d3f664acfad496dc741c9a501e72d15e803b34 docker.io/library/httpd:latest [PATH=/usr/local/apache2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin TERM=xterm container=podman HTTPD_VERSION=2.4.52 HTTPD_SHA256=0127f7dc497e9983e9c51474bed75e45607f2f870a7675a86dc90af6d572f5c9 HTTPD_PATCHES= HTTPD_PREFIX=/usr/local/apache2 HOME=/root HOSTNAME=7b932bbe6367]
Jackpot! Now the container is running with the HTTPD_VERSION=2.4.52 environment variable, which means Apache should be running with this version. I'll confirm it by running curl
against it again:
$ sudo curl -v http://localhost:8081
* Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
> GET / HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Tue, 18 Jan 2022 18:23:04 GMT
< Server: Apache/2.4.52 (Unix)
< Last-Modified: Tue, 07 Dec 2021 21:29:58 GMT
< ETag: "74-5d295133b0ae6"
< Accept-Ranges: bytes
< Content-Length: 116
< Content-Type: text/html
<
<html>
<header>
<title>Enable SysAdmin</title>
</header>
<body>
<p>Hello World!</p>
</body>
</html>
* Connection #0 to host localhost left intact
As the Server: Apache/2.4.52 (Unix) field shows, the container is finally updated and running the latest httpd image version. And that's the whole process for a quick manual image update.
You might say, "This is good, but it's error-prone. Is there any automatic way to run all of this?" You bet there is! And for that, I recommend two excellent articles from Enable Sysadmin community members: Pulling podman images from a container repository and How to use auto-updates and rollbacks in Podman.
Keep things current
Keeping your container images current is essential for operating and managing a containerized environment. There are several benefits:
- It enables your applications to have the latest versions of certain packages and tools.
- It also ensures that you can make desired changes to the application at the image level.
- It improves the environment's security by keeping the images with the most recent security patches and bug fixes.
My next article will show how to specify Arch when pulling images. Stay tuned!
Alexon Oliveira
Alexon has been working as a Senior Technical Account Manager at Red Hat since 2018, working in the Customer Success organization focusing on Infrastructure and Management, Integration and Automation, Cloud Computing, and Storage Solutions. More about me