Red Hat Certified System Administrator (RHCSA) #14 Managing containers: Podman, systemd integration (quadlet)
If the 21-post RHEL hands-on track had you working directly with user management, storage, systemd, and SELinux, the natural next step is putting that intuition to the test in a certification exam. This post covers the last pillar of the RHCSA exam objectives: containers. RHEL’s container engine is not Docker but Podman, and RHCSA expects you to go beyond simply launching a container — you must be able to register that container with systemd so it starts automatically at boot, end to end, by hand.
This area doesn’t involve many commands, but two pitfalls decide whether you pass: rootless execution and systemd integration via quadlet. Both are easy to trip over, so in this post we’ll nail the exact procedure by typing it out ourselves.
Why Podman #
Since RHEL 8, Podman has been the default container engine in place of Docker. Podman is nearly command-compatible with Docker, so dropping podman in where you’d write docker mostly just works. But the real reasons RHCSA chose Podman are twofold.
- There’s no daemon. Docker sends commands to a
dockerddaemon running as root, whereas Podman launches container processes directly without any daemon. That makes managing containers with systemd a natural fit. - It supports rootless properly. A regular user can launch their own containers without root. RHCSA usually asks you to run a rootless container as a specific regular user, so this matters.
First, let’s check that the package is installed.
# Install Podman (usually included by default on RHEL 9)
sudo dnf install -y container-tools
# Check the version
podman --versionRegistry login and working with images #
The official images RHEL provides live in the Red Hat registry. For registries that require authentication, log in first.
# Log in to the Red Hat registry (enter your account credentials)
podman login registry.access.redhat.com
# Login info is stored in a per-user authentication file
# $XDG_RUNTIME_DIR/containers/auth.jsonAfter logging in, search for and pull an image.
# Search for an image
podman search ubi9
# Pull an image (ubi9 from registry.access.redhat.com)
podman pull registry.access.redhat.com/ubi9/ubi
# List images pulled locally
podman imagespodman search finds images in the configured registries, and podman pull stores the pulled image locally. On the exam it’s safer to specify the image name with the full registry path. A short name may pull the wrong image depending on the registry search order.
Running containers and basic commands #
Running a container in the background while mapping ports, volumes, and environment variables is the heart of the RHCSA container objective.
# Run in the background (-d), map a port (-p), assign a name (--name)
podman run -d --name web -p 8080:80 \
registry.access.redhat.com/ubi9/httpd-24
# List running containers
podman ps
# Show all containers, including stopped ones
podman ps -a
# Check logs
podman logs web
# Run a command inside the container (enter a shell)
podman exec -it web /bin/bash
# Stop and remove
podman stop web
podman rm web-d runs detached (in the background), -p host_port:container_port maps a port, and --name assigns a name so it’s easier to work with. With podman exec -it you can step inside a running container to check its state.
Volume mapping #
When you remove a container its internal data is gone, so for data you need to keep, mount a host directory as a volume.
# Prepare a host directory
mkdir -p ~/web-content
echo "hello from host" > ~/web-content/index.html
# Map a volume (-v host_path:container_path:Z)
podman run -d --name web -p 8080:80 \
-v ~/web-content:/var/www/html:Z \
registry.access.redhat.com/ubi9/httpd-24You mount with -v host_path:container_path, and the trailing :Z is an easy RHCSA pitfall. RHEL has SELinux enabled, so adding :Z makes Podman automatically set the container_file_t context on that host directory. Leave it out and the container can’t access the volume, producing a permission error.
Passing environment variables #
# Pass environment variables (-e KEY=VALUE)
podman run -d --name db \
-e POSTGRESQL_USER=appuser \
-e POSTGRESQL_PASSWORD=secret \
-e POSTGRESQL_DATABASE=appdb \
-p 5432:5432 \
registry.redhat.io/rhel9/postgresql-15You pass environment variables with -e KEY=VALUE. Container images typically take their initial setup (user, password, database name) through such variables. Which variables an image requires is documented in the image’s documentation, so on the exam you just plug in the values the question gives you.
Rootless containers #
RHCSA almost always asks you to run a rootless container as a regular user. The key is simple: while logged in as that user, run podman commands without sudo.
# When root switches to a specific user, enter a login shell
sudo su - appuser
# Now run rootless as appuser (without sudo)
podman run -d --name web -p 8080:80 \
registry.access.redhat.com/ubi9/httpd-24
# Only appuser's containers are visible
podman psRootless comes with two caveats.
- You can’t map ports below 1024 directly to the host. A rootless user is unprivileged, so using port 80 as the host port like
-p 80:80fails. That’s why the example above uses-p 8080:80with a port at or above 1024. - Always switch users with a login shell. You must include the dash, as in
su - user, so that the user’s environment variables (XDG_RUNTIME_DIRand the like) are set up correctly. Without it, rootless Podman won’t work.
systemd integration with quadlet #
This is the very task that decides whether you pass in the RHCSA container area. “Turn this container into a systemd service that starts automatically at boot” is a recurring question. From RHEL 9.3 on, quadlet is the recommended approach.
With quadlet, you write the container definition in a .container file, and systemd reads it and automatically generates a service. For a regular (rootless) user, you put the file under ~/.config/containers/systemd/.
# Create the quadlet directory for the rootless user
mkdir -p ~/.config/containers/systemdNow write the .container file. The file name becomes the service name. For example, web.container becomes web.service.
# ~/.config/containers/systemd/web.container
[Container]
Image=registry.access.redhat.com/ubi9/httpd-24
PublishPort=8080:80
Volume=%h/web-content:/var/www/html:Z
Environment=KEY=VALUE
[Install]
WantedBy=default.targetHere’s what each key means.
Image=. The image to use (specifying the full registry path is recommended)PublishPort=. Port mapping (equivalent topodman run -p)Volume=. Volume mapping (equivalent to-v).%hexpands to the user’s home directory, and:Zis added because of SELinuxEnvironment=. Environment variables (equivalent to-e)[Install] WantedBy=. The auto-start target. It specifies which target systemd attaches this service to
After creating the file, have systemd read the new definition and start the service.
# Re-read the quadlet definitions to generate the service (rootless uses --user)
systemctl --user daemon-reload
# Start the service (file name web.container → service name web.service)
systemctl --user start web.service
# Check the status
systemctl --user status web.serviceThere are two spots where people commonly get stuck.
- A quadlet service is not enabled through
systemctl --user enabledirectly. Auto-start is controlled by the.containerfile’s[Install] WantedBy=, anddaemon-reloadpicks it up. Trying toenableit manually can give you a “can’t enable a static service” error. - After editing a definition, you must run
daemon-reloadagain for the change to take effect.
Auto-start at boot with loginctl enable-linger #
A rootless user’s systemd services by default run only while that user is logged in. When the user logs out, their user services shut down with them, so to keep the container up right after boot or while logged out, you need to enable linger.
# Enable linger for the user (requires root)
sudo loginctl enable-linger appuser
# Or the user can run it themselves
loginctl enable-linger
# Check the status (Linger must be yes)
loginctl show-user appuser | grep LingerWith enable-linger on, the user’s systemd instance starts at boot even when they aren’t logged in, and the rootless container service attached to it starts automatically along with it. Omitting this step in a “start the rootless container automatically at boot” question means the container won’t come up after a reboot and you lose points.
The whole flow, summarized #
Here is the complete procedure for auto-starting a rootless container with systemd at boot, all at once.
# 1) Enter a login shell as the target user
sudo su - appuser
# 2) Create the quadlet directory and .container file
mkdir -p ~/.config/containers/systemd
vi ~/.config/containers/systemd/web.container
# 3) Apply the definition to systemd and start it
systemctl --user daemon-reload
systemctl --user start web.service
# 4) Enable linger so it auto-starts at boot
loginctl enable-lingerExam points #
Here are the points that decide your score in the RHCSA container area.
- For rootless, enter a login shell with
su - user, then run podman withoutsudo. Forgetting the dash and breaking the environment variables is a frequent mistake. - Rootless can’t use host ports below 1024. Map to 1024 or above, like
-p 8080:80. - Add
:Zto volumes. It’s for the SELinux context; leave it out and the container can’t access the volume. - For rootless, put quadlet files in
~/.config/containers/systemd/*.container. The file name is the service name. - Don’t
enablea quadlet service. Auto-start is set by[Install] WantedBy=, applied withsystemctl --user daemon-reload. loginctl enable-lingeris mandatory for auto-start at boot. Skip this one line and the container disappears after a reboot.
In particular, quadlet’s [Install] section and loginctl enable-linger are the two core scoring points of RHCSA container questions. Don’t stop at launching the container — always confirm that the container is still alive after a reboot.
Wrap-up #
What we nailed in this post:
- Podman is a daemonless, rootless container engine. Highly command-compatible with Docker and natural for systemd integration
- Working with images. Log in with
podman login registry.access.redhat.com, manage images withsearch,pull, andimages - Running containers.
run -d -p -v -efor background, port, volume, and environment variables;ps,logs,exec,stop,rmfor operations - Rootless. Enter a login shell as a regular user and run without
sudo, ports at 1024 or above,:Zon volumes - quadlet integration. Put a
[Container]definition in~/.config/containers/systemd/*.container, thensystemctl --user daemon-reload+start - Auto-start at boot.
loginctl enable-lingerkeeps the rootless service running even after logout
Container integration with systemd extends into a broader operational context in the RHEL advanced track. Within the RHCSA scope, the goal is to achieve auto-start after reboot with quadlet and linger.
Next: exam tips #
With that we’ve made a full circle through all of RHCSA’s exam objectives. Tools and scripts, boot and operations, storage and file systems, packages and networking, users and security, and now containers — all learned by hand. What’s left is to sharpen the operational intuition to finish these tasks accurately within 2.5 hours.
In #15 Exam tips, time management, and commonly missed patterns, we’ll cover the order to tackle problems, a checking routine so you never miss making changes persistent, how to find man pages quickly, and the patterns candidates repeatedly get wrong — a strategy to comfortably clear the 210-point passing line.