Skip to content

Networking

Sockets for guests, built-in DNS, networks with aliases and several networks per container, published ports, and a class network through the relay. Live in the playground since v0.3.0.

Containers have a network (engine v0.10.0, extended in v0.14.0). Networking is live in the playground since playground v0.3.0 (engine v0.10.0 there), and joining a teacher’s class from the page works.

$ wctr network create lab
$ wctr run -d --name web --network lab netprobe serve 80
$ wctr run --rm --network lab netprobe get http://web/class

The second container reaches web by its name, through the network’s DNS.

Sockets for guests

A guest opens sockets with the WasmEdge socket extension of wasi_snapshot_preview1 (its V2 form, as stealthrocket/wasi-go serves it) and preview 1’s sock_* calls. A stock Go program that uses github.com/stealthrocket/net v0.2.1 runs unchanged: HTTP and UDP between containers, by container name.

DNS by container name

Every network has a DNS server inside the engine, on UDP port 53, answering on 127.0.0.11, 127.0.0.1 and ::1. It answers A and AAAA for the names on the network and NXDOMAIN for anything else; nothing is forwarded outside. Guests built with -tags getaddrinfo resolve through sock_getaddrinfo instead.

Networks

  • The default network is bridge (10.88.0.0/16); the other is none, which gives no sockets.
  • wctr network create|ls|inspect|rm|connect|disconnect|prune, and wctr run --network NAME; the container’s address is shown by inspect. The API has /networks.
  • Since v0.14.0: wctr run --network-alias NAME gives a container more names on a user-defined network (replicas may share one); wctr network connect [--alias NAME] NETWORK CONTAINER attaches a running container at once, so a container can be on several networks; disconnect [-f] detaches it; and prune [-f] [--filter label=K[=V]] removes unused networks. Lists can be filtered by label, and wctr events has network events (create, connect, disconnect, destroy, prune).

A class network

wctrd --relay URL --relay-join-code-file FILE [--relay-ca CA] [--relay-network class] joins a class of the relay and adds a network on which containers get the class’s addresses and names, under the teacher’s firewall. The join code is read from a file, which is refused if other users can read it; the session token is kept with mode 0600 and refreshed. Since engine v0.11.0 a host can also add and remove such a network at run time, which is what the playground’s “Join class” does.

The WASI host

wctrd --wasi engine is the default, because sockets need it. wctrd --wasi wazero gives no network.

Published ports (engine v0.22.0, native)

$ wctr run -d --name web -p 8080:80 netprobe serve 80
$ wctr port web
80/tcp -> 127.0.0.1:8080

A container has no socket on the host, so a published port is a listener that wctrd opens on the host and proxies into the container (the way Docker’s userland proxy does, not iptables). UDP keeps one session per client, ended after 90 seconds of silence. The API shapes are Docker’s (HostConfig.PortBindings, PublishAllPorts, Config.ExposedPorts, NetworkSettings.Ports).

  • A binding without an address listens on 127.0.0.1, not on every address as Docker does. -p 8080:80 makes the container reachable from this machine only; -p 0.0.0.0:8080:80 makes it reachable from the network.
  • A host port someone holds refuses the start (Bind for 127.0.0.1:8080 failed: port is already allocated), and nothing of that container is left listening. A container on --network none cannot publish.
  • Bounds: each binding proxies at most 128 connections and 256 UDP clients at a time, and at most 1024 bindings per container; the parsers are fuzzed.
  • No SCTP, and the source address the guest sees is its own, not the client’s.

In the browser, -p is not available yet: it is in progress, through a second origin (the host would be the page, not a machine). Engine v0.24.0 adds the groundwork, portmap.Virtual, published ports with no sockets, for an engine that runs in a page.

In the browser

In the playground, nothing leaves the page: there is no route to the Internet or to the machine. Measured by net bench (200 sequential GETs, then one 8 MiB GET, between two containers on the bridge) on an Apple M4 Max, under a load of 16 to 19, so indicative only:

latency p50 / p90throughput
Chromium (the page)1.1 / 1.4 ms106–112 MB/s
native: the same engine on wazero0.33 / 0.39 ms1.2 GB/s
native: Go net/http over loopback TCP (upper bound)0.05 / 0.07 ms3.8 GB/s

The browser is about 3 times slower in latency and 11 times in throughput than the same engine natively, because every socket read or write is a WASI call that crosses from the container’s worker to the engine’s. Larger reads per call are an open item.

Limitations

  • -p is not in the browser yet (in progress, through a second origin); natively it exists since engine v0.22.0 (see above).
  • A container on several networks binds to its primary address or to all of them (0.0.0.0), not to a secondary address alone.
  • Aliases work on in-engine networks only; no IPv6 on in-engine networks; no AF_UNIX.
  • The DNS shadows a container’s own UDP server on port 53 at those resolver addresses, and an unconnected UDP sendto to the resolver is not answered.

Created on by tannevaled

Modified on by tannevaled