diff --git a/content/en/docs/images.md b/content/en/docs/images.md index 79ef1c8..f171897 100644 --- a/content/en/docs/images.md +++ b/content/en/docs/images.md @@ -123,10 +123,11 @@ sudo nspawn pull REFERENCE [--name NAME] [--backend BACKEND] [--mode MODE] [--fo It resolves the reference to the manifest for the host's platform (image indexes are followed), downloads every layer and the config -blob that is not already in the store, checking each one against its sha256 -digest while it streams (a blob is written next to its final name and renamed -only once verified, so an interrupted download never passes for a complete -one), and then: +blob that is not already in the store, three at a time as docker does, checking +each one against its sha256 digest while it streams (a blob is written next to +its final name and renamed only once verified, so an interrupted download never +passes for a complete one, and a download cut short takes its part file with +it), says of each blob when it is downloaded, and then: 1. assembles the root file system with the chosen [backend](#backends); 2. reads the OCI config and decides whether the image is a diff --git a/content/en/docs/machines.md b/content/en/docs/machines.md index 18e3b1e..2ddd766 100644 --- a/content/en/docs/machines.md +++ b/content/en/docs/machines.md @@ -185,9 +185,9 @@ What an app runs is decided exactly as with docker: forgets them all, and `exec` sees the same environment as the program. Names follow the usual rules (letters, digits and `_`, not starting with a digit). - The working directory, the user and the stop signal come from the image - unless `-w`, `-u` and `--stop-signal` say otherwise. Of docker's `uid:gid` - form of the image's user, the uid part is used; the gid comes from the - image's `passwd`, and `-u uid:gid` is refused. The user is resolved as + unless `-w`, `-u` and `--stop-signal` say otherwise. docker's `USER:GROUP` + form is taken as docker takes it, from the image's config or from `-u`: the + group, a name or a number, is the program's primary and only group. The user is resolved as docker resolves it, from the image's `passwd` and `group` files: systemd-nspawn asks `getent` inside the machine, which busybox lacks and musl's (alpine) cannot answer, so nspawn binds a stand-in that answers those lookups and @@ -353,9 +353,11 @@ its unit: - `--hostname NAME`: the hostname inside, the machine's name by default. A booted machine gets it as its `/etc/hostname`, over the image's, since its systemd sets the hostname from that file. -- `-u USER` and `-w DIR`: the user (a name or a uid, listed in the image's - `passwd` or not; `uid:gid` is refused) and the working directory the - program runs with, instead of the image's. App images only. +- `-u USER[:GROUP]` and `-w DIR`: the user (a name or a uid, listed in the + image's `passwd` or not, with a group of the image's `group` file or a gid + after a colon, as docker's `--user` takes it; a group name the image lacks + is refused) and the working directory the program runs with, instead of the + image's. App images only. - `--cap-add`, `--cap-drop` and `--privileged`: capabilities on top of, or out of, systemd-nspawn's default set (`NET_ADMIN` or `CAP_NET_ADMIN`; `ALL`). `--cap-drop ALL --cap-add NET_BIND_SERVICE` keeps that one, as with @@ -438,7 +440,8 @@ registers, libvirt's among them, are left out); machines that nspawn did not install show `-` in the image columns. `-a` adds the nspawn machines that are not running. `COMMAND` is the effective entrypoint and arguments of an app, and `NETWORK` the machine's address on the default network, its other networks -as `NAME:ADDRESS`, and the published ports, or `host`, `veth` or `none`. A +as `NAME:ADDRESS`, and the published ports, or `host`, `veth`, `none` or +`container:NAME`. A machine between two runs of its restart policy is listed as `restarting` even without `-a`, a frozen one as `paused`, and a healthcheck follows the state: `running (healthy)`. diff --git a/content/en/docs/networking.md b/content/en/docs/networking.md index 93cb4e3..afdfad7 100644 --- a/content/en/docs/networking.md +++ b/content/en/docs/networking.md @@ -16,6 +16,7 @@ and the choice sticks for the next start. | a network's name | | The same on a bridge of its own, made with `network create`; several at once, with `--network` repeated: see [Networks of your own](#networks-of-your-own). | | `host` | | The host's network namespace, like `docker run --network host`: the machine sees the host's interfaces and binds to the host's ports. Works for both kinds of image. | | `none` | | No network at all, like `docker run --network none`: `lo` and nothing else. Works for both kinds of image. | +| `container:NAME` | | The network namespace of the running machine `NAME`, like `docker run --network container:NAME`: its interfaces, address, hosts file and resolv.conf, nothing of the machine's own. App images only; see [container:NAME](#containername). | | `veth` | Images not installed by nspawn | The classic systemd-nspawn setup: a virtual ethernet pair whose host end is configured by systemd-networkd through the stock `80-container-ve.network`. Booted images only. | ## The bridge @@ -239,3 +240,32 @@ namespace. `--network none` sets `Private=yes`: the machine has `lo` and nothing else, like `docker run --network none`. Published ports do not apply, and an app that runs this way keeps its user namespace too. + +## container:NAME + +`--network container:NAME` puts an app machine in the network namespace of the +machine `NAME`, docker's sidecar pattern (a VPN client with the programs that +must go through it, for one): the same interfaces and address, `NAME`'s hosts +and resolv.conf files, and nothing of the machine's own. A port the program +serves is published with `-p` on `NAME`, since that is where the address is. +`NAME` can be an app or a booted machine on any bridge network, has to be +running when the machine starts, and cannot be removed while a machine names +it. When `NAME` stops or restarts, the machine keeps the namespace it joined, +which then leads nowhere, and has to be restarted to join the new one, as with +docker. + +```shell +sudo nspawn run -d docker.io/qmcgaw/gluetun --name vpn --cap-add NET_ADMIN --device /dev/net/tun -p 8080:8080 +sudo nspawn run -d docker.io/library/nginx:1.27 --name web --network container:vpn +``` + +Behind the scenes the service binds the name systemd-nspawn looks for +(`/run/netns/nspawn-web`) to the network namespace of `vpn`'s leader process, +the mount `ip netns attach` would make, so the settings are the ones of any +app on a bridge, and drops the name when `web` stops while the namespace +stays `vpn`'s. `-p`, +`--network-alias`, `--dns`, `--dns-search`, `--add-host` and `--sysctl` are +refused on such a machine, since they shape a network of its own, and so is a +booted image, whose systemd would configure the shared interfaces again. `ps` +and `inspect` show the network as `container:NAME`; `network inspect` does not +list the machine among the network's members, as it has no address there. diff --git a/content/en/docs/reference.md b/content/en/docs/reference.md index 4b4284c..c66809f 100644 --- a/content/en/docs/reference.md +++ b/content/en/docs/reference.md @@ -257,7 +257,7 @@ nspawn start NAME [--network NETWORK]... [--network-alias [NETWORK=]NAME]... [-p [--restart POLICY] [-m SIZE] [--cpus N] [--pids-limit N] [--health-cmd COMMAND] [--health-interval D] [--health-timeout D] [--health-retries N] [--health-start-period D] [--health-start-interval D] [--no-healthcheck] - [--hostname NAME] [-u USER] [-w DIR] [--cap-add CAP]... [--cap-drop CAP]... [--privileged] + [--hostname NAME] [-u USER[:GROUP]] [-w DIR] [--cap-add CAP]... [--cap-drop CAP]... [--privileged] [--read-only] [--tmpfs PATH[:OPTIONS]]... [--shm-size SIZE] [--device HOST[:CONTAINER[:PERMISSIONS]]]... [--dns ADDRESS]... [--dns-search DOMAIN]... [--add-host HOST:IP]... [--ulimit NAME=SOFT[:HARD]]... [--oom-score-adj N] @@ -269,7 +269,7 @@ Boots an image as a machine. Every option is remembered for the next start. | Option | Meaning | | --- | --- | -| `--network NETWORK` | Network of the machine: `bridge`, the default network (the default); the name of a network made with [network create](#network-create); `veth`, a veth pair configured by systemd-networkd on the host (booted images only); `host`, the host's own network; or `none`, no interface but `lo`. Repeatable for several bridge networks, the first one primary: its address is where published ports lead and its gateway the default route, unless it is internal, in which case the first network that is not has the route. `veth` and `host` go alone. | +| `--network NETWORK` | Network of the machine: `bridge`, the default network (the default); the name of a network made with [network create](#network-create); `veth`, a veth pair configured by systemd-networkd on the host (booted images only); `host`, the host's own network; `none`, no interface but `lo`; or `container:NAME`, the network namespace of that running machine, like `docker run --network container:NAME` (app images only; see [container:NAME](/docs/networking/#containername)). Repeatable for several bridge networks, the first one primary: its address is where published ports lead and its gateway the default route, unless it is internal, in which case the first network that is not has the route. `veth`, `host`, `none` and `container:NAME` go alone. | | `--network-alias [NETWORK=]NAME` | Another name for the machine on its primary network, or on `NETWORK`, like `docker --network-alias`: every member of that network resolves it. Repeatable; `none` forgets them. | | `-p`, `--publish [IP:]HOST:CONTAINER[/udp]` | Publish a port on the host, like `docker -p`: on every address of the host, or on `IP` alone (`127.0.0.1:8080:80`). `8000-8010:8000-8010` publishes a range, one mapping per port. Repeatable; `none` forgets them all. | | `--entrypoint PROGRAM` | Replace the image's entrypoint; an empty string runs the arguments alone. App images only. | @@ -288,7 +288,7 @@ Boots an image as a machine. Every option is remembered for the next start. | `--health-start-interval D` | Time between probes during the start period. Default: `5s`. | | `--no-healthcheck` | No probes, whatever the image says. | | `--hostname NAME` | Hostname inside the machine. Default: its name. A booted machine gets it as its `/etc/hostname`. | -| `-u`, `--user USER` | User the program runs as, a name or a uid (listed in the image's `passwd` or not), instead of the image's; `uid:gid` is refused. nspawn resolves it from the image's `passwd` and `group` files through a stand-in for getent, as docker does. App images only. | +| `-u`, `--user USER[:GROUP]` | User the program runs as, a name or a uid (listed in the image's `passwd` or not), instead of the image's, with a group after a colon as docker takes it: a name of the image's `group` file or a number, which becomes the primary and only group of the program; a name the image lacks is refused. nspawn resolves both from the image's `passwd` and `group` files through a stand-in for getent, as docker does. App images only. | | `-w`, `--workdir DIR` | Working directory of the program, instead of the image's. App images only. | | `--cap-add CAP` | Capability to keep on top of systemd-nspawn's default set: `NET_ADMIN`, `CAP_NET_ADMIN`, `ALL`. Repeatable; `none` forgets them. | | `--cap-drop CAP` | Capability to drop from the default set. `--cap-drop ALL --cap-add X` keeps `X`, as with docker. Repeatable; `none` forgets them. | diff --git a/hugo.yaml b/hugo.yaml index 63a5391..053957e 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -53,7 +53,7 @@ params: privacy_policy: /about/#privacy # Version of nspawn the documentation describes. - version: 1.3.1 + version: 1.4.0 archived_version: false # In-page links to open issues and suggest changes.