Skip to content

Add --add-host flag for static /etc/hosts entries#1563

Open
bilby91 wants to merge 1 commit into
apple:mainfrom
crunchloop:fix/add-host-flag
Open

Add --add-host flag for static /etc/hosts entries#1563
bilby91 wants to merge 1 commit into
apple:mainfrom
crunchloop:fix/add-host-flag

Conversation

@bilby91
Copy link
Copy Markdown

@bilby91 bilby91 commented May 15, 2026

Summary

Add a --add-host host:ip flag on container create / container run (repeatable), so callers can inject arbitrary host-to-IP mappings into the container's /etc/hosts. Mirrors Docker's flag of the same name and compose's extra_hosts.

The daemon already builds a minimal /etc/hosts (loopback + the container's primary-interface address) and the SandboxService even carries a hint at this gap:

// NOTE: We can support a user providing new entries eventually, but
// for now craft a default /etc/hosts.

This PR fills that in by mirroring the existing --dns-* flag plumbing.

Changes

  • Flags.Management gains an --add-host @Option (repeatable, host:ip format).
  • Parser.extraHosts(_:) validates each value via IPAddress (accepts both IPv4 and IPv6) and splits on the first : — DNS hostnames cannot contain :, so the first colon is unambiguous as the separator and IPv6 addresses (host:2001:db8::1) parse correctly.
  • ContainerConfiguration gains an extraHosts: [ExtraHost] field, decoded with decodeIfPresent and defaulting to [] so older snapshots decode unchanged.
  • Utility.makeContainerConfig plumbs parsed values into the new field.
  • SandboxService appends each ExtraHost to hostsEntries before constructing the Hosts(entries:) written into the VM.

Motivation

We're building crunchloop/devcontainer — an open-source Go runtime for Dev Containers — and are wiring up apple/container as a backend alongside Docker. Several Dev Container / compose features need static host mappings:

  • extra_hosts in compose service definitions.
  • Aliasing an external service (DB, API) to a stable name inside the container so application config doesn't need per-environment URLs.
  • Pointing services at the host loopback (the typical host.docker.internal-style escape hatch).

Without --add-host today, the workaround is to container runcontainer inspectcontainer exec --user 0 to append to /etc/hosts post-start, which is racy (intra-level peers can resolve each other before either has been patched) and brittle (fails for distroless images that have no sh).

The capability is also useful well beyond compose — anything that needs deterministic name resolution without standing up a DNS server: pinning a CI artifact registry by IP, aliasing internal hostnames in air-gapped environments, etc. It's the same role --add-host plays in Docker, --dns-search plays today in apple/container, and extra_hosts plays in compose.

Test plan

  • swift build (full project) — clean
  • swift test --filter "ParserTest|ContainerConfigurationExtraHostsTests" — 12/12 pass
    • Parser: IPv4, IPv6, multiple flags, IPv6 full-form host:2001:db8::1, rejects missing colon, rejects empty hostname / IP, rejects invalid IP
    • Flags: --add-host db:192.168.66.2 --add-host cache:192.168.66.3 round-trips through Flags.Management.parse
    • Configuration: legacy JSON (no extraHosts key) decodes to extraHosts == []; populated values round-trip through JSON; default-initialized config has extraHosts == []
  • make fmt — no changes

Notes

  • Format strictly follows Docker's: --add-host host:ip only. host:host-gateway and host=ip are deliberately out of scope; either can be added in a follow-up without breaking this surface.
  • No existing tracking issue (filed this directly per apple/container's general "small fixes welcome" guidance in CONTRIBUTING.md). Happy to file an issue first if maintainers prefer.

The container daemon currently builds a minimal `/etc/hosts` containing
only loopback and the container's own primary-interface address — there
is no way for a caller to inject arbitrary host-to-IP mappings.
SandboxService even carries a comment hinting at this:

    // NOTE: We can support a user providing new entries eventually, but
    // for now craft a default /etc/hosts.

Add a `--add-host host:ip` flag on `container create` / `container run`
(repeatable, matching Docker's flag of the same name and compose's
`extra_hosts`). The flag values flow through `Flags.Management` →
`Parser.extraHosts` → `ContainerConfiguration.extraHosts` → SandboxService,
where each entry is appended to the `/etc/hosts` written before user
processes start.

The parser mirrors the existing `--dns-*` plumbing: separate `@Option`
on the `Management` flag group, validation via `IPAddress` (accepts both
IPv4 and IPv6), splitting on the *first* `:` so that IPv6 addresses
(which themselves contain `:`) parse correctly. DNS hostnames cannot
contain `:`, so the first colon is unambiguous as the separator.

`ContainerConfiguration.extraHosts` is decoded with `decodeIfPresent`
and defaults to `[]`, so configurations encoded by older daemons (or
clients that never set the field) decode unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants