OFFSET偏移
← All articlesOFFSET / FIELD NOTESNO. 124

Compose providers and interoperability with Docker tools

Separate the responsibilities of Compose implementations, the Podman wrapper, and the compatible API socket.

English translation · Code and commands follow the Chinese original.

IN THESE READING PATHSPodman container workflows ↗
About 4 min readStart reading

Use Docker Compose syntax with the Podman engine, and connect tools such as VS Code Dev Containers.


What Is podman-compose?#

podman-compose is a Python script that lets Podman read docker-compose.yml files. It is a separately maintained Compose implementation. Check Compose feature support for its specific version rather than confusing it with the podman compose wrapper.

Installation

# 可变发行版可在隔离 Python 工具环境安装;不是所有系统通用
pipx install podman-compose
# 需 Python/pipx;NixOS 用 Nix 声明包,避免绕过配置安装

# Fedora
sudo dnf install podman-compose

# Arch:先确认当前官方仓库包
sudo pacman -Syu podman-compose

Basic Usage

# 和 docker-compose 命令几乎一样,把 docker 换成 podman
podman-compose up -d         # 启动所有服务(后台)
podman-compose ps             # 查看服务状态
podman-compose logs -f        # 跟踪日志
podman-compose stop           # 停止所有服务
podman-compose down           # 停止并删除容器、网络
podman-compose down -v        # 同时删除卷(数据丢失!)
podman-compose restart web    # 重启指定服务

Example docker-compose.yml

services:
  db:
    image: docker.io/library/postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?provide a non-public password}"
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: always

  web:
    image: docker.io/library/nginx:alpine
    ports:
      - "127.0.0.1:8080:80"
    depends_on:
      - db

volumes:
  pgdata:
podman-compose up -d
# 效果和 docker-compose up -d 几乎一样

Docker Socket Compatibility: Use Docker Tools with Podman#

Many tools, including VS Code Dev Containers, Testcontainers, and some CI systems, assume a Docker socket exists. Podman can emulate this socket.

Enable the Podman Socket

# 启动用户级 Docker 兼容 socket
systemctl --user enable --now podman.socket

# 设置环境变量,让 Docker 客户端连接到 Podman 的 socket
export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock

# 把这个写入 shell 配置文件以便永久生效
# Bash 中可将上述 export 按配置管理方式保存;NixOS/Home Manager 写 Nix 源配置

Verify Compatibility

# 装了 DOCKER_HOST 后
docker ps        # 实际调用的是 Podman
docker compose up # 也能用

# 如果系统还装了 docker CLI(没有 dockerd)
# docker 命令会使用 DOCKER_HOST 指向 Podman socket

Connect VS Code Dev Containers#

With VS Code Dev Containers, you can try the Podman CLI or the Docker-compatible API. Verify the configuration, mounts, and feature support against your extension version:

# 1. 启用 podman socket
systemctl --user enable --now podman.socket

# 2. 设置环境变量
export DOCKER_HOST=unix:///run/user/$UID/podman/podman.sock

# 3. 在 VS Code 设置中
# "dev.containers.dockerPath": "podman"
# 或者直接用 Docker 路径,通过 DOCKER_HOST 转发

Known Issues

  • The Dev Containers remoteUser field behaves differently in rootless mode: root inside a container is not root on the host
  • In some devcontainer.json files, the mounts syntax may require adjustments to path permissions
  • Configure containerUser and remoteUser according to the image's users and UID mappings. Setting them to root is not a universal fix for mount errors, and rootless mode alone does not eliminate the need to assess risk

podman-compose Compatibility Pitfalls#

Unsupported Features

Docker Compose Feature Supported by podman-compose? Alternative
depends_on + condition: service_healthy The current implementation supports this condition; verify your version and use case Check the health command and actual waiting behavior; Quadlet requires a readiness-notification design
deploy.resources.limits Partial Explicit --memory and --cpus arguments
secrets: Supported in the current source; still verify sources and attributes Check file/environment/external semantics and permissions
profiles: Supported by the current implementation Check --profile, COMPOSE_PROFILES, and expansion of the selected services
network_mode: host Yes (with limitations in rootless mode) —

Port-mapping Differences

# Docker 中:容器可直接暴露 80 端口
# Podman rootless:是否可绑低端口取决于系统政策,示例优先高端口
ports:
  - "127.0.0.1:8080:80"   # 正确
  # - "80:80"   # 可能受系统非特权端口边界限制

Volume Permission Issues

volumes:
  - ./data:/var/lib/mysql
  # podman rootless 下,容器内进程 UID 映射为宿主机普通用户
  # 如果数据目录属于 root,容器内可能无法写入
  # 核对应用UID映射与目录权限;当前用户拥有目录也不保证映射后的应用用户能写

When Should You Use Quadlet or podman-compose?#

Scenario Recommended Tool Reason
Development environment (local debugging) podman-compose Share docker-compose.yml with the team and start or stop services quickly
Production server Quadlet Native systemd management, startup at boot, unified logs, and automatic updates
Single-container service Quadlet One .container file is enough
Temporary tests/CI podman run / podman-compose One-off tasks do not need persistent configuration
Migration to K8s required Pod + generate kube Export the Pod as K8s YAML for deployment

Convenient Aliases#

The following examples use Bash; save them through your configuration-management workflow. Fish uses different environment-variable syntax:

# 让 docker 命令实际运行 podman
alias docker=podman
alias docker-compose=podman-compose

# 需要 DOCKER_HOST 时
export DOCKER_HOST=unix:///run/user/$UID/podman/podman.sock


The podman compose Wrapper and Provider Selection#

podman compose does not interpret the Compose specification itself. It calls an external provider and prepares the environment for connecting to the Podman socket. By default it tries docker-compose and podman-compose, giving an installed docker-compose priority. You can specify a path through [engine] compose_providers in containers.conf or the PODMAN_COMPOSE_PROVIDER environment variable.

# 只检查命令/版本与provider支持参数
podman compose --help
podman-compose --version
# 选择明确安装好的provider;此调用可能启动容器
PODMAN_COMPOSE_PROVIDER=/path/to/podman-compose podman compose up -d

The Docker CLI and a Podman alias are different approaches: the real docker CLI reads DOCKER_HOST, while alias docker=podman invokes Podman directly. API compatibility does not guarantee identical behavior across all plugins and tools. Socket permissions also grant the corresponding user's container-management capabilities; do not expose an unprotected TCP API. Supply passwords for the Compose examples through a controlled environment, and never commit .env or secrets files to the repository. The short syntax for depends_on does not automatically wait for the database to be ready. Verify both providers' features and deprecations against their versions.

References & further reading

  1. Official Podman run Manual ↗
  2. Official Podman Overview and Rootless Mode ↗
  3. Podman Compose Provider Mechanism ↗
  4. Official podman-compose Project ↗
  5. podman-compose Feature Source Code ↗

Adapted from technical notes. Examples use generic names.

Continue along a reading path

Podman container workflows

  1. 01Podman fundamentals
  2. 02A basic Podman usage guide
  3. 03Rootless containers: whose file permissions count?
  4. 04Rootless configuration: mappings, ICMP, and registries
  5. 05Pods and Kubernetes manifests
  6. 06How does Quadlet turn container declarations into services?
  7. 07Pods and multi-service configuration with Quadlet
  8. 08Compose providers and interoperability with Docker tools
  9. 09Managing Podman on NixOS
  10. 10Advanced Podman operations and tuning
  11. 11Docker and Podman: architecture, compatibility, and coexistence
CONTINUE READING / NEXT ARTICLEManaging Podman on NixOS

Declare container runtime environments through system modules, Home Manager, or quadlet-nix.