Bookmark this page

Deploy Containers

Objectives

Discuss container management tools for using registries to store and retrieve images, and for deploying, querying, and accessing containers.

The Podman Utility

Podman is a fully featured container engine from the container-tools meta-package to manage Open Container Initiative (OCI) containers and images. The podman utility does not use a daemon to function, and so developers do not need a privileged user account on the system to start or stop containers. Podman provides many subcommands to interact with containers and images. The following list shows subcommands that are used in this section:

Table 13.1. Podman Commands

CommandDescription
podman build Build a container image with a container file.
podman run Run a command in a new container.
podman images List images in local storage.
podman ps Print information about containers.
podman inspect Display configuration of a container, image, volume, network, or pod.
podman pull Download an image from a registry.
podman cp Copy files or directories between a container and the local file system.
podman exec Execute a command in a running container.
podman rm Remove one or more containers.
podman rmi Remove one or more locally stored images.
podman search Search a registry for an image.

For more information about each subcommand by using the man pages, append the subcommand to the podman command with a hyphen to separate the two. For example, the podman-build man page explains the use of the podman build subcommand.

To cover the topics in this lecture, imagine the following scenario.

As a system administrator, you are tasked to run a container that is based on the RHEL 8 UBI container image called python38 with the python-38 package. You are also tasked to create a container image from a container file, and to run a container called python36 from that container image. The container image that is created with the container file must have the python36:1.0 tag. Identify the differences between the two containers. Also, ensure that the installed python packages in the containers do not conflict with the installed Python version in your local machine.

Install Container Utilities

The container-tools meta-package contains required utilities to interact with containers and container images. To download, run, and compare containers on your system, you install the container-tools meta-package with the dnf install command. Use the dnf info command to view the version and contents of the container-tools package:

[root@host ~]# dnf install container-tools
...output omitted...
[user@host ~]$ dnf info container-tools
...output omitted...
Summary      : A meta-package witch container tools such as podman, buildah,
             : skopeo, etc.
License      : MIT
Description  : Latest versions of podman, buildah, skopeo, runc, conmon, CRIU,
             : Udica, etc as well as dependencies such as container-selinux
             : built and tested together, and updated.
...output omitted...

The container-tools meta-package provides the needed podman and skopeo utilities to achieve the assigned tasks.

Download a Container Image from a Registry

First, you ensure that the podman utility is configured to search and download containers from the registry.redhat.io registry. The podman info command displays configuration information of the podman utility, including the configured registries.

[user@host ~]$ podman info
...output omitted...
insecure registries:
  registries: []
registries:
  registries:
  - registry.redhat.io
  - quay.io
  - docker.io
...output omitted...

The podman search command searches for a matching name image by using the specified list of registries in the registries.conf file. By default, Podman searches in all unqualified-search registries.

Note

The unqualified-search-registries directive is a list of registries that Podman uses to search or pull an image when a not fully qualified name image such as registry.redhat.io/ubi9/python-39 is used. You can obtain more information from the containers-registries.conf(5) man page.

Depending on the Docker distribution API that is implemented with the registry, some registries might not support the search feature.

Use the podman search command to display a list of images on the configured registries that contain the python-38 package.

[user@host ~]$ podman search python-38
NAME                                          DESCRIPTION
registry.access.redhat.com/ubi7/python-38     Python 3.8 platform for building and running applications
registry.access.redhat.com/ubi8/python-38     Platform for building and running Python 3.8 applications
...output omitted...

The registry.access.redhat.com/ubi8/python-38 image seems to match the criteria for the required container.

You can use the skopeo inspect command to examine different container image formats from a local directory or a remote registry without downloading the image. This command output displays a list of the available version tags, exposed ports of the containerized application, and metadata of the container image. You use the skopeo inspect command to verify that the image contains the required python-38 package.

[user@host ~]$ skopeo inspect docker://registry.access.redhat.com/ubi8/python-38
{
    "Name": "registry.access.redhat.com/ubi8/python-38",
    "Digest": "sha256:c6e522cba2cf2b3ae4a875d5210fb94aa1e7ba71b6cebd902a4f4df73cb090b8",
    "RepoTags": [
...output omitted...
        "1-68",
        "1-77-source",
        "latest"
...output omitted...
        "name": "ubi8/python-38",
        "release": "86.1648121386",
        "summary": "Platform for building and running Python 3.8 applications",
...output omitted...

The registry.access.redhat.com/ubi8/python-38 image contains the required package and it is based on the required image. You use the podman pull command to download the selected image to the local machine. You can use the fully qualified name of the image from the preceding output to avoid ambiguity on container versions or registries.

[user@host ~]$ podman pull registry.access.redhat.com/ubi8/python-38
Trying to pull registry.access.redhat.com/ubi8/python-38:latest...
Getting image source signatures
Checking if image destination supports signatures
Copying blob c530010fb61c done
...output omitted...

Then, you use the podman images command to display the local images.

[user@host ~]$ podman images
REPOSITORY                                TAG     IMAGE ID      CREATED     SIZE
registry.access.redhat.com/ubi8/python-38 latest  a33d92f90990  1 hour ago  901 MB

Create a Container Image from a Container File

You are provided with the following container file to create the container image in the python36-app directory:

[user@host python36-app]$ cat Containerfile
FROM registry.access.redhat.com/ubi8/ubi:latest
RUN dnf install -y python36
CMD ["/bin/bash", "-c", "sleep infinity"]

The previous container file uses the registry.access.redhat.com/ubi8/ubi:latest image as the base image. The container file then installs the python36 package and runs the sleep infinity bash command to prevent the container from exiting.

Normally, a container runs a process, and then exits after that process is complete. The sleep infinity command prevents the container from exiting, because the process never completes. You can then test, develop, and debug inside the container.

After examining the container file, you use the podman build command to build the image. The syntax for the podman build command is as follows:

[user@host ~]$ podman build -t NAME:TAG DIR
NAME

Name for the new image.

TAG

Tag for the new image. If the tag is not specified, then the image is automatically tagged as latest.

DIR

Path to the working directory. The container file must be in the working directory. If the working directory is the current directory, then you designate it by a dot (.). Use the -f flag to specify a different directory from the current one.

In the following example, you use the podman build command -t option to provide the python36 name and the 1.0 tag for the new image. The container file is in the current directory.

[user@host python36-app]$ podman build -t python36:1.0 .
STEP 1/3: FROM registry.access.redhat.com/ubi8/ubi:latest
STEP 2/3: RUN dnf install -y python36
...output omitted...
STEP 3/3: CMD ["/bin/bash", "-c", "sleep infinity"]
COMMIT python36:1.0
--> 35ab820880f
Successfully tagged localhost/python36:1.0
35ab820880f1708fa310f835407ffc94cb4b4fe2506b882c162a421827b156fc

The last line of the preceding output shows the container image ID. Most Podman commands use the first 12 characters of the container image ID to refer to the container image. You can use this short ID or the name of a container or a container image as arguments for most Podman commands.

Note

If a version number is not specified in the tag, then the image is created with the :latest tag. If an image name is not specified, then the image and tag fields show the <none> string.

You use the podman images command to verify that the image is created with the defined name and tag.

[user@host ~]$ podman images
REPOSITORY                                TAG    IMAGE ID     CREATED      SIZE
localhost/python36                        1.0    35ab820880f1 3 minute ago 266 MB
registry.access.redhat.com/ubi8/python-38 latest a33d92f90990 1 hour ago   901 MB

You then use the podman inspect command to view the low-level information of the container image and verify that its content matches the requirements for the container.

[user@host ~]$ podman inspect localhost/python36:1.0
...output omitted...
               "Cmd": [
                    "/bin/bash",
                    "-c",
                    "sleep infinity"
               ],
...output omitted...
               {
                    "created": "2022-04-18T19:47:52.708227513Z",
                    "created_by": "/bin/sh -c dnf install -y python36",
                    "comment": "FROM registry.access.redhat.com/ubi8/ubi:latest"
               },
...output omitted...

The output of the podman inspect command shows the registry.access.redhat.com/ubi8/ubi:latest base image, the dnf command to install the python36 package, and the sleep infinity bash command that is executed at runtime to prevent the container from exiting.

Note

The podman inspect command output varies from the python-38 image to the python36 image, because you created the /python36 image by adding a layer with changes to the existing registry.access.redhat.com/ubi8/ubi:latest base image, whereas the python-38 image is itself a base image.

Run Containers

Now that you have the required container images, you can use them to run containers. A container can be in one of the following states:

Created

A container that is created but is not started.

Running

A container that is running with its processes.

Stopped

A container with its processes stopped.

Paused

A container with its processes paused. Not supported for rootless containers.

Deleted

A container with its processes in a dead state.

The podman ps command lists the running containers on the system. Use the podman ps -a command to view all containers (that are created, stopped, paused, or running) in the machine.

You use the podman create command to create the container to run later. To create the container, you use the ID of the localhost/python36 container image. You also use the --name option to set a name to identify the container. The output of the command is the long ID of the container.

[user@host ~]$ podman create --name python36 dd6ca291f097
c54c7ee281581c198cb96b07d78a0f94be083ae94dacbae69c05bd8cd354bbec

Note

If you do not set a name for the container with the podman create or podman run command with the --name option, then the podman utility assigns a random name to the container.

You then use the podman ps and podman ps -a commands to verify that the container is created but is not started. You can see information about the python36 container, such as the short ID, name, and the status of the container, the command that the container runs when started, and the image to create the container.

[user@host ~]$ podman create --name python36 dd6ca291f097
c54c7ee281581c198cb96b07d78a0f94be083ae94dacbae69c05bd8cd354bbec
[user@host ~]$ podman ps
CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
[user@host ~]$ podman ps -a
CONTAINER ID  IMAGE                   COMMAND               CREATED        STATUS      PORTS       NAMES
c54c7ee28158  localhost/python36:1.0  /bin/bash -c slee...  5 seconds ago  Created                 python36

Now that you verified that the container is created correctly, you decide to start the container, so you run the podman start command. You can use the name or the container ID to start the container. The output of this command is the name of the container.

[user@host ~]$ podman start python36
python36
[user@host ~]$ podman ps
CONTAINER ID  IMAGE                   COMMAND               CREATED        STATUS            PORTS       NAMES
c54c7ee28158  localhost/python36:1.0  /bin/bash -c slee...  6 minutes ago  Up 3 seconds ago              python36

Run a Container from a Remote Repository

You can use the podman run command to create and run the container in one step. The podman run command runs a process inside a container, and this process starts the new container.

You use the podman run command -d option to run a container in detached mode, which runs the container in the background instead of in the foreground of the session. In the example of the python36 container, you do not need to provide a command for the container to run, because the sleep infinity command was already provided in the container file that created the image for that container.

To create the python38 container, you decide to use the podman run command and to refer to the registry.access.redhat.com/ubi8/python-38 image. You also decide to use the sleep infinity command to prevent the container from exiting.

[user@host ~]$ podman run -d --name python38 \
registry.access.redhat.com/ubi8/python-38 \
sleep infinity

a60f71a1dc1b997f5ef244aaed232e5de71dd1e8a2565428ccfebde73a2f9462
[user@host ~]$ podman ps
CONTAINER ID  IMAGE                                             COMMAND               CREATED         STATUS             PORTS       NAMES
c54c7ee28158  localhost/python36:1.0                            /bin/bash -c slee...  37 minutes ago  Up 30 minutes ago              python36
a60f71a1dc1b  registry.access.redhat.com/ubi8/python-38:latest  sleep infinity        32 seconds ago  Up 33 seconds ago              python38

Important

If you run a container by using the fully qualified image name, but the image is not yet stored locally, then the podman run command first pulls the image from the registry and then runs.

Environment Isolation in Containers

Containers isolate the environment of an application. Each container has its own file system, networking, and processes. You can notice the isolation feature when you look at the output of the ps command and compare it between the host machine and a running container.

You first run the ps -ax command on the local machine, and the command returns an expected result with many processes.

[root@host ~]# ps -ax
    PID TTY      STAT   TIME COMMAND
      1 ?        Ss     0:01 /usr/lib/systemd/systemd --switched-root --system --deseriali
      2 ?        S      0:00 [kthreadd]
      3 ?        I<     0:00 [rcu_gp]
      4 ?        I<     0:00 [rcu_par_gp]
...output omitted...

The podman exec command executes a command inside a running container. The command takes the name or ID of the container as the first argument and the following arguments as commands to run inside the container. You use the podman exec command to view the running processes in the python36 container. The output from the ps -ax command looks different, because it is running different processes from the local machine.

[student@host ~]$ podman exec python38 ps -ax
    PID TTY      STAT   TIME COMMAND
      1 ?        Ss     0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep infinity
      7 ?        R      0:00 ps -ax

You can use the sh -c command to encapsulate the command to execute in the container. In the following example, the ps -ax > /tmp/process-data.log command is interpreted as the command to be executed in the container. If you do not encapsulate the command, then Podman might interpret the greater-than character (>) as part of the podman command instead of as an argument to the podman exec option.

[student@host ~]$ podman exec python38 sh -c 'ps -ax > /tmp/process-data.log'
    PID TTY      STAT   TIME COMMAND
      1 ?        Ss     0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep infinity
      7 ?        R      0:00 ps -ax

You decide to compare the installed python version on the host system with the installed python version on the containers.

[user@host ~]$ python3 --version
Python 3.9.10
[user@host ~]$ podman exec python36 python3 --version
Python 3.6.8
[user@host ~]$ podman exec python38 python3 --version
Python 3.8.8

File-system Isolation in Containers

Developers can use the file-system isolation feature to write and test applications for different versions of programming languages without the need to use multiple physical or virtual machines.

You create a simple bash script that displays hello world on the terminal in the /tmp directory.

[user@host ~]$ echo "echo 'hello world'" > /tmp/hello.sh

The /tmp/hello.sh file exists on the host machine, and does not exist on the file system inside the containers. If you try to use the podman exec to execute the script, then it gives an error, because the /tmp/hello.sh script does not exist in the container.

[user@host ~]$ stat /tmp/hello.sh
  File: /tmp/hello.sh
  Size: 19        	Blocks: 8          IO Block: 4096   regular file
Device: fc04h/64516d	Inode: 17655599    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/ user)   Gid: ( 1000/ user)
Context: unconfined_u:object_r:user_tmp_t:s0
Access: 2022-04-19 21:47:40.101601412 -0400
Modify: 2022-04-19 21:47:36.497558132 -0400
Change: 2022-04-19 21:47:36.497558132 -0400
 Birth: 2022-04-19 21:45:24.785976758 -0400

[user@host ~]$ podman exec python38 stat /tmp/hello.sh
stat: cannot statx '/tmp/hello.sh': No such file or directory

The podman cp command copies files and directories between host and container file systems. You can copy the /tmp/hello.sh file to the python38 container with the podman cp command.

[user@host ~]$ podman cp /tmp/hello.sh python38:/tmp/hello.sh

[user@host ~]$ podman exec python38 stat /tmp/hello.sh
  File: /tmp/hello.sh
  Size: 19        	Blocks: 8          IO Block: 4096   regular file
Device: 3bh/59d	Inode: 12280058    Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1001/ default)   Gid: (    0/    root)
Access: 2022-04-20 01:47:36.000000000 +0000
Modify: 2022-04-20 01:47:36.000000000 +0000
Change: 2022-04-20 02:02:04.732982187 +0000
 Birth: 2022-04-20 02:02:04.732982187 +0000

After the script is copied to the container file system, it can be executed from within the container.

[user@host ~]$ podman exec python38 bash /tmp/hello.sh
hello world

Remove Containers and Images

You can remove containers and images by using the podman rm and podman rmi commands, respectively. Before you remove a container image, any existing running containers from that image must be removed.

You decide to remove the python38 container and its related image. If you try to remove the registry.access.redhat.com/ubi8/python-38 image when the python38 container exists, then it gives an error.

[user@host ~]$ podman rmi registry.access.redhat.com/ubi8/python-38
Error: Image used by a60f71a1dc1b997f5ef244aaed232e5de71dd1e8a2565428ccfebde73a2f9462: image is in use by a container

You must stop the container before you can remove it. To stop a container, use the podman stop command.

[user@host ~]$ podman stop python38

After you stop the container, use the podman rm command to remove the container.

[user@host ~]$ podman rm python38
a60f71a1dc1b997f5ef244aaed232e5de71dd1e8a2565428ccfebde73a2f9462

When the container no longer exists, you can remove the registry.access.redhat.com/ubi8/python-38 image with the podman rmi command.

[user@host ~]$ podman rmi registry.access.redhat.com/ubi8/python-38
Untagged: registry.access.redhat.com/ubi8/python-38:latest
Deleted: a33d92f90990c9b1bad9aa98fe017e48f30c711b49527dcc797135352ea57d12

 

References

podman(1), podman-build(1), podman-cp(1), podman-exec(1), podman-images(1), podman-inspect(1), podman-ps(1), podman-pull(1), podman-rm(1), podman-rmi(1), podman-run(1), podman-search(1), and podman-stop(1) man pages

For more information, refer to the Starting with Containers chapter in the Building, Running, and Managing Linux Containers on Red Hat Enterprise Linux 9 guide at https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/building_running_and_managing_containers/index#starting-with-containers_building-running-and-managing-containers

Revision: rh134-9.0-fa57cbe