The Network Is a Deliberate Bridge

In apple/container, a container’s network is not an invisible extension of the Mac’s network. This chapter explains how a VM-backed workload gets an address, how peers and the host find it, and how traffic can move back from a guest to a service on the Mac. The practical result is a choice among three different paths—guest to guest, host to guest, and guest to host—each with its own setup, trust boundary, and macOS-version limits.

The distinction matters because “the container is running” says nothing about how it is reachable. A Python web server may be healthy inside its Linux guest while no host port is published. A second container may have network access but no usable name if DNS was not configured. A guest may need to call a development service listening only on the Mac, which requires an explicit reverse path. apple/container makes these channels visible instead of treating them as one shared network.

Start with an address, then add names

Starting the container system creates a vmnet-backed network named default. Unless a different network is selected, containers attach to it and receive an IP address. The address is reachable from the Mac and from other containers on the same network. It is the base primitive of the system: a user can inspect a container to find its current address and connect directly without asking a name service to translate anything.

That direct address is useful for understanding what the network is doing. The web-server example can listen on a wildcard address inside the guest, while the host connects to the guest IP. The IP belongs to the current network attachment, not to the image. It can change after the container stops and starts, because the live VM and its interface are rebuilt. A name or published port is a convenience layered on top of that attachment; neither replaces the underlying guest address.

Names come from the embedded DNS service. To give containers a local domain such as test, the user first configures that domain for the container service and restarts the service. The container runtime then registers names such as my-web-server.test and configures guest resolvers to use the service. The Mac itself still has its normal resolver configuration, so a second step creates a macOS resolver entry that sends queries for the chosen domain to the local DNS service.

Both steps are necessary because they configure different sides of the boundary. A name can resolve inside one container while remaining unknown to the Mac, or the Mac can be pointed at the local resolver while the container service has not been configured to register names. A successful end-to-end test should therefore be made from the same place where the client will run: use a host request for host-to-guest access and a guest command for guest-to-guest access.

Name resolution is not the same as connectivity. If the name resolves but the service is not listening, DNS is not the cause. If the IP works but the name does not, the problem is in the resolver or registration path. If a container is attached to a different network, the name may be outside the relevant network scope. Keeping address allocation, name translation, and application listening as separate steps makes troubleshooting much faster.

The allocation sequence explains why these distinctions persist. The API server coordinates the network resource, but the per-container runtime asks for a concrete attachment when the guest is being bootstrapped.