Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions planning/releases/0.4.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# compose2pod 0.4.0 — Podman 5.x support: the script owns `/etc/hosts`

Generated scripts now own `/etc/hosts` outright instead of asking Podman to
populate it with pod-level `--add-host`. Every container runs under `--no-hosts`
and bind-mounts a hosts file compose2pod writes at run time. Because Podman no
longer manages the file, the pre-6.0.0 bug that wiped it can no longer fire —
pod-internal name resolution is now correct on **every** Podman version,
including the 5.x line that has no fix for that bug. The `Podman >= 6.0.0`
requirement is gone.

## Why

Before 6.0.0, a container stopping inside a multi-container pod made Podman
regenerate the pod's shared `/etc/hosts` and delete every entry — wiping the
`--add-host` set that was the pod's only source of name resolution. A
`service_completed_successfully` dependency (a migration that runs and exits)
triggered it, producing a `could not translate host name` failure deep inside an
unrelated service, minutes after the script appeared to succeed.

The fix ([containers/podman#28494](https://github.com/containers/podman/pull/28494))
first shipped in Podman 6.0.0 and was **never backported to any 5.x** — verified
against the `v5.8` release notes and tag containment for 5.8.0–5.8.5. Anyone
pinned to a Fedora-based Podman 5.x image could not get a fixed Podman, and the
0.3.0 run-time version guard could only *warn*, not fix. This release removes the
cause instead of warning about it.

## Change

- **The script owns `/etc/hosts`.** `podman pod create` and every `podman run`
now carry `--no-hosts`; no `--add-host` is emitted. The script writes a full
hosts file to a `mktemp` path — `127.0.0.1 localhost`, `::1 localhost`, each
service alias/hostname → `127.0.0.1`, each `extra_hosts` host → its address —
and bind-mounts it read-only into every container as
`-v "$hostsfile":/etc/hosts:ro,z`, removing it on teardown. The `z` relabel is
mandatory on SELinux-enforcing hosts (Fedora) and a no-op elsewhere.
- **Works on any Podman.** With `--no-hosts`, Podman never rewrites the file, so
the stop-wipe cannot occur regardless of version. Behavior is identical on 5.x
and 6.x.
- **The Podman-version guard is removed.** The run-time warning 0.3.0 added
existed only to flag the now-impossible bug, so it is deleted along with the
documented version floor.

## Downstream

- **No pre-editing needed on Podman 5.x.** Compose files with a run-to-completion
dependency that previously lost name resolution now work unchanged.
- **`host.containers.internal` / `host.docker.internal` are no longer provided.**
Under `--no-hosts`, compose2pod cannot resolve Podman's gateway IP to synthesize
them (Docker Compose on Linux does not add them by default either). A service
that needs to reach the host adds an explicit `extra_hosts` entry with the
address it wants.
- **Everything else is unchanged.** The alias/hostname resolution set, the
`extra_hosts` merge, and the conflict rule (a name landing on two addresses is
refused) behave exactly as before — only the mechanism that carries them to the
container changed.

## Internals

- Tests at 100% line coverage (enforced); `ruff select=ALL`, `ty`, `eof-fixer`
clean; the conformance harness (real Docker CLI) and integration harness (real
Podman) both green — the integration suite exercises name resolution surviving a
completion container's stop.
- The mechanism was validated end-to-end in a Fedora CoreOS VM before it was
written: with `--no-hosts` and the bind-mounted file, a container's stop leaves
the hosts file byte-identical, and the missing `:z` relabel was caught there
(an un-relabeled mount is unreadable inside the container). See
`planning/changes/2026-07-20.01-own-etc-hosts-via-no-hosts.md` for the full
rationale, the upstream research, and the rejected alternatives.