How to Install and Use Podman Pods on RHEL 7
Podman is a daemonless, rootless-capable container engine that ships with modern versions of RHEL and is available via EPEL on RHEL 7. One of Podman’s most powerful features is pods — a concept borrowed directly from Kubernetes. A pod is a group of one or more containers that share the same network namespace, UTS namespace (hostname), and optionally IPC namespace. This sharing means that containers within a pod communicate over localhost and see the same hostname, making them ideal for multi-component applications such as a web server paired with a sidecar logging agent or a database bundled with a connection pooler. This guide covers creating, managing, and inspecting Podman pods on RHEL 7, along with generating Kubernetes-compatible YAML from your running pod.
Prerequisites
- RHEL 7 with EPEL repository enabled
- Root or a user with
sudoprivileges - Internet access to pull container images
- At least 2 GB of free disk space in
/var/lib/containers - Basic familiarity with container concepts (images, containers, ports)
Step 1: Install Podman on RHEL 7
Podman is available in the EPEL repository for RHEL 7. Install it along with container-selinux, which provides the SELinux policies required for container isolation.
# Enable EPEL if not already enabled
sudo yum install -y epel-release
# Install Podman and supporting packages
sudo yum install -y podman container-selinux slirp4netns fuse-overlayfs
# Verify the installation
podman --version
# Expected output: podman version 1.x.x (or later on RHEL 7 EPEL)
# Pull a test image to confirm connectivity
podman pull docker.io/library/nginx:alpine
On RHEL 7, Podman typically runs as root when using the default overlay storage driver. Rootless operation requires kernel user namespace support, which may need additional configuration on older RHEL 7 kernels.
Step 2: Understanding the Pod Concept
When you create a pod with Podman, a hidden infra container is automatically started. This infra container (based on the k8s.gcr.io/pause image) holds the network and UTS namespaces open for the lifetime of the pod, even when application containers start and stop. All application containers you add to the pod share these namespaces.
# Inspect what a pod looks like after creation
podman pod create --name demo-pod
# List pods - you will see the pod in "Created" state
podman pod list
# List all containers including the infra container
podman ps -a
# The infra container is named <pod-name>-infra
Step 3: Create a Pod with Port Mappings
Port mappings must be defined when creating the pod, not when adding individual containers. This is because the infra container owns the network namespace and therefore the port bindings.
# Create a pod named "webapp" exposing port 8080 on the host
# mapped to port 80 inside the pod
podman pod create
--name webapp
-p 8080:80
-p 8443:443
# Verify the pod was created
podman pod list
# Output:
# POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
# a1b2c3d4e5f6 webapp Created 5 seconds ago f7g8h9i0j1k2 1
Step 4: Add Containers to the Pod
Add multiple containers to the pod using podman run --pod <pod-name>. Notice that you do not specify port mappings on individual containers — the pod already owns the ports.
# Add an Nginx web server container to the pod
# Note: no -p flag needed; the pod owns port 8080:80
podman run -d
--pod webapp
--name nginx-server
docker.io/library/nginx:alpine
# Add a PHP-FPM container to the same pod
# It will communicate with Nginx over localhost:9000
podman run -d
--pod webapp
--name php-fpm
docker.io/library/php:7.4-fpm-alpine
# Add a log aggregator sidecar (e.g., fluentd)
podman run -d
--pod webapp
--name log-sidecar
-v /var/log/webapp:/fluentd/log:Z
docker.io/library/fluent/fluentd:v1.14-1
# List all containers in the pod
podman ps --pod
Because all containers share the same network namespace, the Nginx container can proxy PHP requests to localhost:9000 and the log sidecar can read from a shared socket or volume without any complex networking configuration.
Step 5: Inspect and Monitor Pods
# List all pods with status
podman pod list
# Detailed JSON inspection of the pod
podman pod inspect webapp
# Extract just the container names from the pod
podman pod inspect webapp
--format '{{range .Containers}}{{.Name}} {{.State}}{{"n"}}{{end}}'
# View resource usage for all containers in the pod
podman pod stats webapp
# View logs from a specific container in the pod
podman logs nginx-server
# Follow logs from the PHP-FPM container
podman logs -f php-fpm
# Execute a command inside a pod container
podman exec -it nginx-server sh
Step 6: Stop, Start, and Remove Pods
Podman provides pod-level lifecycle commands that operate on all containers in the pod simultaneously.
# Stop all containers in the pod (graceful SIGTERM, then SIGKILL)
podman pod stop webapp
# Start all containers in the pod
podman pod start webapp
# Restart all containers in the pod
podman pod restart webapp
# Pause all containers (suspend CPU scheduling)
podman pod pause webapp
# Unpause
podman pod unpause webapp
# Remove the pod and all its containers (pod must be stopped first)
podman pod stop webapp
podman pod rm webapp
# Force remove a running pod
podman pod rm --force webapp
Step 7: Generate Kubernetes YAML from a Pod
One of Podman’s most valuable features is the ability to export a running pod as Kubernetes-compatible YAML. This makes it easy to prototype locally and then deploy to a Kubernetes cluster.
# Re-create the pod for this example
podman pod create --name mypod -p 8080:80
podman run -d
--pod mypod
--name web
-e NGINX_HOST=example.com
docker.io/library/nginx:alpine
# Generate Kubernetes YAML
podman generate kube mypod > mypod-kubernetes.yaml
# Inspect the generated YAML
cat mypod-kubernetes.yaml
The generated YAML includes a Pod specification with all containers, environment variables, volume mounts, and port mappings translated to Kubernetes format. You can apply this directly to a Kubernetes cluster with kubectl apply -f mypod-kubernetes.yaml. This workflow — develop locally with Podman pods, deploy to Kubernetes — is a core use case for Red Hat’s container ecosystem on RHEL.
Step 8: Running a Pod as a systemd Service
On RHEL 7, you can integrate a Podman pod with systemd to ensure it starts automatically at boot.
# Generate systemd unit files for the pod and its containers
podman generate systemd --name mypod --files --new
# This creates unit files like:
# pod-mypod.service
# container-web.service
# Move unit files to systemd
sudo mv pod-mypod.service container-web.service
/etc/systemd/system/
# Reload systemd and enable the pod service
sudo systemctl daemon-reload
sudo systemctl enable pod-mypod.service
sudo systemctl start pod-mypod.service
# Verify
sudo systemctl status pod-mypod.service
Step 9: Podman Pods vs Docker Compose
If you are familiar with Docker Compose, Podman pods offer a comparable multi-container experience with some important differences:
- No daemon required: Podman runs without a background daemon, reducing the attack surface and eliminating a single point of failure.
- Kubernetes-native: Pods map directly to Kubernetes Pod objects; Docker Compose YAML requires conversion tools.
- Shared namespace: All containers in a Podman pod share one network namespace, so inter-container communication uses
localhost. Docker Compose containers use a shared bridge network and communicate by service name. - Rootless support: Podman supports rootless pods; Docker requires root for most operations on RHEL 7.
- systemd integration:
podman generate systemdproduces native unit files; Docker Compose needs a wrapper service.
Podman pods on RHEL 7 provide a powerful, Kubernetes-aligned approach to running multi-container applications. By grouping tightly coupled containers into a pod, you get shared networking without the complexity of container-to-container network configuration, while the seamless Kubernetes YAML export makes it straightforward to move workloads from your RHEL 7 development environment to a production Kubernetes cluster. The daemonless architecture and native systemd integration make Podman pods an excellent choice for production workloads on RHEL 7 systems where stability and security are paramount.