π¦ Podman Containers Deep Dive
RHCSA RHEL 10 β Images Β· Containers Β· Volumes Β· Rootless Β· Pods Β· Registry Β· Production
1. Podman Overview (L1)
Daemonless Β· Rootless Β· OCI Β· Docker-compatible container engine for RHEL 8/9/10
What is Podman? Architecture vs Docker
Podman (Pod Manager) is a daemonless, rootless, OCI-compliant container engine β the default on RHEL 8/9/10.
| Feature | Docker | Podman |
|---|---|---|
| Architecture | Client-server β dockerd daemon required | Daemonless β fork/exec per command via conmon |
| Root requirement | Root or docker group required | Fully rootless β user namespace mapping |
| Security | Single root daemon = single attack point | No persistent daemon β no root process to exploit |
| CLI | docker CLI | podman CLI β drop-in compatible |
| Pods | Compose only | Native pod support (Kubernetes-compatible) |
| Systemd | Limited | Native β Quadlet unit files on RHEL 10 |
| K8s migration | docker-compose limited | podman generate kube β valid K8s YAML |
| OCI | Yes | Yes β OCI native |
podman CLI crashes, running containers are NOT affected β no parent daemon to kill them. Docker containers die if dockerd crashes.2. Image Management (L1)
Pull Β· Build Β· List Β· Search Β· Tag Β· Remove Β· Containerfile
Image Management β Pull, Build, List, Remove
ubi9-minimal as base on RHEL β Red Hat supported, smaller than full RHEL, freely redistributable. Use ubi-init when systemd inside the container is needed.3. Container Lifecycle (L1)
run Β· start Β· stop Β· restart Β· kill Β· rm β full lifecycle with all key options
Container Lifecycle β Full Reference
| Option | Description | Example |
|---|---|---|
| -d | Detached mode | -d |
| -it | Interactive terminal | -it ubi9 bash |
| --name | Name the container | --name webserver |
| -p | Port mapping host:container | -p 8080:80 |
| -v | Volume / bind mount | -v mydata:/app/data |
| -e | Environment variable | -e DB_HOST=localhost |
| --rm | Auto-remove on exit | --rm |
| --read-only | Read-only root filesystem | --read-only |
| --cap-drop | Drop Linux capabilities | --cap-drop ALL |
| --security-opt | Security options | --security-opt no-new-privileges |
| --restart | Restart policy | --restart always |
4. Container Interaction (L1)
exec Β· logs Β· inspect Β· top Β· stats Β· cp β interact with running containers
Container Interaction β exec, logs, inspect, stats
5. Container Ports & Networking (L1)
Port mapping Β· Network create Β· Container DNS Β· Custom networks
Container Ports & Networking
podman network create mynet) for container-to-container DNS.6. Volumes Management (L1)
Named volumes Β· Create Β· Inspect Β· Mount Β· Backup Β· Restore
Volumes Management
| Aspect | Named Volume | Bind Mount |
|---|---|---|
| Managed by | Podman | User (host filesystem) |
| Location | Container storage dir | Any host path |
| SELinux | Auto-labelled | Needs :Z or :z suffix |
| Use case | Database data, persistent state | Config files, source code |
| Syntax | -v volname:/path | -v /host/path:/path |
7. Bind Mounts (L1)
Host path mounting Β· SELinux :Z :z labels Β· Read-only mounts Β· RHEL SELinux context
Bind Mounts & SELinux Labels
| Label | Meaning | When to Use |
|---|---|---|
| :Z | Private β relabel for this container ONLY | Single container accessing the path |
| :z | Shared β relabel for multiple containers | Multiple containers sharing same host path |
| :ro | Read-only | Container must not modify host files |
| :Z,ro | Private + read-only | Config files for single container |
ausearch -m avc -ts recent8. Pods (L2)
Create pods Β· Add containers Β· K8s YAML export Β· Infra container
Pods β Kubernetes-style Container Groups
A Pod groups containers sharing the same network namespace, IPC, and optionally PID namespace β identical to Kubernetes pods. Port mappings go on the pod, not containers.
pause infra container that holds the network namespace. Inspect: podman ps -a --pod | grep infra9. Rootless Containers (L2)
User namespaces Β· subuid/subgid Β· Systemd integration Β· Quadlet (RHEL 10)
Rootless Containers β Architecture & Setup
- No root process β container UID 0 maps to your unprivileged host UID via user namespaces
- No persistent daemon β completely eliminates the dockerd root attack surface
- CI/CD safety β build/run containers in pipelines without giving root to CI agents
- Multi-user β each user has isolated, invisible container namespaces
10. Registry Operations (L2)
Login Β· Push Β· Pull Β· Logout Β· Registry config Β· Skopeo
Registry Operations
11. Container Commit & Export (L2)
commit Β· save Β· load Β· export Β· import β image portability and backup
Container Commit & Export
| Operation | Includes | Use Case |
|---|---|---|
podman save | Image layers + metadata | Offline image transfer between hosts |
podman export | Container filesystem only (flat) | Snapshot container filesystem |
podman commit | Running container β new image | Capture configured container |
podman push | Push to registry | Best practice for image sharing |
12. Docker Compatibility (L2)
Alias Β· Socket emulation Β· podman-compose Β· Docker β Podman migration
Docker Compatibility
| Docker | Podman | Notes |
|---|---|---|
| docker run | podman run | Identical syntax |
| docker-compose up | podman-compose up | Requires podman-compose |
| docker swarm | podman play kube | Use Kubernetes for orchestration |
| docker build | podman build | Containerfile or Dockerfile |
13. Troubleshooting (L2)
Common issues Β· Diagnosis commands Β· SELinux Β· Rootless Β· Storage
Troubleshooting β Issues, Diagnosis & Solutions
| Issue | Diagnosis | Solution |
|---|---|---|
| Container not starting | podman logs <c>podman inspect <c> | Check exit code + logs. Verify CMD exists in image. |
| Port already in use | ss -tulnp | grep <port> | Kill conflicting process or use different host port. |
| Image pull failed | podman pull <image> 2>&1 | Check internet/DNS, verify registry login. |
| Permission denied (rootless) | cat /etc/subuid | Add subuid/subgid entries + podman system migrate |
| Storage full | podman system df | podman system prune -a |
| Container exits immediately | podman ps -apodman logs <id> | PID1 must not exit. Debug: podman run --entrypoint bash myimage |
| SELinux permission denied | ausearch -m avc -ts recent | Add :Z to mount: -v /path:/cpath:Z |
| DNS not resolving | podman exec web cat /etc/resolv.conf | Create custom network: podman network create |
| Volume mount empty | podman inspect web | grep Mounts | Check host path exists, SELinux label, volume name. |
| OCI runtime error | podman run ... 2>&1 | Check crun: rpm -q crun |
14. System Management (L2)
prune Β· stats Β· info Β· version Β· systemd units Β· Quadlet (RHEL 10)
System Management
15. Real Production Scenarios (L3)
Application isolation Β· CI/CD pipelines Β· Security hardening Β· Disaster recovery
Deploy frontend (Nginx), backend API (Flask), and database (PostgreSQL) on RHEL 10. Each tier isolated, only frontend port exposed externally.
- How do you design the network topology?
- How do you handle DB persistence?
- How do you auto-restart on failure?
- Creates frontend-net (nginx+api) and backend-net (api+db). Only API connects to both β database has no external port mapping.
- Named volume for PostgreSQL:
podman volume create pgdata - Systemd unit files or Quadlet for auto-restart. Uses
--restart=always. - Generates K8s YAML with
podman generate kubefor documentation.
Jenkins/GitLab CI runner on shared RHEL 10 β build images, test in containers, push to registry β no root access on runner.
- How do you configure rootless Podman in CI?
- How do you authenticate non-interactively?
- How do you cache layers between runs?
- Rootless Podman: no sudo, no docker group, no root daemon.
- Auth via file:
podman login --authfile /tmp/auth.json registry.example.com. Credentials as CI secret. - Build args from env:
podman build --build-arg VERSION=$CI_SHA -t myapp . - Pre-pull base image to seed layer cache:
podman pull myapp:latestbefore build.
Production nginx container: no new privileges, read-only filesystem, dropped capabilities, non-root user, SELinux enforcing.
- What flags enforce these requirements?
- How does nginx write pid/tmp files if root filesystem is read-only?
podman run -d --read-only --security-opt no-new-privileges --cap-drop ALL --cap-add NET_BIND_SERVICE --user 1001:1001 nginx- Tmpfs for required write paths:
--tmpfs /var/run --tmpfs /var/cache/nginx --tmpfs /tmp - Verify:
podman inspect --format "{{.HostConfig.ReadonlyRootfs}}" web - Verify user:
podman exec web idβ should show UID 1001, NOT root.
6 production containers on RHEL 10 must migrate to new hardware. No registry available (air-gapped environment). Minimal downtime.
- How do you capture container configurations?
- How do you transfer images without a registry?
- How do you preserve volume data?
- Save all images:
for img in $(podman images -q); do podman save -o images/$img.tar $img; done - Export volumes:
podman volume export volname -o volname.tar - Transfer via SCP/rsync. Import on new host:
podman load -i image.tar,podman volume import volname volname.tar - Verify:
podman ps,podman stats --no-stream, application health checks.
L1 β L3 Responsibility Matrix
Competency breakdown: Basic Β· Intermediate Β· Advanced
L1 β L3 Responsibility Matrix
| Level | Focus | Responsibilities | Key Commands |
|---|---|---|---|
| L1 Basic | Container Basics | Run containers, manage images, volumes & basic troubleshooting | run, ps, images, rmi, logs, exec |
| L2 Intermediate | Container Management | Networks, volumes, pods, registry, rootless, commit/export | network, volume, pod, commit, login, info |
| L3 Advanced | Production Admin | Design, secure, optimise, troubleshoot & automate | inspect, system df, prune, generate kube, events |
- Run named container detached
- List/start/stop/remove containers
- Pull and remove images
- View logs
- Map ports
- Create/mount named volumes
- Bind mounts with :Z
- Custom networks + DNS
- Build from Containerfile
- Rootless configuration
- Registry login/push
- Create and manage pods
- Generate systemd units
- Commit containers to images
- Multi-tier container architecture
- Security hardening flags
- K8s YAML generation
- CI/CD rootless integration
- Disaster recovery image save/load
- Quadlet systemd (RHEL 10)
- Performance tune + resource limits
Interview Questions β L2/L3
8 core interview questions with comprehensive model answers
Interview Q&A β 8 Core Questions with Model Answers
podman run -d --name web nginx β -d detaches from terminal. Container runs in background. View output: podman logs web. Attach: podman attach web. Container's PID 1 must be a long-running process β if it exits, the container stops.podman run -d -p 8080:80 nginx β format: -p HOST_PORT:CONTAINER_PORT. Traffic to localhost:8080 β container port 80. Bind to specific IP: -p 127.0.0.1:8080:80. Rootless: ports below 1024 need net.ipv4.ip_unprivileged_port_start sysctl.podman pod create --name mypod -p 8080:80. Add containers: podman run -d --pod mypod --name c1 nginx. Export to K8s: podman generate kube mypod.podman volume create mydata β Podman-managed storage. Mount: podman run -d -v mydata:/var/lib/mysql mariadb. Persists beyond container removal. Inspect mount path: podman volume inspect mydata. Backup: podman volume export mydata -o backup.tar. Rootless storage: $HOME/.local/share/containers/storage/volumes/./etc/subuid and /etc/subgid. Networking uses slirp4netns or pasta (RHEL 10) β userspace TCP/IP, no iptables root required. Cgroup v2 required for resource limits. Verify: podman info | grep rootless.podman ps -a β find exited container, note exit code. Step 2: podman logs <container> β read application error. Step 3: podman inspect <container> β check config, mounts, network. Step 4: podman events --since 1h β runtime events. Step 5: SELinux check: ausearch -m avc + add :Z. Step 6: Debug interactively: podman run --entrypoint /bin/sh myimage.podman save -o myimage.tar myimage:latest β exports all layers + metadata. Load: podman load -i myimage.tar. Air-gap workflow: save β SCP β load on target host. Alternative: podman export/import for filesystem-only snapshot (no image metadata). Best practice: use a registry with push/pull when possible.Deep-Dive Topics
cgroups v2 Β· Linux namespaces Β· Image layers Β· Storage drivers Β· Optimisation
Deep Dive β cgroups v2, Namespaces & Layers
| Namespace | Isolates | Podman Usage |
|---|---|---|
| PID | Process tree starting at PID 1 | Each container gets own PID namespace |
| Network | Interfaces, routing | Each container gets veth pair + bridge |
| Mount | Filesystem view | Container / = image layers (overlay) |
| IPC | SysV IPC, message queues | Isolated by default; shared in pods |
| UTS | Hostname | Container has own hostname |
| User | UID/GID mapping | Rootless maps UID 0 β host UID |
| Cgroup | Cgroup tree visibility | Container sees only its cgroup slice |
Quick Reference Cheat Sheet
40 essential Podman commands organised by category β L1 to L3
Quick Reference Cheat Sheet β All Essential Commands
| Category | Command | Description |
|---|---|---|
| Container | podman run -d --name web nginx | Run detached named container |
| Container | podman run -it ubi9 bash | Interactive shell |
| Container | podman run --rm alpine date | Run & auto-remove |
| Container | podman ps -a | List all containers |
| Container | podman stop/start/restart web | Lifecycle control |
| Container | podman rm -f web | Force remove |
| Container | podman container prune | Remove all stopped |
| Image | podman pull nginx:latest | Pull image |
| Image | podman images | List images |
| Image | podman rmi nginx:latest | Remove image |
| Image | podman image prune -a | Remove all unused |
| Image | podman build -t myapp:v1 . | Build from Containerfile |
| Image | podman save -o img.tar myapp:v1 | Export to tar |
| Image | podman load -i img.tar | Import from tar |
| Interact | podman exec -it web bash | Shell into container |
| Interact | podman logs -f web | Follow logs |
| Interact | podman inspect web | Full metadata JSON |
| Interact | podman stats | Live resource usage |
| Interact | podman cp web:/etc/nginx.conf . | Copy from container |
| Network | podman network create mynet | Create bridge network |
| Network | podman network ls | List networks |
| Network | podman port web | Show port mappings |
| Volume | podman volume create mydata | Create volume |
| Volume | podman volume ls/inspect/rm | Manage volumes |
| Volume | podman volume export/import | Backup/restore |
| Pod | podman pod create --name mypod -p 8080:80 | Create pod |
| Pod | podman pod ps | List pods |
| Pod | podman generate kube mypod | Export to K8s YAML |
| Pod | podman play kube mypod.yaml | Create from K8s YAML |
| Registry | podman login registry.redhat.io | Login to registry |
| Registry | podman push myapp:v1 registry.example.com/myapp:v1 | Push image |
| System | podman system df | Disk usage |
| System | podman system prune -a | Remove all unused |
| System | podman info | System config |
| System | podman events --since 1h | Recent events |
| Security | podman run --read-only --security-opt no-new-privileges --cap-drop ALL | Hardened run |
| Rootless | cat /etc/subuid && cat /etc/subgid | Check user namespace config |
| Rootless | podman system migrate | Apply rootless configuration |
| Systemd | podman generate systemd --name web | Generate unit file |
| Docker | alias docker=podman | Docker compatibility alias |