Running Podman Containers with systemd

podman containers with systemd

Looking for a container management tool that integrates seamlessly with systemd? Podman containers with systemd support allow you to easily create, run, manage, and deploy containers using the system’s own process management and networking stack, making it both more secure and simpler to use than Docker. Plus, Podman is OCI-compliant, ensuring that your containers will be portable and run smoothly on any compatible platform.

Table of Contents

Introduction

Podman is a container management tool that allows users to create, run, manage, and deploy containers. It was developed by Red Hat and is an alternative to Docker. Unlike Docker, Podman uses the system’s own process management and networking stack, which makes it more secure and easier to use. Podman also supports the OCI (Open Container Initiative) standard, which ensures that containers are portable and can be run on any OCI-compliant platform.

Popular Features

Podman has several popular features, including:

  1. Rootless Containers: Podman allows users to run containers without root privileges, which makes it more secure.
  2. Podman-compose: Podman has a built-in compose tool that allows users to define and run multi-container applications.
  3. Image Management: Podman has a built-in image management tool that allows users to search, pull, and manage container images.
  4. Network Management: Podman allows users to manage container networking using standard Linux networking tools.

System Requirements

To run Podman, you need a Linux-based operating system with the following requirements:

  1. A modern kernel that supports the cgroup v2 subsystem.
  2. Systemd version 240 or later.
  3. Root privileges or a user account with the necessary permissions.

Container Setup

Here are the steps to set up and run a container using Podman:

Search for a container image:

				
					$ podman search <image_name>
				
			

Pull the container image:

				
					$ podman pull <image_name>
				
			

Run the container:

				
					$ podman run --name <container_name> <image_name>
				
			

Check the container status:

				
					$ podman ps -a
				
			

Container Setup with Examples

In this exercise, we will review the steps in the previous section and setup an actual container running Apache web server or http.

Search for a container image

First, we search for available http images by running the following command:

podman containers with systemd

Photo by admingeek from Infotechys

Pull the container image

Next, we pull the container image and in this example, we’re going with Red Hat’s Universal Base Image version 9 (ubi9) option or the third on the list (registry.access.redhat.com/ubi9/httpd-24):

				
					$ podman pull registry.access.redhat.com/ubi9/httpd-24:latest
Trying to pull registry.access.redhat.com/ubi9/httpd-24:latest...
Getting image source signatures
Checking if image destination supports signatures
Copying blob e4f880d62b89 done
Copying blob 2a625e4afab5 done
Copying blob 4a13c0e9217d done
Copying config 870a5c4ea2 done
Writing manifest to image destination
Storing signatures
870a5c4ea287c94603765476aaacde12242265c92a3e4c63ef51b58ecac32967
				
			

Now run the podman images command. As you can see (below), the image downloaded successfully.

				
					$ podman images
REPOSITORY                               TAG    IMAGE ID     CREATED    SIZE
registry.access.redhat.com/ubi9/httpd-24 latest 870a5c4ea287 9 days ago 379 MB
				
			

Running Containers

When it comes to running containers, there are a few ways we can achieve this.

Method #1: Standard CLI

The standard method involves entering all of the necessary options for starting the container on the command line (CLI). In this example, our container will be exposed to port 8080 and we will provide a basic index.html file for illustration purposes.

Create a sample index.html file

First, let’s create a directory where we will store our web content (call it webcontent). Then, cd into that directory and create an index.html file.

				
					$ mkdir webcontent; cd webcontent
$ echo "Hello, world!" > index.html
				
			

Start container with sample file

Run the following command to start the httpd container with the sample index.html file:

				
					$ podman run -d -p 8001:8080 --name web_app1 -v ~/webcontent:/var/www/html:Z registry.access.redhat.com/ubi9/httpd-24:latest
				
			

This command creates a simple index.html file with the content “Hello, world!”

The Breakdown

This command executes a containerized web application using Podman, a container engine that runs without a daemon. Let’s break it down piece by piece:

  • podman is the command-line tool used to run, manage, and deploy containers.
  • run is the command that tells Podman to run a container.
  • -d runs the container in detached mode, meaning it runs in the background without showing the output on the terminal.
  • -p 8001:8080 publishes the container’s port 8080 to the host machine’s port 8001.
  • --name web_app1 assigns the name “web_app1” to the container.
  • -v ~/webcontent:/var/www:Z mounts the directory ~/webcontent on the host machine to the directory /var/www inside the container, with the option Z to add a security context to the mounted volume.
  • registry.access.redhat.com/ubi9/httpd-24:latest is the image to be used to create the container, in this case, the Apache HTTP Server version 2.4, built on Red Hat Universal Base Image version 9.

Overall, this command creates a containerized web application using the Apache HTTP Server image, mounts a host directory to the container, and maps the container’s port to a port on the host machine.

Verify and test container

Run the podman ps command to confirm the container is running:

				
					$ podman ps
CONTAINER ID IMAGE                                           COMMAND              CREATED        STATUS        PORTS                  NAMES
41d4b2a7499d registry.access.redhat.com/ubi9/httpd-24:latest /usr/bin/run-http... 25 minutes ago Up 25 minutes 0.0.0.0:8001->8080/tcp web_app1
				
			

You can test the container to check if HTTP is operational by running the following command (or enter the URL in your browser):

				
					$ curl http://localhost:8001
Hello World!
				
			
Podman containers with systemd: Verify the container

Photo by admingeek from Infotechys

Method #2: Using a Containerfile

In this example, we will build the same container we used in the previous section, using a Containerfile:

Create the Containerfile

Using your favorite text editor or vim, open a file called Containerfile.

				
					$ vim Containerfile
				
			

Insert (copy and paste) the following into the file, then save and quit:

				
					FROM registry.access.redhat.com/ubi9/httpd-24:latest 
COPY ./webcontent /var/www/html 
EXPOSE 8080 
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
				
			

This Containerfile performs the following actions:

  • Uses the FROM instruction to specify the base image.
  • Copies the webcontent directory from the build context to the container’s /var/www/html directory.
  • Uses the EXPOSE instruction to expose port 8080.
  • Uses the CMD instruction to start the Apache HTTP Server and run it in the foreground.

Build the container

To build the container using this Containerfile, you would run the following command:

				
					$ podman build -t web_app_image .
STEP 1/4: FROM registry.access.redhat.com/ubi9/httpd-24:latest
STEP 2/4: COPY ./webcontent /var/www/html
--> e990b32b61c
STEP 3/4: EXPOSE 8080
--> fdd3147cdbb
STEP 4/4: CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
COMMIT web_app_image
--> aaf1b76fc60
Successfully tagged localhost/web_app_image:latest
aaf1b76fc60471cd0cab9d5dfdf449f05b4727d997eee1a0c0a5acb7199ebc82
				
			
This builds an image named web_app_image using the current directory (.) as the build context (where your Containerfile is located):
				
					$ podman images
REPOSITORY              TAG    IMAGE ID     CREATED       SIZE
localhost/web_app_image latest aaf1b76fc604 5 minutes ago 379 MB
registry.access.redhat.com/ubi9/httpd-24 latest 870a5c4ea287 9 days ago 379 MB
				
			

Run the Container

You can then run the container with the following command:

				
					$ podman run -d -p 8001:8080 --name web_app1 web_app_image
				
			

This runs the container in detached mode, maps port 8080 inside the container to port 8001 on the host machine, assigns the name web_app1 to the container, and uses the web_app_image image that was built in the previous step.

NOTE: If you already have the web_app1 container running, you’ll need to stop it and remove it, in order to run the new build. Or, you can just name the container something else (e.g. web_app2) and map it to a different port (e.g. port 8002).

Running Podman Containers with Systemd

Containers can run as systemd services and in this section, we will look at how we can achieve this with our already running container from the previous (Verify and test the running container) section.

Create the systemd user

As a regular non-root user, create a systemd user under the .config directory:

				
					$ mkdir -pv .config/systemd/user
mkdir: created directory '.config/systemd'
mkdir: created directory '.config/systemd/user'
				
			

Run Podman generate systemd

Now, cd into the ‘.config/systemd/user‘ directory and run the following command to generate systemd files:

				
					$ podman generate systemd --name web_app1 --files --new
/home/admin/.config/systemd/user/container-web_app1.service
				
			

Notice the ‘container-web_app1.service‘ was generated. The –files option dumps the systemd files to your present working directory under .config/systemd/user.  The –new option indicates a new or fresh instance of the container will be run each time the command is executed. Now, let’s breakdown what’s inside that file.

				
					# container-web_app1.service
# autogenerated by Podman 4.4.0
# Fri Mar  3 17:40:55 EST 2023

[Unit]
Description=Podman container-web_app1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman run \
	--cidfile=%t/%n.ctr-id \
	--cgroups=no-conmon \
	--rm \
	--sdnotify=conmon \
	--replace \
	-d \
	-p 8001:8080 \
	--name web_app1 \
	-v /home/admin/webcontent:/var/www/html:Z registry.access.redhat.com/ubi9/httpd-24:latest
ExecStop=/usr/bin/podman stop \
	--ignore -t 10 \
	--cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
	-f \
	--ignore -t 10 \
	--cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target
				
			

Podman containers with systemd: Breakdown

The service file includes the following configurations:

  • [Unit] section: includes a description of the service, documentation reference, and dependencies.
  • Specifically, it specifies that the service wants to start after the network-online.target and requires mounts for the %t/containers directory.
  • [Service] section: specifies the environment, restart, timeout, and executable commands for the service.
  • The environment variable PODMAN_SYSTEMD_UNIT is set to %n, which is the name of the service.
  • The service is set to restart on failure and has a stop timeout of 70 seconds. The ExecStart command runs the container using Podman with specific flags and options, such as a CID file, disabling conmon cgroups, removing the container upon exit, sending notification to conmon, and mapping port 8001 on the host to port 8080 on the container.
  • It also mounts the /home/admin/webcontent directory on the host to /var/www/html in the container with the Z option, which sets the SELinux security context.
  • The ExecStop command stops the container and the ExecStopPost command removes the container forcefully.
  • The Type is set to notify, which means that the service sends a notification when it starts or stops, and the NotifyAccess is set to all, which means that all users can receive notifications.
  • [Install] section: specifies the target where the service should be installed. In this case, it is set to the default target.

Enable systemd unit files

Run this command to load the newly generated systemd unit files.

				
					$ systemctl --user daemon-reload
				
			

Now, enable the systemd container as a service like you normally do when running systemd.

				
					$ systemctl --user status container-web_app1.service
○ container-web_app1.service - Podman container-web_app1.service
Loaded: loaded (/home/admin/.config/systemd/user/container-web_app1.service; disabled; preset: disabled)
Active: inactive (dead)
Docs: man:podman-generate-systemd(1)

$ systemctl --user enable container-web_app1.service
Created symlink /home/admin/.config/systemd/user/default.target.wants/container-web_app1.service → /home/admin/.config/systemd/user/container-web_app1.service.)
				
			

Start container using systemd

Before starting the container with systemd, make sure to stop the container and verify that it’s stopped–then proceed.

				
					$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
41d4b2a7499d registry.access.redhat.com/ubi9/httpd-24:latest /usr/bin/run-http... 3 hours ago Up 3 hours 0.0.0.0:8001->8080/tcp web_app1

$ podman stop web_app1
web_app1

$ systemctl --user start container-web_app1.service
				
			

If you’ve followed all the steps as outlined correctly, you can perform a final test by rebooting your machine, logging back in, and checking to see if the container instance started automatically post reboot.

Best Practices

Here are some best practices to follow when using Podman:

  1. Use rootless containers: Running containers without root privileges is more secure.
  2. Use podman-compose: Podman-compose simplifies the process of defining and running multi-container applications.
  3. Use image registries: Hosting your own image registry ensures that your container images are secure and can be easily shared.
  4. Secure container networks: Use standard Linux networking tools to secure container networks and prevent unauthorized access.
  5. Automate container deployment: Use tools like Ansible or Kubernetes to automate container deployment and management.

Conclusion

Podman is a powerful container management tool that allows users to create, run, manage, and deploy containers. Its support for rootless containers, podman-compose, image management, and network management make it a popular alternative to Docker.

To use Podman, you need a modern Linux-based operating system with the necessary requirements. By following best practices like using rootless containers, image registries, and automating container deployment, you can make the most of Podman and ensure that your containerized applications are secure and easily managed.

Running containers as systemd services can further simplify the process of container management and deployment.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *