Page
Container images details

This lesson is focused on understanding how container images are built, tagged, organized, and leveraged to deliver software in a range of use cases.
In order to get full benefit from taking this lesson, you need:
- To complete the previous lesson, Containers 101.
- The GitHub command-line interface.
- A copy of the GitHub repository, https://github.com/redhat-developer/demos/intro-both.
In this lesson, you will:
- Internalize the difference between base images and multi-layered images.
- Understand the full URL of an image/repository.
- Command a complete understanding of what's inside a container image.
Image layers and repositories: Inspect base images, layers, and histories
The goal of this lesson is to understand the difference between base images and multi-layered images (repositories). Also, we'll try to understand the difference between an image layer and a repository.
Clone the GitHub repository and move it into the resulting directory, using the following two commands:
git clone https://github.com/redhat-developer-demos/intro-both cd intro-both
Let's take a look at some base images. We will use the
podman history
command to inspect all of the layers in these repositories. Notice that these container images have no parent layers. These are base images, and they are designed to be built upon. First, let's look at the fullubi9
base image by running the following command:podman pull registry.access.redhat.com/ubi9:9.6-1747219013 podman history registry.access.redhat.com/ubi9:9.6-1747219013
By the way, you can find this image at the Red Hat Ecosystem Catalog.
Now, let's take a look at the minimal base image, which is part of the Red Hat Universal Base Image (UBI) collection. Notice that it's quite a bit smaller.
podman pull registry.access.redhat.com/ubi9/ubi-minimal:latest podman history registry.access.redhat.com/ubi9/ubi-minimal:latest
Use a simple Dockerfile we created for you to build a multi-layered image:
podman build -t ubi9-change -f Dockerfile
Now view the image by running the following command:
podman images
Do you see the newly-created
ubi9-change
tag? Can you see all of the layers that make up the new image/repository/tag? This command even shows a short summary of the commands run in each layer. This is very convenient for exploring how an image was made.To see these layers, run the following command:
podman history ubi9-change
Note
The first image ID (bottom) listed in the output matches the registry.access.redhat.com/ubi9/ubi image. Remember, it is important to build on a trusted base image from a trusted source (provenance or chain of custody). Container repositories are made up of layers, but we often refer to them simply as "container images" or containers. When architecting systems, we must be precise with our language or else we could cause confusion to our end users.
Image URLs: Map business requirements to the URL, namespace, repository, and tag
Now we are going to inspect the different parts of the URL that you pull.
The most common command is similar to this command, where only the repository name is specified:
podman inspect ubi9/ubi
But what's really going on? Well, similar to DNS, the podman command line is resolving the full URL and tag of the repository on the registry server. The following command will give you the same results:
podman inspect registry.access.redhat.com/ubi9/ubi:latest
You can run any of the following commands and get the same results:
podman inspect registry.access.redhat.com/ubi9/ubi:latest
podman inspect registry.access.redhat.com/ubi9/ubi
podman inspect ubi9/ubi:latest
podman inspect ubi9/ubi
Let's build another image, but give it a tag other than latest
:
podman build -t ubi9:test -f Dockerfile
Now there is another tag.
podman images
Try the resolution trick again. What happened?
podman inspect ubi9
It failed, but why? Try again with a complete URL:
podman inspect ubi9:test
Notice that Podman resolves container images, similar to DNS resolution. Each container engine is different, and Docker will actually resolve some things podman doesn't because there is no standard on how image URIs are resolved. If you test long enough, you will find many other caveats to namespace, repository, and tag resolution.
Generally, it's best to always use the full URL, specifying the server, namespace, repository, and tag. Remember this when building scripts. Containers seem deceptively easy, but you need to pay attention to details.
Image internals: Inspect the libraries, interpreters, and operating system components in a container image
In this exercise, we will take a look at what's inside the container image. Java is particularly interesting because it uses glibc, even though most people don't realize it. We will use the ldd
command to prove it, which shows you all of the libraries that a binary is linked against. When a binary is dynamically linked (libraries loaded when the binary starts), these libraries must be installed on the system or else the binary will not run.
In this example in particular, you can see that getting a JVM to run with the same behavior requires compiling and linking in the same way. Stated another way, all Java images are not created equal:
podman run -it registry.access.redhat.com/jboss-eap-7/eap70-openshift ldd -v -r /usr/lib/jvm/java-1.8.0-openjdk/jre/bin/java
Notice that dynamic scripting languages are also compiled and linked against system libraries:
podman run -it registry.access.redhat.com/ubi9/ubi ldd /usr/bin/python3
Inspecting a common tool like curl
demonstrates how many libraries you are using from the operating system.
First, start the RHEL tools container. This is a special image that Red Hat releases with all of the tools necessary for troubleshooting in a containerized environment. It's rather large, but quite convenient.
podman run -it registry.access.redhat.com/ubi9/toolbox bash
Once inside the container, take a look at all of the libraries curl
is linked against:
ldd /usr/bin/curl
Let's see what packages deliver those libraries. When there is a new CVE discovered, a new container image will need to be built to patch it:
rpm -qf /lib64/libssl.so.3
Exit the ubi9
toolbox container:
exit
It's a similar story with Apache and most other daemons and utilities that rely on libraries for security or deep hardware integration:
podman run -it registry.access.redhat.com/ubi9/httpd-24 bash
Inspect the mod_ssl Apache
module:
ldd /usr/lib64/httpd/modules/mod_ssl.so
Once again, we find a library provided by OpenSSL:
rpm -qf /usr/lib64/libcrypto.so.3
To exit the httpd24
container, run the following command:
exit
Summary
What does this all mean? Well, it means you need to be ready to rebuild all of your container images any time there is a security vulnerability in one of the libraries inside it.
It is a journey, and we are always happy to help. If you want more options, consider the following learning paths:
- Install Podman Desktop and connect it to your Developer Sandbox
- Download and install the Red Hat OpenShift CLI
- Move your Developer Sandbox objects to another cluster
The next lesson in this series looks at container engines and the Linux kernel.