Skip to content
COMA

Podman

Use rootless Podman on a remote machine through COMA, with the podman CLI, a docker alias for it, or the Docker CLI.

COMA works with Podman on the machine the same way it works with Docker: the endpoint on your computer forwards to the machine's engine over SSH, bind mounts resolve to the synced copy, and published ports are mirrored to localhost. This guide covers what is specific to Podman. For how engines are chosen, see Engines.

Install Podman on the machine

On a Debian or Ubuntu machine without an engine, coma machine bootstrap installs rootless Podman from the distribution's own packages:

coma machine bootstrap dev --engine podman

COMA shows the plan, with every command it would run, and asks before it changes anything. The Podman steps install podman, uidmap and dbus-user-session, enable lingering for your SSH user and start that user's Podman socket. If you connect as root, COMA uses the system socket and skips lingering. Steps marked sudo need passwordless sudo. Add --plan to see the plan without changing anything, and --yes to skip the question. See Bootstrap a bare VM.

Connect

coma connect dev --engine podman

--engine is needed only when the machine has both Docker and Podman. Connecting to a Podman engine does two things:

  • the Docker context coma points at the machine's Podman, through its Docker-compatible API, so the Docker CLI and docker compose reach it;
  • COMA adds a podman connection called coma and makes it podman's default, so the podman CLI, and a docker alias for it, reach the machine too.

Every new shell picks both up. coma disconnect switches the Docker CLI back and restores podman's previous default, unless you changed the default yourself since connecting. Connecting to a Docker engine also restores podman's default, because a Docker engine cannot serve the podman CLI.

If a podman connection named coma already exists and COMA did not create it, COMA leaves it alone and warns; the Docker context still works. --replace lets COMA take it over.

For a workspace, set the engine in coma.yaml:

spec:
  runtime:
    engine: podman

or pass it once with coma workspace up --engine podman.

One shell only

To point the podman CLI at the machine in the current shell without changing podman's default, connect with --no-switch, then:

eval "$(coma endpoint env --podman)"

This sets CONTAINER_HOST and unsets CONTAINER_CONNECTION. See Tools that ignore Docker contexts.

The docker alias trap

Many Podman users have alias docker=podman. Podman ignores Docker contexts and DOCKER_HOST; it reads CONTAINER_HOST or its own default connection. So with the alias:

  • coma connect dev --engine docker switches the Docker context, but docker run still runs podman against its old default, usually the local Podman machine;
  • DOCKER_HOST=… docker run does the same.

Nothing fails. The containers start on your laptop, and the output looks normal. During dogfooding, a coding agent ran a whole task this way before anyone noticed.

To avoid it:

  • With a docker alias for podman, use the Podman engine: coma connect dev --engine podman. The alias then reaches the machine through podman's default connection.
  • To keep a Docker engine, bypass the alias with command docker, which runs the real Docker CLI (it must be installed).
  • For one shell, use eval "$(coma endpoint env --podman)".

coma doctor checks where the podman CLI points while you are connected:

WARN  cli-routing            connected to dev's Docker engine, but the podman CLI (and a `docker` alias for it) uses "podman-machine-default", not the machine
                             -> connect with --engine podman, or bypass the alias with `command docker`

Its local-fallback check also lists containers created on a local engine while you were connected. See Troubleshooting.

Compose on Podman

The Docker CLI with Compose v2 works against a Podman engine through the coma context.

podman compose is a wrapper: it runs an external Compose program, and it prefers Docker's docker-compose when one is installed, even if podman-compose is installed too. On your laptop it runs the first docker-compose on PATH, which may be the old Compose v1; coma doctor reports every Compose v1 it finds. Older podman-compose releases have their own bugs: version 1.2.0 crashed on run with the stack already up.

Builds are slower

Podman has no built-in BuildKit, so docker compose up --build against a Podman engine creates a builder container on the machine (buildx_buildkit_coma). Each built image is then exported as a tarball through your computer and loaded back into Podman. On a distant machine this is slow: a small Python image spent 27 s sending its tarball at 260 ms round-trip time. The builder container keeps running afterwards.

  • Prefer a Docker engine for Compose projects that build images, or build with podman build.
  • Remove the builder with docker buildx rm when you no longer need it.

Image short names

Podman resolves unqualified names such as redis:7-alpine through the search registries in registries.conf. Ubuntu's Podman package configures none, while the Fedora-based Podman machine on a Mac searches Docker Hub. So the same command works locally and fails on the machine when it goes through the podman CLI. The Docker CLI and Compose are not affected: Podman's Docker-compatible API assumes Docker Hub.

Either fully qualify image names:

podman run docker.io/library/redis:7-alpine

or add unqualified-search-registries = ["docker.io"] to the machine's registries.conf.

What works

Podman has been checked against fewer scenarios than Docker. These work through COMA with a Podman engine:

  • podman run with -p and a synced bind mount, and with -P;
  • podman run -it with exit codes, run -i and exec -i with piped input;
  • podman pod create -p, with the pod's ports mirrored to localhost;
  • podman build with a local build context;
  • Testcontainers (Node), including Ryuk cleanup.

As with Docker, published ports are moved to 127.0.0.1 on the machine and bind mounts outside a synced directory are refused.

podman kube play is refused, because COMA does not yet check hostPort and hostPath in Kubernetes YAML. Use podman run, podman pod create or Compose instead.

On this page