Podman Images¶
Understanding Images¶
Container images are read-only templates containing: - Application code - Runtime environment - System libraries - Dependencies - Configuration files
Image Layers¶
Images are built in layers:
Layer 4: Application code
Layer 3: Application dependencies
Layer 2: Runtime (Node.js, Python, etc.)
Layer 1: Base OS (Alpine, Ubuntu, etc.)
Building Images¶
Using Dockerfile¶
Basic Dockerfile¶
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Build Image¶
# Build from Dockerfile
podman build -t myapp:latest .
# Build with specific file
podman build -f Dockerfile.prod -t myapp:prod .
# Build with build args
podman build --build-arg VERSION=1.0 -t myapp:1.0 .
# Build without cache
podman build --no-cache -t myapp:latest .
# Build with labels
podman build --label version=1.0 --label env=prod -t myapp .
Multi-Stage Builds¶
# Build stage
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# Runtime stage
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]
# Build multi-stage
podman build -t myapp:latest .
# Build specific stage
podman build --target builder -t myapp:builder .
Dockerfile Best Practices¶
Optimize Layers¶
# Bad: Multiple RUN commands
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim
# Good: Single RUN command
RUN apt-get update && \
apt-get install -y \
curl \
vim && \
rm -rf /var/lib/apt/lists/*
Use .dockerignore¶
Minimize Image Size¶
# Use Alpine base
FROM node:18-alpine
# Multi-stage build
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine
COPY --from=builder /app/node_modules ./node_modules
COPY . .
CMD ["node", "server.js"]
Using Buildah¶
Buildah provides more flexibility than Dockerfile builds.
Basic Buildah Commands¶
# Create working container
buildah from alpine
# Run commands in container
buildah run alpine-working-container apk add nginx
# Copy files
buildah copy alpine-working-container index.html /usr/share/nginx/html/
# Configure container
buildah config --port 80 alpine-working-container
buildah config --cmd "nginx -g 'daemon off;'" alpine-working-container
# Commit to image
buildah commit alpine-working-container mynginx:latest
Buildah Script Example¶
#!/bin/bash
# Create container from base
container=$(buildah from node:18-alpine)
# Install dependencies
buildah run $container npm install -g pm2
# Copy application
buildah copy $container package*.json /app/
buildah run $container --workingdir /app npm install
buildah copy $container . /app/
# Configure
buildah config --workingdir /app $container
buildah config --port 3000 $container
buildah config --cmd "pm2-runtime start server.js" $container
# Commit
buildah commit $container myapp:latest
# Cleanup
buildah rm $container
Image Management¶
Tagging Images¶
# Tag image
podman tag myapp:latest myapp:v1.0
# Tag for registry
podman tag myapp:latest registry.example.com/myapp:latest
# Multiple tags
podman tag myapp:latest myapp:stable
podman tag myapp:latest myapp:production
Pushing Images¶
# Login to registry
podman login docker.io
podman login quay.io
podman login registry.example.com
# Push image
podman push myapp:latest
# Push to specific registry
podman push myapp:latest docker.io/username/myapp:latest
# Push all tags
podman push --all-tags myapp
Pulling Images¶
# Pull latest
podman pull nginx
# Pull specific tag
podman pull nginx:1.21-alpine
# Pull from specific registry
podman pull quay.io/nginx/nginx:latest
# Pull with digest
podman pull nginx@sha256:abc123...
# Pull all tags
podman pull --all-tags nginx
Image Inspection¶
Inspect Image¶
# Full inspection
podman inspect nginx
# Get specific field
podman inspect --format='{{.Config.Cmd}}' nginx
# Get environment variables
podman inspect --format='{{.Config.Env}}' nginx
# Get exposed ports
podman inspect --format='{{.Config.ExposedPorts}}' nginx
# Get labels
podman inspect --format='{{.Config.Labels}}' nginx
Image History¶
# View image layers
podman history nginx
# Show full commands
podman history --no-trunc nginx
# Human-readable sizes
podman history --human nginx
# Show layer IDs
podman history --format "{{.ID}} {{.Size}}" nginx
Image Tree¶
# Show image layers as tree
podman image tree nginx
# Show with layer IDs
podman image tree --whatrequires nginx
Image Scanning¶
Using Skopeo¶
# Inspect remote image
skopeo inspect docker://nginx:latest
# Copy image between registries
skopeo copy \
docker://nginx:latest \
docker://registry.example.com/nginx:latest
# Delete remote image
skopeo delete docker://registry.example.com/nginx:old
Vulnerability Scanning¶
# Using Trivy
trivy image nginx:latest
# Scan with severity filter
trivy image --severity HIGH,CRITICAL nginx:latest
# Generate report
trivy image --format json -o report.json nginx:latest
Working with Registries¶
Registry Configuration¶
[registries.search]
registries = ['docker.io', 'quay.io']
[registries.insecure]
registries = ['registry.local:5000']
[registries.block]
registries = []
Private Registry¶
# Run local registry
podman run -d -p 5000:5000 --name registry registry:2
# Tag for local registry
podman tag myapp:latest localhost:5000/myapp:latest
# Push to local registry
podman push localhost:5000/myapp:latest
# Pull from local registry
podman pull localhost:5000/myapp:latest
Authentication¶
# Login
podman login registry.example.com
# Login with credentials
podman login -u username -p password registry.example.com
# Logout
podman logout registry.example.com
# View stored credentials
cat ~/.config/containers/auth.json
Image Optimization¶
Reduce Image Size¶
Use Alpine Base¶
Multi-Stage Builds¶
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o app
FROM scratch
COPY --from=builder /app/app /app
CMD ["/app"]
Remove Unnecessary Files¶
Layer Caching¶
# Copy dependencies first (cached)
COPY package*.json ./
RUN npm install
# Copy source code last (changes frequently)
COPY . .
Image Formats¶
OCI vs Docker¶
# Build OCI format (default)
podman build --format oci -t myapp:latest .
# Build Docker format
podman build --format docker -t myapp:latest .
Manifest Lists¶
# 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 docker://registry.example.com/myapp:latest
Advanced Image Operations¶
Flatten Image¶
Modify Image¶
# Create container from image
podman create --name temp nginx
# Make changes
podman exec temp apt-get update
podman exec temp apt-get install -y curl
# Commit changes
podman commit temp nginx:modified
# Cleanup
podman rm temp
Image Diff¶
# Show changes in container
podman diff mynginx
# Output:
# C /etc
# A /etc/nginx/custom.conf
# D /tmp/cache
Troubleshooting Images¶
Debug Build Issues¶
# Build with verbose output
podman build --log-level=debug -t myapp .
# Build specific stage
podman build --target builder -t myapp:debug .
# Run intermediate container
podman run -it <layer-id> sh
Check Image Issues¶
# Verify image
podman inspect myapp:latest
# Check layers
podman history myapp:latest
# Test image
podman run --rm myapp:latest
Best Practices¶
- Use Official Base Images: Start with trusted images
- Keep Images Small: Use Alpine, multi-stage builds
- One Process Per Container: Follow single responsibility
- Don't Run as Root: Use USER directive
- Use .dockerignore: Exclude unnecessary files
- Tag Properly: Use semantic versioning
- Scan for Vulnerabilities: Regular security scans
- Document: Add LABEL instructions
- Cache Wisely: Order instructions for optimal caching
- Clean Up: Remove temporary files in same layer
Next Steps¶
Continue to: - Containers - Advanced container management - Pods - Working with pods - Networking - Container networking