feat: add Podman container-engine support alongside Docker
Goal
Add full Podman support as an alternative container engine alongside Docker, selected via [docker] engine = "podman". glci invokes the podman binary directly (no podman-docker shim) and works with no Docker installed.
How it works
glci drives a container engine by shelling out to its CLI (docker/podman) as a subprocess. This introduces a lightweight abstraction: an Engine value type + a process-wide defaultEngine + an engineCmd helper. The zero value is Docker, so every existing path is unchanged. Podman is CLI- and API-compatible with Docker, so gitlab-runner keeps executor = docker, talking to Podman's Docker-compatible socket mounted at /var/run/docker.sock.
Key divergences handled by the abstraction: the binary name, --context→--connection, DOCKER_HOST→CONTAINER_HOST, docker context inspect→podman system connection list, and socket paths (rootless $XDG_RUNTIME_DIR/podman/podman.sock, rootful /run/podman/podman.sock).
Scope
- Engine core —
pkg/daemon/engine.go:Enginetype, parsers,engineCmd/engineCmdCtx,engineAvailable,ResolveEffectiveEngine(explicit config + docker→podman auto-fallback). - DockerHost + package funcs — engine-aware
Command/buildEnv(strips both host env vars so none leaks across engines),detectPodmanSocket,InitEngine. - Config —
[docker] engine+ per-runner[runners.<name>] engine, with validation and merge. Orthogonal to[defaults] executor, which staysdockerunder Podman (gitlab-runner has no podman executor). - Provisioning/routing — engine resolved once at daemon startup and threaded per runner; the daemon reports its active engine via the health endpoint so CLI inspection commands stay consistent with it.
- CLI —
glci doctorreports the active engine and verifies the Podman API socket; inspection commands (ps,system,registry) route through the resolved engine. - Documentation — config-files, docker-network, cli-reference, architecture, the glci skill, README, and troubleshooting.
Docker-in-Docker
Rootful Podman DinD works (privileged defaults on); rootless Podman DinD is best-effort — documented as a known limitation.
Verification
go build ./...,go vet ./...,make test,go test -race(daemon/cmd/config) — green.make test-e2e-parse,make test-e2e-golden— golden fixtures unchanged (engineis a daemon-execution field, not a pipeline-parse field).- CLI integration (doctor/system) — green.
- The
unitjob was run locally via glci before pushing — pipeline PASSED. - Full fork MR pipeline is green (unit, unit:race, e2e:golden, comprehensive, all integration tiers incl. multi-daemon).
Review
Ran a multi-agent post-implementation review (correctness, performance, security, docs, concurrency, CLI-UX). All findings addressed: CLI
Note
Podman was not exercised on a real host in this environment — a smoke test with podman system service (glci doctor → run a simple pipeline → podman ps) is recommended before merge.