Skip to main content

Images

Comprehensive guide to Podman image management including building, pulling, pushing, and registry operations.

Image Basics

Listing Images

# List all images
podman images
podman images -a # Include intermediate images
podman images --format table # Formatted table output
podman images --format json # JSON output

# Filter images
podman images alpine # Images matching 'alpine'
podman images --filter dangling=true # Dangling images
podman images --filter before=nginx # Images created before nginx
podman images --filter since=alpine # Images created after alpine

# Sort images
podman images --sort created # Sort by creation time
podman images --sort size # Sort by size

Pulling Images

# Pull from default registry (docker.io)
podman pull alpine
podman pull alpine:3.18
podman pull alpine:latest

# Pull from specific registry
podman pull quay.io/podman/hello
podman pull registry.redhat.io/rhel8/httpd-24
podman pull gcr.io/google-containers/pause

# Pull all tags
podman pull --all-tags alpine

# Pull with specific platform
podman pull --platform linux/amd64 alpine
podman pull --platform linux/arm64 nginx

# Pull quietly
podman pull -q nginx

Image Information

# Inspect image
podman inspect alpine
podman inspect alpine:3.18

# Image history (layers)
podman history alpine
podman history --human alpine # Human readable sizes
podman history --no-trunc alpine # Full layer IDs

# Image size and details
podman images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.Created}}"

Building Images

Building from Dockerfile

# Basic build
podman build -t myapp .
podman build -t myapp:v1.0 .
podman build -t registry.example.com/myapp:latest .

# Build with specific Dockerfile
podman build -f Dockerfile.prod -t myapp:prod .
podman build -f containers/Dockerfile -t myapp .

# Build with build args
podman build --build-arg VERSION=1.0 -t myapp .
podman build --build-arg USER_ID=$(id -u) -t myapp .

# Build with specific platform
podman build --platform linux/amd64 -t myapp .
podman build --platform linux/arm64 -t myapp-arm .

# Multi-platform build
podman build --platform linux/amd64,linux/arm64 -t myapp .

Advanced Build Options

# Build without cache
podman build --no-cache -t myapp .

# Build with custom context
podman build -t myapp /path/to/context

# Build from Git repository
podman build -t myapp https://github.com/user/repo.git
podman build -t myapp https://github.com/user/repo.git#branch

# Build from stdin
echo -e 'FROM alpine\nRUN echo "hello"' | podman build -t myapp -

# Build with labels
podman build --label version=1.0 --label maintainer=user@example.com -t myapp .

# Build with resource limits
podman build --memory=1g --cpus=2 -t myapp .

Dockerfile Examples

Multi-stage Build

# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Runtime stage
FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

Minimal Security-focused Build

FROM alpine:3.18 AS base
RUN apk update && apk upgrade && \
apk add --no-cache ca-certificates && \
addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup

FROM base AS runtime
COPY --chown=appuser:appgroup app /app/
USER appuser
WORKDIR /app
CMD ["./app"]

Registry Operations

Pushing Images

# Login to registry
podman login docker.io
podman login -u username registry.example.com
podman login --password-stdin registry.example.com

# Push to registry
podman push myapp:latest
podman push registry.example.com/myapp:v1.0

# Push to specific registry
podman tag myapp:latest registry.example.com/myapp:latest
podman push registry.example.com/myapp:latest

# Push all tags
podman push --all-tags myapp

Registry Configuration

# Configure registries
sudo tee /etc/containers/registries.conf <<EOF
[registries.search]
registries = ['docker.io', 'quay.io', 'registry.redhat.io']

[registries.insecure]
registries = ['registry.local:5000']

[registries.block]
registries = ['untrusted-registry.com']

[[registry]]
location = "internal-registry.company.com"
insecure = false
blocked = false
mirror = [
{ location = "mirror1.company.com" },
{ location = "mirror2.company.com" }
]
EOF

Private Registry Setup

# Run local registry
podman run -d \
--name registry \
-p 5000:5000 \
-v registry-data:/var/lib/registry \
registry:2

# Use local registry
podman build -t localhost:5000/myapp .
podman push localhost:5000/myapp
podman pull localhost:5000/myapp

Image Management

Tagging Images

# Tag image
podman tag alpine myapp:base
podman tag myapp:latest myapp:v1.0
podman tag myapp:latest registry.example.com/myapp:latest

# Multiple tags
podman tag myapp:latest myapp:stable myapp:production

Removing Images

# Remove specific image
podman rmi alpine
podman rmi alpine:3.18
podman rmi myapp:v1.0

# Force remove (even if containers exist)
podman rmi -f myapp

# Remove multiple images
podman rmi alpine nginx ubuntu

# Remove all images
podman rmi $(podman images -q)

# Remove dangling images
podman image prune

# Remove all unused images
podman image prune -a

# Remove images with filter
podman image prune --filter "until=24h"

Image Import/Export

# Save image to tar file
podman save alpine > alpine.tar
podman save -o alpine.tar alpine
podman save myapp:latest | gzip > myapp.tar.gz

# Load image from tar file
podman load < alpine.tar
podman load -i alpine.tar

# Save multiple images
podman save -o images.tar alpine nginx ubuntu

# Export container as tar
podman export container_name > container.tar

# Import tar as image
podman import container.tar new_image:latest
podman import - new_image:latest < container.tar

Image Optimization

Reducing Image Size

# Use minimal base images
FROM alpine:3.18 # ~5MB
FROM debian:bullseye-slim # ~80MB
FROM scratch # 0MB (static binaries)

# Multi-stage builds
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o app

FROM alpine:3.18
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/app /app
CMD ["/app"]

# Combine RUN commands
RUN apk update && \
apk add --no-cache curl && \
apk del .build-deps && \
rm -rf /var/cache/apk/*

# Use .dockerignore
# .dockerignore
.git
*.md
node_modules
tests/

Layer Optimization

# Analyze image layers
podman history myapp
podman history --no-trunc myapp

# Use dive to analyze layers (external tool)
dive myapp:latest

# Optimize layer caching
# Order Dockerfile instructions from least to most likely to change
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./ # Copy package files first
RUN npm ci # Install dependencies
COPY . . # Copy source code last
RUN npm run build

Image Security

Vulnerability Scanning

# Scan with Trivy
podman run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image myapp:latest

# Scan specific severity
podman run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image --severity HIGH,CRITICAL myapp:latest

# Generate report
podman run --rm -v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd):/output \
aquasec/trivy image --format json --output /output/report.json myapp:latest

Secure Image Practices

# Use specific versions
FROM node:18.17.0-alpine3.18 # ✓ Specific version
FROM node:18-alpine # ✓ Acceptable
FROM node:latest # ✗ Unpredictable

# Run as non-root user
FROM alpine:3.18
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
USER appuser

# Update packages
RUN apk update && apk upgrade

# Remove unnecessary packages
RUN apk add --no-cache --virtual .build-deps \
build-base && \
# build commands here
apk del .build-deps

Image Formats and Standards

OCI Compliance

# Build OCI-compliant image
podman build --format oci -t myapp .

# Build Docker format
podman build --format docker -t myapp .

# Check image format
podman inspect myapp | grep -i format

Manifest Operations

# Create manifest list
podman manifest create myapp:latest

# Add images to manifest
podman manifest add myapp:latest myapp:amd64
podman manifest add myapp:latest myapp:arm64

# Push manifest
podman manifest push myapp:latest registry.example.com/myapp:latest

# Inspect manifest
podman manifest inspect myapp:latest

Automation and CI/CD

Build Scripts

#!/bin/bash
# build.sh

set -e

IMAGE_NAME="myapp"
VERSION=${1:-latest}
REGISTRY="registry.example.com"

echo "Building $IMAGE_NAME:$VERSION"
podman build -t $IMAGE_NAME:$VERSION .

echo "Tagging for registry"
podman tag $IMAGE_NAME:$VERSION $REGISTRY/$IMAGE_NAME:$VERSION

echo "Pushing to registry"
podman push $REGISTRY/$IMAGE_NAME:$VERSION

echo "Cleaning up"
podman image prune -f

GitHub Actions Example

name: Build and Push
on:
push:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install Podman
run: |
sudo apt update
sudo apt install -y podman

- name: Build image
run: podman build -t myapp:${{ github.sha }} .

- name: Push image
run: |
echo ${{ secrets.REGISTRY_PASSWORD }} | \
podman login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin registry.example.com
podman push myapp:${{ github.sha }}

Quick Reference

Essential Image Commands

# Building
podman build -t myapp .
podman build --no-cache -t myapp .

# Managing
podman images
podman rmi myapp
podman image prune

# Registry
podman pull alpine
podman push myapp
podman login registry.example.com

# Import/Export
podman save myapp > myapp.tar
podman load < myapp.tar

Common Patterns

# Build and tag for multiple environments
podman build -t myapp:dev .
podman tag myapp:dev myapp:staging
podman tag myapp:dev registry.com/myapp:prod

# Clean development images
podman image prune --filter "label=stage=development"

# Update base image
podman pull alpine:latest
podman build --pull -t myapp .