Podman

Podman

Run a container as a systemd service

  • Podman before 4.4

    1. Provision a running container
    podman run -d --name $container_name $image_name
    1. Generate a systemd service unit file for the container
    podman generate systemd --new --name $container_name > "$service_name.service"
    1. Verify and tweak the unit file if needed, and the deploy
    cp "$service_name.service" $HOME/.config/systemd/user
    1. Start and enable the service
      # Verify by running:
    > systemctl --user cat "$service_name.service"
    > systemctl --user start "$service_name.service"   # Verify it runs correctly
    > systemctl --user enable "$service_name.service"  # Auto start at login
  • Podman 4.4+

    1. Create a container unit file

      1.1 Manually

      # $HOME/.config/containers/systemd/$service_name.container
      # The container unit file has an extension of `.container`
      # It also has a dedicated section `Container`
      [Unit]
      Description=$container_description
      After=local-fs.target
       
      # The dedicated container section
      [Container]
      Image=$image
      Exec=$image_start_command
       
      [Install]
      # Start by default on boot
      WantedBy=multi-user.target default.target

      1.2 Using Podlet

      # Install Podlet
      brew install podlet
      # Generate a systemd container unit file
      podlet $podman_command_to_run_a_container
      # e.g. podlet podman run -d --publish 8080:8080 --name $container_name $image_name
    2. Create a systemd service unit file based on the container unit file

      systemctl --user daemon-reload
    3. Check the generated service unit file

      /usr/libexec/podman/quadlet -dryrun -user
    4. Check the service status

      systemctl --user status "$service_name.service"
    5. Start and enable the service

      systemctl --user start "$service_name.service"

Use rootless Podman

Convert running container(s) / pod(s) / volume(s) -> Kubernetes manifest

Podman will always generate the specification as a Pod, as the smallest deployable unit in Kubernetes.

podman generate kube [$container_name... | $pod_name... | $volume_name...] > $kubernetes_yaml_file

Run a Pod using an existing Kubernetes YAML

podman kube play $kubernetes_yaml_file

Health Check

Quadlet (systemd)

Quadlets allow you to manage containers declaratively using systemd.

Since version 4.4, Podman can create, start, and manage containers (including pulling images, creating volumes, and managing pods) through systemd.

Quadlets are simplified systemd unit files, recognized by their specific extensions, such as *.container, *.pod, or *.image that are processed during startup or when you reload the daemon using the systemctl daemon-reload command.

Quadlets generate the equivalent systemd unit files, streamlining the container management process.

Quadlet supports these unit file types:

  • Container units: Used to manage containers by running the podman run command.

    • File extension: .container
    • Section name: [Container]
    • Required fields: Image describing the container image the service runs
  • Kube units: Used to manage containers defined in Kubernetes YAML files by running the podman kube play command.

    • File extension: .kube
    • Section name: [Kube]
    • Required fields: Yaml defining the path to the Kubernetes YAML file
  • Network units: Used to create Podman networks that may be referenced in .container or .kube files.

    • File extension: .network
    • Section name: [Network]
    • Required fields: None
  • Volume units: Used to create Podman volumes that may be referenced in .container files.

    • File extension: .volume
    • Section name: [Volume]
    • Required fields: None
  • Resources

Convert a Podman container / pod / network / volume / image -> Quadlet (systemd unit file)

podlet generate [$container_name... | $pod_name... | $network_name... | $volume_name... | $image_name...] > $quadlet_file

Convert a Docker Compose spec file -> Quadlet

Generate Podman Quadlet files from a compose file
 
Creates a `.container` file for each service, a `.volume` file for each volume (if it has additional options set), and a `.network` file for each network.
 
The `--file` option must be a directory if used.
 
Some compose options are not supported, such as `build`.
 
When Podlet encounters an unsupported option, an error will be returned. Modify the compose file to resolve the error.
 
Usage: podlet compose [OPTIONS] [COMPOSE_FILE]
 
Arguments:
  [COMPOSE_FILE]
          The compose file to convert
 
          If `-` or not provided and stdin is not a terminal, the compose file will be read from stdin.
 
          If not provided, and stdin is a terminal, Podlet will look for (in order) `compose.yaml`, `compose.yml`, `docker-compose.yaml`, and `docker-compose.yml`, in the current working directory.
 
Options:
      --pod
          Create a `.pod` file and link it with each `.container` file.
 
          The top-level `name` field in the compose file is required when using this option. It is used for the name of the pod and in the filenames of the created files.
 
          Each container becomes a part of the pod and is renamed to "{pod}-{container}".
 
          Published ports are taken from each container and applied to the pod.
 
      --kube
          Create a Kubernetes YAML file for a pod instead of separate containers
 
          A `.kube` file using the generated Kubernetes YAML file is also created.
 
          The top-level `name` field in the compose file is required when using this option. It is used for the name of the pod and in the filenames of the created files.
 
  -h, --help
          Print help (see a summary with '-h')

Create a .pod unit file and link it with each .container unit file

podlet compose --pod ${docker_compose_file} > ${quadlet_file}

Example:

# compose.yml
name: paperless-postgres
 
services:
  postgres:
    image: docker.io/postgres:16
    container_name: db-postgres
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: paperless
      PGDATA: /var/lib/postgresql/data/pgdata
    ports:
      - "5432:5432"
    restart: on-failure
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "paperless"]
      interval: 30s
      timeout: 30s
      retries: 3
# Need to extract file content from the genrated output, and save it to each unit file respectively
 podlet compose --pod compose.yml
# paperless-postgres-postgres.container
[Container]
ContainerName=db-postgres
Environment=POSTGRES_DB=paperless POSTGRES_USER=paperless POSTGRES_PASSWORD=paperless PGDATA=/var/lib/postgresql/data/pgdata
HealthCmd=["pg_isready","-U","paperless"]
HealthInterval=30s
HealthRetries=3
HealthTimeout=30s
Image=docker.io/postgres:16
Pod=paperless-postgres.pod
 
[Service]
Restart=on-failure
 
---
 
# paperless-postgres.pod
[Pod]
PublishPort=5432:5432

Create a single Kubernetes YAML file for all resources involved

podlet compose --kube ${docker_compose_file} > ${kubernetes_manifest_file}

Use [Kube] section in the systemd unit file (by convention, use .kube) to reference the generated Kubernetes manifest.

# service_name.kube
[Unit]
Description=Podman Pod Name

[Kube]
Yaml=/path/to/kubernetes_manifest.yaml

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target

Tooling

Podman Desktop

Podman TUI

podman-compose

Oh-my-zsh plugin

Container Registry - Public

Docker Hub (opens in a new tab)

Red Hat - Quay.io (opens in a new tab)