Skip to content

engine: refuse network_mode: host when the host netns is shared #136

Description

@bilby91

Symptom

A compose-source devcontainer whose service declares

services:
  app:
    network_mode: host

is passed straight through when the engine runs inside a Kubernetes pod. The
container joins the pod's network namespace — the one the engine does not
exclusively own — where it shares every listening socket with the sidecars
already there. Any port the service binds collides with whatever holds it,
and the failure surfaces as a raw bind: address already in use from the
service's own process, with nothing pointing at the actual conflict.

This is the sibling of #135, filed from its "Not in scope" section.

Cause

The native orchestrator resolves the namespace mode and hands it to the
backend verbatim (compose/orchestrator.go, resolveNamespaceMode — "" /
host / none / container:<id> pass through unchanged, by design, because
that is correct compose behaviour when the daemon's host is the user's
machine).

EngineOptions.DisableHostPortPublishing (#135) tells the engine that
assumption does not hold, and drops the host side of ports: on that basis.
It does not touch network_mode: host, because the two cases do not have the
same answer:

  • Dropping a ports: publish is semantically safe — service-to-service
    traffic goes over the compose network by service name, so nothing the
    project relies on changes.
  • Silently moving a network_mode: host service onto the project's bridge
    network is not safe. The service asked to be on the host's namespace;
    putting it somewhere else changes what it can reach and who can reach it,
    in ways the compose file cannot express and the user did not ask for.

So the option currently covers one half of the collision and leaves the other
half to fail at boot.

Suggested fix

Refuse it. Under the same option, a service declaring
network_mode: host should be rejected at plan time with a typed error that
names the service and says why, rather than started into a namespace it will
fight over.

Plan-time is the right gate: compose.Plan.Validate already refuses the
compose features the orchestrator will not run (compose/plan.go,
compose.UnsupportedFeatureOnBackendError and neighbours), and refusing there
costs the user nothing — no image is pulled, no sidecar is built, nothing is
created.

That needs the option to reach Plan.Validate, which today only sees
runtime.Capabilities. The shape is open: a field on Plan, or an
Orchestrator field, or folding it into the capability set. Worth deciding
against the case where more environment-derived refusals follow, rather than
in isolation.

Not in scope

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions