Podman Volumes: Managing Persistent Data (4/5)
Containers are disposable by design. Stop one, remove it, and everything written inside its writable layer disappears with it. That’s a…
Podman Volumes: Managing Persistent Data (4/5)
Containers are disposable by design. Stop one, remove it, and everything written inside its writable layer disappears with it. That’s a feature for stateless workloads — and a serious problem the moment you run a database, an upload directory, or anything else that needs to survive a restart.
This part of the series covers how Podman handles persistent storage: named volumes, bind mounts, the permission issues that trip up almost everyone on SELinux systems, and how to share data safely between containers.

Why Containers Need Volumes
A container’s filesystem is a writable layer stacked on top of a read-only image. When the container is removed, that writable layer goes with it. Volumes solve this by attaching storage that lives outside the container’s lifecycle.
Podman gives you two main approaches:
Type Managed by Best for Named volume Podman Databases, application data, anything you want Podman to track and back up Bind mount You (host path) Local development, injecting config files, sharing a specific host directory
1. Named Volumes
Creating a Volume
podman volume create app-data
Podman creates the volume in its managed storage location and confirms the name.
Inspecting and Listing Volumes
podman volume ls
podman volume inspect app-data
inspect returns the mount point, driver, and labels as JSON.
Mounting a Named Volume
podman run -d --name postgres \
-v app-data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:16
If app-data doesn't exist yet, Podman creates it automatically — you don't have to run volume create first.
Verifying Persistence
podman stop postgres
podman rm postgres
# Recreate the container with the same volume
podman run -d --name postgres \
-v app-data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:16
The data is still there. The container was disposable; the volume wasn’t.
2. Bind Mounts
Bind mounts map a specific host directory directly into the container — useful when you need direct access to source code, config files, or logs.
podman run -d --name web \
-v ~/site-config:/usr/share/nginx/html:ro \
-p 8080:80 \
nginx:alpine
The :ro suffix mounts it read-only. Unlike named volumes, the host path must already exist — Podman will not create it for you.
3. The SELinux Permission Problem
If you’re on Fedora, RHEL, or another SELinux-enforcing system, this is the error almost everyone hits eventually:
permission denied
…even though the file permissions look fine. SELinux labels are the real culprit, and Podman has a built-in fix: relabeling suffixes on the volume mount.
Suffix Meaning :z (lowercase) Shared label — multiple containers can read/write this volume :Z (uppercase) Private label — only this container can access it
podman run -d --name secure-app \
-v ~/private-config:/config:ro,Z \
nginx:alpine
If two containers need to share the same bind-mounted directory, use :z instead — :Z will lock the other container out.
4. Sharing a Volume Between Containers
Named volumes aren’t tied to a single container — multiple containers can mount the same one simultaneously.
podman volume create shared-data
# Writer
podman run -d --name writer \
-v shared-data:/output \
alpine sh -c "while true; do date >> /output/log.txt; sleep 5; done"
# Reader
podman run -d --name reader \
-v shared-data:/input:ro \
alpine tail -f /input/log.txt
podman exec reader cat /input/log.txt
This pattern is common for log shippers, sidecar exporters, and any setup where one container produces data another consumes.
5. The --mount Flag (the Explicit Alternative)
The -v shorthand is convenient, but --mount is more readable for complex configurations — especially in scripts and CI pipelines:
podman run -d --name app \
--mount type=volume,source=app-data,target=/data \
alpine
Bind mount with --mount:
podman run -d --name app \
--mount type=bind,source=/home/user/config,target=/etc/app/config,readonly=true \
alpine
Both flags do the same job — pick -v for quick one-liners, --mount when readability matters more than brevity.
Conclusion
Volumes are what turn Podman from “a way to run disposable processes” into something you can actually trust with production data. The pattern to default to: named volumes for anything you want Podman to manage and back up, bind mounts for config and development workflows, and :Z/:z whenever SELinux throws permission errors at you.
In the final part of this series, we’ll bring networking, volumes, and multi-container setups together using pods and Podman’s systemd integration — running container groups as proper, declarative system services.
Further reading:
메타데이터
- post_id
- 7b6dd83b166f
- slug
- podman-volumes-managing-persistent-data-4-5-7b6dd83b166f
- url
- https://medium.com/@parkashsarangani/podman-volumes-managing-persistent-data-4-5-7b6dd83b166f
- canonical_url
- https://medium.com/@parkashsarangani/podman-volumes-managing-persistent-data-4-5-7b6dd83b166f
- author_url
- https://medium.com/@parkashsarangani
- status
- ok
- fetched_at
- 2026-07-13 06:23:13