Skip to content

Instantly share code, notes, and snippets.

@virtuallyunknown
Created August 20, 2026 23:19
Show Gist options
  • Select an option

  • Save virtuallyunknown/bbed8d4312e573bc326778cb03ed2291 to your computer and use it in GitHub Desktop.

Select an option

Save virtuallyunknown/bbed8d4312e573bc326778cb03ed2291 to your computer and use it in GitHub Desktop.
Podman cheetsheet/starter

Podman Cheatsheet

Images

Command Description
podman pull <image> Pull an image from a registry
podman images List local images
podman image inspect <image> Show detailed image info
podman rmi <image> Remove an image
podman tag <image> <new-tag> Tag an image
podman build -t <name> . Build image from Dockerfile in current dir
podman build -t <name> -f <Dockerfile> . Build from a specific Dockerfile

Containers — Create & Run

# Run a container interactively (removed on exit)
podman run -it --rm <image> bash

# Run detached (background)
podman run -d --name <name> <image>

# Run with port mapping (host:container)
podman run -d -p 8080:80 <image>

# Run with environment variables
podman run -d -e MY_VAR=value <image>

# Run with a named volume mounted
podman run -d -v myvolume:/data <image>

# Run with a bind mount (host path)
podman run -d -v /host/path:/container/path:Z <image>
# :Z fixes SELinux labeling on Fedora/RHEL

# Run with multiple options combined
podman run -d \
  --name myapp \
  -p 3000:3000 \
  -e NODE_ENV=production \
  -v mydata:/app/data \
  node:20

Rootless tip: Podman runs containers as your user by default — no root required.


Container Lifecycle

Command Description
podman ps List running containers
podman ps -a List all containers (including stopped)
podman start <name|id> Start a stopped container
podman stop <name|id> Gracefully stop a container
podman kill <name|id> Force-kill a container
podman restart <name|id> Restart a container
podman rm <name|id> Remove a stopped container
podman rm -f <name|id> Force-remove a running container
podman rm $(podman ps -aq) Remove all stopped containers

Inspecting Containers

# View logs
podman logs <name>
podman logs -f <name>           # Follow (tail) logs

# Get detailed container info
podman inspect <name>

# Show resource usage
podman stats

# Show running processes inside container
podman top <name>

# Show port mappings
podman port <name>

Executing Commands in Containers

# Open an interactive shell in a running container
podman exec -it <name> bash
podman exec -it <name> sh       # if bash is not available

# Run a one-off command
podman exec <name> ls /app

# Run as a specific user
podman exec -it -u root <name> bash

Volumes

Managed (Named) Volumes

# Create a volume
podman volume create myvolume

# List volumes
podman volume ls

# Inspect a volume (see mount path on host)
podman volume inspect myvolume

# Remove a volume
podman volume rm myvolume

# Remove all unused volumes
podman volume prune

Bind Mounts

# Mount a host directory into a container
podman run -v /absolute/host/path:/container/path <image>

# Read-only bind mount
podman run -v /host/path:/container/path:ro <image>

# With SELinux relabeling (required on RHEL/Fedora for file access)
podman run -v /host/path:/container/path:Z <image>

Use :Z for private (single container) mounts, :z for shared (multiple containers).


Networks

Default Behaviour

  • Rootless containers share a private network namespace.
  • Containers on the same pod or explicitly the same network can communicate.

Common Network Commands

# List networks
podman network ls

# Create a custom network
podman network create mynet

# Connect a running container to a network
podman network connect mynet <name>

# Run a container on a specific network
podman run -d --network mynet --name app1 <image>

# Containers on the same network can reach each other by container name
# e.g. from app1: curl http://db:5432

# Inspect a network
podman network inspect mynet

# Remove a network
podman network rm mynet

Pods

Pods group containers that share the same network namespace (like Kubernetes pods).

# Create a pod with a port published
podman pod create --name mypod -p 8080:80

# Run containers inside the pod
podman run -d --pod mypod --name frontend nginx
podman run -d --pod mypod --name backend myapp

# List pods
podman pod ls

# Stop / start / remove a pod (and all its containers)
podman pod stop mypod
podman pod start mypod
podman pod rm -f mypod

Compose

Compatibility with Docker Compose

podman-compose implements the Compose Spec — the same spec that Docker Compose v2 uses. In practice:

  • Most docker-compose.yml files work unchanged with podman-compose.
  • Not every Compose feature is implemented (some deploy, build.cache_from, and Swarm-specific keys may be ignored or unsupported).
  • Podman-specific extensions can be added under the x-podman: key (e.g. userns_mode, passwd).
  • podman compose (the built-in subcommand) is a thin wrapper that delegates to whichever provider is installed — docker-compose takes precedence if both are installed.
  • The top-level version: field is obsolete in the current Compose Spec and will trigger a warning — omit it.

Documentation


Installation

# Fedora / RHEL
sudo dnf install podman-compose

# Debian / Ubuntu
sudo apt install podman-compose

# pip (latest stable)
pip3 install --user podman-compose

Anatomy of a Compose File

# compose.yaml  (preferred filename; docker-compose.yml also works)

services:
  <service-name>:
    image: <image>          # or use `build:` instead
    container_name: <name>  # optional; defaults to <project>_<service>_1
    restart: unless-stopped
    ports:
      - "<host>:<container>"
    environment:
      - KEY=value
    env_file:
      - .env
    volumes:
      - <named-vol>:<container-path>
      - ./relative/host/path:/container/path:Z
    networks:
      - <network-name>
    depends_on:
      - <other-service>

volumes:
  <named-vol>:              # declare named volumes here

networks:
  <network-name>:           # declare custom networks here

Translating CLI Commands to Compose

CLI compose.yaml equivalent
podman run -d nginx image: nginx
-p 8080:80 ports: ["8080:80"]
-e KEY=val environment: [KEY=val]
-v mydata:/data volumes: [mydata:/data] + top-level volumes: {mydata:}
-v $(pwd):/app:Z volumes: [.:/app:Z]
--network mynet networks: [mynet] + top-level networks: {mynet:}
--name myapp container_name: myapp
--restart unless-stopped restart: unless-stopped

Example — before (CLI):

podman run -d \
  --name myapp \
  -p 8080:80 \
  -e NODE_ENV=production \
  -v mydata:/app/data \
  -v $(pwd):/app:Z \
  node:20

After (compose.yaml):

services:
  myapp:
    image: node:20
    container_name: myapp
    ports:
      - "8080:80"
    environment:
      - NODE_ENV=production
    volumes:
      - mydata:/app/data
      - .:/app:Z

volumes:
  mydata:

Multi-Service Example

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro,Z
    depends_on:
      - api
    networks:
      - frontend

  api:
    image: node:20
    working_dir: /app
    volumes:
      - .:/app:Z
    environment:
      - DB_HOST=db
      - DB_PORT=5432
    depends_on:
      - db
    networks:
      - frontend
      - backend

  db:
    image: postgres:16
    environment:
      - POSTGRES_USER=myuser
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=mydb
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - backend

volumes:
  pgdata:

networks:
  frontend:
  backend:

Common Compose Commands

# Start all services (detached), building images if needed
podman compose up -d

# Start and force rebuild images
podman compose up -d --build

# Stop and remove containers (keeps volumes)
podman compose down

# Stop and remove containers AND named volumes
podman compose down -v

# View logs for all services
podman compose logs -f

# View logs for a single service
podman compose logs -f <service>

# Execute a command in a running service container
podman compose exec <service> bash

# Run a one-off command in a new container
podman compose run --rm <service> <command>

# List containers managed by this compose file
podman compose ps

# Pull latest images without starting
podman compose pull

# Restart a single service without touching others
podman compose restart <service>

# Scale a service to N replicas
podman compose up -d --scale <service>=3

Environment Variables in Compose

# .env file in the same directory is loaded automatically
# compose.yaml can reference variables with ${VAR} syntax
services:
  db:
    image: postgres:${PG_VERSION:-16}   # fallback default after :-
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
# .env
PG_VERSION=16
DB_PASSWORD=secret

Override for a single run without editing .env:

PG_VERSION=15 podman compose up -d

Rootless-Specific Notes

# Add userns_mode so files written inside the container are owned by your
# host user (equivalent to --userns=keep-id on the CLI)
services:
  myapp:
    image: node:20
    userns_mode: keep-id        # podman-compose extension (x-podman not needed)
    volumes:
      - .:/app:Z

Without userns_mode: keep-id, files created inside the container may appear owned by a different UID on the host.


Cleanup

# Remove all stopped containers
podman container prune

# Remove unused images
podman image prune

# Remove unused volumes
podman volume prune

# Remove everything unused (containers, images, volumes, networks)
podman system prune -a --volumes

Podman in VSCode

VSCode can attach to a running Podman container via the Dev Containers extension (previously "Remote - Containers"), with Podman as the container engine.

1. Install the Extension

Search for Dev Containers (ms-vscode-remote.remote-containers) in the Extensions panel and install it.

2. Point VSCode at Podman (instead of Docker)

Open Settings (Ctrl+,) and search for Dev Containers: Docker Path.
Set it to the Podman socket or binary:

// settings.json
{
  "dev.containers.dockerPath": "podman"
}

Alternatively, create a Docker-compatible socket so the extension uses the standard path:

# Enable the Podman socket (systemd user service)
systemctl --user enable --now podman.socket

# Verify the socket exists
ls $XDG_RUNTIME_DIR/podman/podman.sock

# Tell VSCode where the socket is
# Add to settings.json:
# "docker.host": "unix:///run/user/1000/podman/podman.sock"

Replace 1000 with your actual UID (id -u).

3. Start a Container to Attach To

Option A — plain container with a shell and sleep loop so it stays alive:

podman run -d \
  --name devbox \
  -v $(pwd):/workspace:Z \
  -w /workspace \
  ubuntu:24.04 \
  sleep infinity

Option B — use a pre-built devcontainer image:

podman run -d \
  --name devbox \
  -v $(pwd):/workspace:Z \
  -w /workspace \
  mcr.microsoft.com/devcontainers/base:ubuntu \
  sleep infinity

4. Attach VSCode to the Running Container

  • Open the Command Palette (Ctrl+Shift+P)
  • Run Dev Containers: Attach to Running Container…
  • Select devbox from the list

A new VSCode window opens with the filesystem rooted inside the container.
Extensions installed in that window live inside the container.

5. Use a devcontainer.json (Recommended)

Add .devcontainer/devcontainer.json to your project for a reproducible setup:

{
  "name": "My Dev Container",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "runArgs": ["--userns=keep-id"],
  "mounts": [
    "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached"
  ],
  "workspaceFolder": "/workspace",
  "customizations": {
    "vscode": {
      "extensions": [
        "ms-python.python",
        "esbenp.prettier-vscode"
      ]
    }
  },
  "postCreateCommand": "echo 'Container ready!'"
}

Then open the project folder in VSCode and run:
Dev Containers: Reopen in Container (Ctrl+Shift+P)

--userns=keep-id maps your host UID into the container so files created inside are owned by you on the host — important for rootless Podman.

6. Forwarding Ports from the Container

While attached to the container, use the Ports panel (bottom bar) to forward ports, or add "forwardPorts": [3000, 8080] to devcontainer.json.


Quick Reference Card

podman pull <img>               Download image
podman build -t <tag> .         Build image
podman run -it <img> bash       Interactive container
podman run -d <img>             Detached container
podman ps / ps -a               List running / all
podman exec -it <n> bash        Shell into running container
podman stop / rm <n>            Stop / remove container
podman logs -f <n>              Tail logs
podman volume create <v>        Create volume
podman volume ls                List volumes
podman network create <n>       Create network
podman system prune -a          Clean up everything

podman compose up -d            Start all services (detached)
podman compose up -d --build    Start and rebuild images
podman compose down             Stop and remove containers
podman compose down -v          Also remove named volumes
podman compose logs -f          Tail all service logs
podman compose exec <svc> bash  Shell into a service
podman compose ps               List compose-managed containers
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment