Managing Container Images with Podman on Fedora: Build, Push, and Pull from Registry

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

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 podman command 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.

Share: