There is no doubt that Docker is the most popular tool for working with containers. In fact, it has become a standard and almost synonymous with containers. Nevertheless, it is not the only solution designed to manage containers, and certainly not the most secure.
Many container engines are based on a client-server model, in which the system includes a so-called daemon running in the background, acting as an intermediary between the user and the containers. Unfortunately, in order to function properly, many such daemons - one of which is Docker's daemon, dockerd - require root user privileges, and this can be considered the biggest problem regarding Docker. (It should be added at this point that quite recently an option appeared in Docker that allows the dockerd daemon to run without root privileges.)
The root user has access to the entire system, is given full privileges on the system and can do literally anything on the system, e.g. create and delete system files, install software, run services and so on. As a result, a potential vulnerability in Docker's security can open an attacker's way into the entire system, since the root user owns the dockerd process. A similar danger is associated with a vulnerability-containing container image - since it is run by a process running with root privileges, an attacker can gain access to any component of the system through such an image. Admittedly, it is recommended to change the container user, but this is often forgotten and the user remains root.
Meet podman, which is an open source tool developed by Red Hat engineers for managing OCI ( open container initiative) compliant containers. With podman, you can easily find, create, run, share and deploy applications based on containers or OCI container images.
Podman does not require a daemon for proper operation, and all operations are done via the shell command, podman, which uses the libpod library to manage the entire container ecosystem. It is worth mentioning that podman interacts with Buildah and Skopeo tools, allowing you to customize your container environment.
The biggest advantage of podman is the ability to run without root user privileges. As a result, the container will not receive any additional privileges, and you don't need to use the sudo mechanism and enter a password when running it. Of course, it is possible to run containers from the root user or another privileged system user.
Another advantage of the sub-mana approach is that containers can be run by unprivileged users, which is important in multi-user environments and HPC environments, i.e. high-performance computing systems. This has made the creation, use and management of containers accessible to ordinary users, which in turn means more convenience for them and less danger for the system.
The daemon-less architecture is one of the biggest advantages of subman. If the container is "cracked," the attacker will not have full control over the system anyway, because an account with root user privileges was not used to run the container. This is important from the perspective of ensuring system security. Another strong point of the podman is that it works with the SELinux architecture, which provides greater control over the resources that containers access.
Despite its undoubted advantages, the subman architecture also has some disadvantages. First of all, it means the inability to share container images between users. In addition, attaching ports with numbers up to and including 1024 requires root privileges, so running podman without using the sudo command eliminates the possibility of using said ports. In this article you will learn the basics of podman. If you have experience with Docker, you will have no problem using the podman tool, which can be considered a direct replacement for Docker. The two container management systems are so compatible with each other that you can easily define a podman as an alias for Docker. In the Bash shell, the following command is used for this:
1$ alias docker=podman
If you create this alias, then you can use Docker commands when working with podman - they are identical.
The podman tool is available for various Linux distributions and on Mac and Windows platforms. Although the podman service works only on Linux, but thanks to virtual machine-based solutions it is also available for Mac and Windows - in the latter it is based on the windows system for linux(WSL) functionality. If you are using macOS and the Homebrew package manager, in order to install podman, just issue the following command:
1$ brew install podman
On systems like Fedora, CentOS and RHEL, installing podman is done with the command:
1$ dnf install podman
On the other hand, in distributions based on Debian, such as Ubuntu, to install podman, you need to issue the command:
1$ apt install podman
Working with the podman tool
Although in the examples presented here I will only use the podman command issued in the shell, but it is worth knowing that for container management the podman tool also offers a RESTful API, which provides access to podman's advanced features, such as those designed to handle pods. (A pod is simply a group of containers using the same resources, similar to Kubernetes).
Searching and retrieving containers
To search for containers, use the podman search command with an argument in the form of a search term, such as:
1$ podman search python 2NAME DESCRIPTION 3registry.fedoraproject.org/f31/python-classroom 4registry.fedoraproject.org/f31/python3 5... 6registry.access.redhat.com/ubi9/s2i-base rhcc_registry.access.redhat.com_ubi9/s2i-bas... 7docker.io/library/python Python is an interpreted, interactive, objec... 8... 9docker.io/fnndsc/python-poetry Python Poetry 10docker.io/ibmcom/python-ceilometerclient-ppc64le Docker image for python-ceilometerclient-ppc... 11quay.io/centos7/python-27-centos7 Python 2.7 available as container is a base... 12... 13quay.io/cloudfirst/python-rating-service 14quay.io/fedora/python-311
Since podman is a replacement for Docker, so it should come as no surprise that podman can use containers found in the Docker repository at docker.io. The pull command is used to download a container, and its syntax is as follows:
1$ podman pull [opcje] nazwa-obrazu[:tag]
Here the image name can be fully qualified, such as docker.io/library/python, or abbreviated, in which case in the example at hand it boils down to the word python. If you use a fully qualified name, it is written in the form shown here:
It is possible to download an image tagged with a specific tag. In this case, the image name should be followed by a colon (without any spaces) and the tag name after it. Suppose you want to download a tagged 3-slim smaller version of a container containing Python version 3.x. Then the command is of the form:
1_(nazwa skrócona)_ 2$ podman pull python:3-slim 3_(użyta w pełni kwalifikowana nazwa obrazu)_ 4$ podman pull docker.io/library/python:3-slim
The effect of executing any of these commands is to download the desired image from the official Docker container repository. By default, the podman tool checks not only the listed repository, but also others, such as Quay.io. Therefore, it is recommended to specify the full name of the image to be downloaded. If you want to download Python from the Quay.io repository, the syntax of the pull command does not change:
1$ podman pull quay.io/fedora/python-311
Some images have been downloaded this way. To see which ones are available locally, use the podman images command:
1$ podman images 2REPOSITORY TAG IMAGE ID CREATED SIZE 3quay.io/fedora/python-311 latest 13fa6ebca8f7 4 days ago 974 MB 4docker.io/library/python 3-slim 9012e93183ab 4 days ago 134 MB
Running a container
Now that we have the images, you can prepare the container and launch it. Similar to Docker, podman also uses the run command to start the container.
1$ podman run --rm -it python:slim 2Resolved "python" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf) 3Trying to pull docker.io/library/python:slim... 4Getting image source signatures 5Copying blob 69038a8b17e6 skipped: already exists 6Copying blob 5fa7ca705967 skipped: already exists 7Copying blob be80bd1fa6e1 skipped: already exists 8Copying blob a82a83a9446e skipped: already exists 9Copying blob 8740c948ffd4 skipped: already exists 10Copying config 9012e93183 done 11Writing manifest to image destination 12Storing signatures 13Python 3.11.1 (main, Jan 17 2023, 23:45:25) [GCC 10.2.1 20210110] on linux 14Type "help", "copyright", "credits" or "license" for more information. 15>>> credits 16 Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands 17 for supporting Python development. See www.python.org for more information. 18>>> exit() 19$
This way, using the podman tool, we have a working Docker container with a Python interpreter running, in which Python commands can be issued. The --rm option automatically removes the container when you're done with it, while the -it option means working with the container in interactive mode. Exactly the same options are used in Docker (remember that podman is a direct replacement for Docker?) In a nutshell, the container's interactive mode means that data entered in the shell used to work with podman is passed to the container's standard input. In turn, the output generated by the container is displayed in the shell in which the podman command was issued. We do not always want to work directly in the container, but use it, for example, to run a service such as a web server. In such a situation, the container should run in the background. Running a container running in the background is possible with the -d option. In the following example, a web server container will be downloaded from the Docker repository, which will then run in the background.
1$ podman pull docker.io/library/httpd 2Trying to pull docker.io/library/httpd:latest... 3Getting image source signatures 4Copying blob 70698c657149 done 5Copying blob ec2ee6bdcb58 done 6Copying blob 00df85967755 done 7Copying blob 8740c948ffd4 skipped: already exists 8Copying blob 8b4456c99d44 done 9Copying config 6e794a4832 done 10Writing manifest to image destination 11Storing signatures 126e794a4832588ca05865700da59a3d333e7daaaf0544619e7f326eed7e72c903 13$ podman images 14REPOSITORY TAG IMAGE ID CREATED SIZE 15docker.io/library/httpd latest 6e794a483258 4 days ago 149 MB 16quay.io/fedora/python-311 latest 13fa6ebca8f7 4 days ago 974 MB 17docker.io/library/python slim 9012e93183ab 4 days ago 134 MB 18docker.io/library/python 3-slim 9012e93183ab 4 days ago 134 MB 19$ podman run -d httpd 204a2a2fc312f54ad302366976836f4bb9e7848f6a3e1bf8fcd6d1803d1cbf4ff6
The container was run in the background, so the only visible result on the screen of executing the podman run command is the displayed container ID. You can confirm that the container is running in the background using the podman ps command.
1$ podman ps 2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 34a2a2fc312f5 docker.io/library/httpd:latest httpd-foreground 6 seconds ago Up 6 seconds ago elated_fermat 4$
Although the container is running, but no IP address has been assigned to it, so it is difficult to access the functionality offered by the web server. As you can see in the example in question, the podman command was issued without using the sudo mechanism, and thus the container's permissions are not raised. Earlier I mentioned that the use of ports with numbers up to and including 1024 requires root privileges, and the web server listens to requests on port 80. In view of this, will our server not perform its role? No worries, just map the container's ports and the web server will work as expected. Port mapping is configured using the -p option, a modified version of the podman run command is as follows:
1$ podman run -dt -p 8080:80/tcp docker.io/library/httpd 2d90b6bfad6d9b18cd9830761cca0b3fe6923ed84109383aee86a3089e50ea0a4
The operation of the -p option is to connect the external port - that is, the port on the host where the container is running - to the container's internal port. In this case, using port 8080 on the local computer, we access port 80 on the running container. Thus, the mapping avoided the need to elevate the container's permissions, while still allowing the web server in the container to listen for requests on port 80. To find out, for example, just launch a web browser and go to http://localhost:8080. When you type in the address, a message appears: IT WORKS!
Alternatively, you can use the curl command:
1$ curl http://localhost:8080 2<html><body><h1>It works!</h1></body></html>
The content shown earlier in the Web browser window was displayed in the shell by the curl command. Our web server in the subman container is working! A list of all running containers can be displayed using the podman ps command mentioned earlier.
1$ podman ps 2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3d90b6bfad6d9 docker.io/library/httpd:latest httpd-foreground About a minute ago Up About a minute ago 0.0.0.0:8080->80/tcp unruffled_napier
The output of this command contains various details about the running containers, such as the container's shortened ID, the image used to open it, the mapped ports, etc.
Stopping and deleting a container
When you have finished working with a container, you need to stop it. The following command is used for this purpose:
1podman stop [nazwa-kontenera] lub [identyfikator-kontenera]
Since no name has been given to the container in this example, use identifier. There is also a convenient -l option to mark the last container used. Therefore, the two commands presented here will stop our container with the web server running:
1$ podman stop d90b6bfad6d9
1$ podman stop -l
With the podman ps command, we confirm that the container is stopped:
1$ podman ps 2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3$
If you didn't use the --rm option during container startup that causes the container to be automatically deleted when you finish working with it, you can delete the recently stopped container by issuing the podman rm -l command.
Podman is a daemon-less container engine with capabilities not inferior to those offered by Docker. Its biggest advantage is the ability to run containers with standard permissions, which provides more security to the host system. Of course, if necessary, a container can be run with root privileges. Thanks to its full compatibility with Docker, the podman can be used to work with Testcontainers. In most cases, this will not require any special configuration.