Podman or Docker? A Perspective from a Daily Fedora User
I’ve been using Fedora as my main development machine for 2 years and I’m pretty happy with the package update cadence. One of the first things I switched to was Podman — not because of trends, but because Fedora ships it pre-installed and it doesn’t require a root daemon. But does Podman’s image management workflow actually differ from Docker in practice? The answer: almost identical in terms of commands, but the underlying architecture is completely different.
Today I’m skipping the theory. I’ll compare 3 approaches to managing images head-to-head, highlight the real differences, and demo a full build/push/pull cycle on a live Fedora machine.
3 Approaches to Container Image Management on Fedora
Approach 1: Installing Docker Engine on Fedora
This still works — add the Docker CE repo, install docker-ce, run the daemon. But there are a few practical issues:
- The Docker daemon runs as root, meaning every container you run has the potential for privilege escalation to the host
- Fedora updates its kernel quickly, and Docker CE sometimes lags behind in supporting the latest versions
- Conflicts with Podman if both use
/var/run/docker.sock
I tried running Docker CE alongside Podman for a while — the result was unnecessary headaches.
Approach 2: Podman with Podman Desktop
Podman Desktop is a GUI app, installable via Flatpak or RPM. If you prefer clicking over typing commands, it’s a solid choice — it has a dashboard for managing images and containers, registry connections, and a built-in Docker Compose compatibility layer.
But I stopped there. Adding an abstraction layer means adding another layer that can fail — when something breaks, you have to dig into what commands the GUI is actually calling underneath, and debugging takes twice as long.
Approach 3: Pure Podman CLI — What I Actually Use
This is what I use for both development environments and CI pipelines. The reasons are simple:
- Rootless by default — containers run under your user namespace
- No daemon — each
podmancommand is an independent process, crash-safe - OCI compliant — images built with Podman are fully compatible with Docker registries
- Buildah built-in — build images without a Docker daemon
Pros and Cons Breakdown
| Criteria | Docker CE | Podman Desktop | Podman CLI |
|---|---|---|---|
| Rootless | Partial (Docker rootless mode) | Yes | Yes (default) |
| Daemon | Required | No | No |
| Fedora compatibility | Requires extra repo | Good | Pre-installed |
| CI/CD friendly | Good | Poor | Excellent |
| Learning curve | Low (already familiar) | Low | Low if you know Docker |
If you’re on Fedora and not locked in by a tool that requires the Docker daemon — stick with Podman CLI. Fewer things that can fail, fewer things to maintain.
Hands-On: Build, Push, Pull with Podman on Fedora
Step 1: Verify Podman is Available
On Fedora 38+, Podman comes pre-installed. Quick check:
podman --version
# Podman version 5.x.x
podman info | grep -E 'rootless|cgroup'
# rootless: true
If it’s not installed:
sudo dnf install -y podman
Step 2: Write a Containerfile (equivalent to Dockerfile)
Podman accepts both Containerfile and Dockerfile — either works. I prefer the name Containerfile to make it clear this isn’t a Docker workflow.
FROM fedora:40
LABEL maintainer="[email protected]"
LABEL version="1.0"
RUN dnf update -y && \
dnf install -y python3 python3-pip && \
dnf clean all
WORKDIR /app
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python3", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Step 3: Build the Image
# Build from Containerfile in the current directory
podman build -t myapp:1.0 .
# Build from a specific file
podman build -f Containerfile -t myapp:1.0 .
# Build with build args
podman build --build-arg APP_ENV=production -t myapp:1.0 .
# List the newly built image
podman images
The output of podman images looks like this:
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/myapp 1.0 a3f8c21d9e4b 2 minutes ago 412 MB
registry.fedoraproject.org/fedora 40 8f3a1bc2d5e9 3 weeks ago 182 MB
Note: Podman uses the localhost/ prefix for local images, unlike Docker which has no prefix. A small detail but it often causes confusion when first switching over.
Step 4: Tag the Image Before Pushing
To push to a registry (Docker Hub, Quay.io, GitHub Container Registry…), you need to tag with the correct format:
# Tag for Docker Hub
podman tag localhost/myapp:1.0 docker.io/yourusername/myapp:1.0
podman tag localhost/myapp:1.0 docker.io/yourusername/myapp:latest
# Tag for GitHub Container Registry
podman tag localhost/myapp:1.0 ghcr.io/yourusername/myapp:1.0
# Tag for Quay.io
podman tag localhost/myapp:1.0 quay.io/yourusername/myapp:1.0
Step 5: Login and Push to Registry
# Login to Docker Hub
podman login docker.io
# Username: yourusername
# Password: yourpassword_or_token
# Login to GitHub Container Registry (using a Personal Access Token)
echo $GITHUB_TOKEN | podman login ghcr.io -u yourusername --password-stdin
# Push image
podman push docker.io/yourusername/myapp:1.0
podman push docker.io/yourusername/myapp:latest
Credentials are stored in ~/.config/containers/auth.json — not ~/.docker/config.json like Docker. However, Podman can also read Docker’s config file if needed.
Step 6: Pull an Image from Registry
# Pull from Docker Hub (explicit)
podman pull docker.io/yourusername/myapp:1.0
# Pull from Fedora registry (example)
podman pull registry.fedoraproject.org/fedora:40
# Pull with platform specified (arm64 for M1/M2 Mac in cross-platform builds)
podman pull --platform linux/amd64 docker.io/yourusername/myapp:1.0
# List all images after pulling
podman images
Step 7: Image Management — Cleanup and Inspection
Skipping this section until your disk hits 95% full is a mistake many people make. Don’t wait until then:
# Inspect image details
podman inspect myapp:1.0
# View image history (layers)
podman history myapp:1.0
# Remove a specific image
podman rmi localhost/myapp:1.0
# Remove all unused images (dangling)
podman image prune
# Remove all images not used by any container
podman image prune -a
# Check disk usage
podman system df
Practical Tips for Using Podman on Fedora
Use registries.conf to Avoid Typing Full Registry Paths
The /etc/containers/registries.conf file lets you configure unqualified-search-registries. I’d avoid editing the system file — instead, create a user-level override for safety:
mkdir -p ~/.config/containers
cat > ~/.config/containers/registries.conf << 'EOF'
unqualified-search-registries = ["docker.io", "quay.io", "registry.fedoraproject.org"]
EOF
Use Multi-Stage Builds to Reduce Image Size
# Stage 1: Build
FROM fedora:40 AS builder
RUN dnf install -y golang
WORKDIR /src
COPY . .
RUN go build -o myapp .
# Stage 2: Runtime (minimal)
FROM fedora-minimal:40
COPY --from=builder /src/myapp /usr/local/bin/myapp
CMD ["/usr/local/bin/myapp"]
Real numbers: a Go app keeping its full build environment typically weighs 700–900MB. With multi-stage builds, the runtime image drops to just 40–80MB — saving over 90% of registry storage and pull time.
Save and Load Images Without a Registry (Offline Transfer)
# Export image to a tar file
podman save -o myapp-1.0.tar localhost/myapp:1.0
# Compress if needed for transfer
gzip myapp-1.0.tar
# Load on another machine
podman load -i myapp-1.0.tar.gz
I use this approach fairly often when deploying to servers with no outbound internet access — build on the dev machine, save to a file, scp it to the server, load it, and you’re done.
Wrapping Up
Podman on Fedora is a natural pairing — nothing extra to install, no daemon required, rootless by default. The build/push/pull workflow is nearly identical to Docker, with only a few minor differences like the localhost/ prefix and the auth config file path. After a few days of use, the experience feels indistinguishable from Docker — but with significantly less overhead to deal with.
If your team already has a Docker-based CI/CD pipeline, migration isn’t painful either — I’ve done it across several repos and most of the time it’s just a matter of swapping docker for podman in the scripts. The rest is mostly fixing auth config paths.

