diff --git a/modules/docker/README.md b/modules/docker/README.md index 1838114..411ec2c 100644 --- a/modules/docker/README.md +++ b/modules/docker/README.md @@ -14,6 +14,8 @@ tools below are the module's own. | `socket` | `docker.socket` running, enabled at boot | given back as found when the module goes (ADR 0118) | | `prune-service`, `prune-timer` | `/etc/systemd/system/docker-prune.{service,timer}`, written whole | removed with the module | | `prune` | `docker-prune.timer` running, enabled at boot; restarted when either file changes | stopped and disabled with the module (the mesh made the unit) | +| `daemon` | `live-restore` written into `/etc/docker/daemon.json`, beside other keys | the key given back as found when the module goes | +| `runtime` | `docker.service` running, enabled at boot; reloaded, never restarted, when `daemon` changes | given back as found (ADR 0118) | The weekly prune takes **dangling images and build cache unused for a week, and nothing else**. It takes no volume, no container and no image a container uses, so it never touches a container the mesh @@ -24,62 +26,47 @@ while the machine was off happens at the next boot. `container-runtime`: under ADR 0165, which is still proposed, that word means a running daemon, and the module that installs the daemon cannot require it. +## The runtime's own file and service (issue 190, hq ADR 0196) + +This module writes one key into `/etc/docker/daemon.json` (`into: json`, ADR 0102): `live-restore`. +`dnsmasq` used to write it, beside `dns`; it no longer writes either. Under ADR 0196 a container +copies its machine's resolvers, so no module writes `dns`. + +- `daemon`: `{"live-restore": true}`, merged into the file beside the keys others write. +- `runtime`: `docker.service` running, enabled at boot, and **reloaded, never restarted**, when + `daemon` changes. A restart stops every container. A reload turns `live-restore` on, and with it on + a later restart keeps every container running. + +In the apply that moves the key, the host first gives back `dnsmasq`'s resources, then applies this +module's: `live-restore` is set again in the same apply, and the daemon is reloaded once. + +`dns` is removed from the file then, but the daemon reads it only at its next start, and a running +container keeps the resolvers it was created with. Each container pinned to a machine's own resolver +is restarted before that machine's `dnsmasq` goes (ADR 0194, step 4). + +Still elsewhere: + +- **The private network**, generated by the controller (`internal/overlay/generator.go`), writes + `insecure-registries`. The collision check does not see generated resources. **Later:** the + controller hands the registry to this module as a value, and the overlay stops generating its two + resources (issue 190, steps 2 and 5). The host merges disjoint keys correctly; the mesh-host + `into.go` record is per resource. +- **Nobody** writes log rotation. One machine has `log-driver` and `log-opts` by hand; they are left + as they are until a size is chosen for every machine. + ## What it does not declare yet, and why -Three things this module should own are already declared by other modules on every machine. The -controller refuses two modules on one node that declare the same `path`, `unit`, `name` or `package` -(`checkResources`, mesh-controller `internal/catalogue/resolve.go`). Declaring any of them here would -make the module unassignable everywhere. The refusals were checked against the controller's own +One thing this module should own is still declared elsewhere. The controller refuses two modules +on one node that declare the same `path`, `unit`, `name` or `package` (`checkResources`, +mesh-controller `internal/catalogue/resolve.go`), so declaring it here would make the module +unassignable everywhere. The refusals were checked against the controller's own check: ``` zsh and docker both declare the name "${machine:account}" -dnsmasq and docker both declare the path "/etc/docker/daemon.json" -dnsmasq and docker both declare the unit "docker.service" ``` -### 1. `/etc/docker/daemon.json` and `docker.service` (issue 190) - -Today the file has three writers. Each writes into it (`into: json`, ADR 0102) and reloads the -service: - -- **`dnsmasq`** writes `dns` and `live-restore`, through `dnsmasq.runtime-dns` and `dnsmasq.runtime`. -- **The private network**, generated by the controller (`internal/overlay/generator.go`), writes - `insecure-registries`. The collision check does not see generated resources. -- **Nobody** writes log rotation. One machine has `log-driver` and `log-opts` by hand. - -**The change proposed, in one merge:** - -1. `dnsmasq` drops its `runtime-dns` and `runtime` resources. -2. `docker` adds the two resources below: - - ```json - {"id": "daemon", "type": "file", "path": "/etc/docker/daemon.json", "mode": "0644", "into": "json", - "content": "{\"dns\": [\"${machine:address}\"], \"live-restore\": true, \"log-driver\": \"json-file\", \"log-opts\": {\"max-size\": \"100m\", \"max-file\": \"5\"}}\n"}, - {"id": "runtime", "type": "service", "unit": "docker.service", "state": "running", "boot": "enabled", "reload-on": ["daemon"]} - ``` - - The service is **reloaded, never restarted**: a restart stops every container. The daemon reads - `live-restore` on a reload. It reads `dns`, `log-driver` and `log-opts` only at its next start, so - they apply then (to containers created afterwards, for the log keys). With `live-restore` on, that - start keeps every container running. - -**Why one merge, and only after this module is on every machine:** - -- In one apply, the host first gives back the resources that are no longer declared, then applies - the new ones (mesh-host `apply.go`). -- `dnsmasq` gives back `dns` and `live-restore` to what they held before it, and `docker` sets them - again in the same apply. The daemon is reloaded once, after both steps. -- A machine pushed the new `dnsmasq` *without* this module would keep its pre-mesh values for both - keys. On one machine that is `live-restore: false`, and the next daemon restart there would stop - every container. - -**Later:** the controller hands the registry to this module as a value, and the overlay stops -generating its two resources (issue 190, steps 2 and 5). Until then the overlay keeps writing its one -key beside this module's. The host merges disjoint keys correctly; the mesh-host `into.go` record is -per resource. - -### 2. The operator account's membership of the `docker` group +### The operator account's membership of the `docker` group The right shape is the host's `user` shape. Its `groups` are additive: the host runs `usermod --append` and never takes a group away. @@ -111,9 +98,8 @@ On the machine the mesh was first installed on, the foundation bundle declared ` never sees them (mesh-host `store.go`). - So `docker.package` here is a **second record of the same package**. The apply says "already installed", and neither record ever uninstalls it. -- This module does not declare `docker.service` today, so nothing overlaps there. The proposed step - 1 would add a second record of that unit. Its found state is *running*, because genesis started - it, so undeclaring this module would leave the daemon running. +- `docker.runtime` is likewise a second record of `docker.service`. Its found state is *running*, + because genesis started it, so undeclaring this module leaves the daemon running. ## Tools diff --git a/modules/docker/module.json b/modules/docker/module.json index 56d12a2..cdf7056 100644 --- a/modules/docker/module.json +++ b/modules/docker/module.json @@ -50,6 +50,24 @@ "state": "running", "boot": "enabled" }, + { + "id": "daemon", + "type": "file", + "path": "/etc/docker/daemon.json", + "mode": "0644", + "into": "json", + "content": "{\"live-restore\": true}\n" + }, + { + "id": "runtime", + "type": "service", + "unit": "docker.service", + "state": "running", + "boot": "enabled", + "reload-on": [ + "daemon" + ] + }, { "id": "prune-service", "type": "file", diff --git a/modules/resolv-conf/module.json b/modules/resolv-conf/module.json index d47a5df..7fb0acb 100644 --- a/modules/resolv-conf/module.json +++ b/modules/resolv-conf/module.json @@ -18,23 +18,6 @@ "path": "/etc/resolv.conf", "mode": "0644", "content": "# Managed by the mesh.\n#\n# For a machine where nothing else owns this file. On one where systemd-resolved\n# or NetworkManager does, assign that module instead — this one and those claim\n# the same thing, so the mesh refuses the pair rather than letting them take\n# turns overwriting each other, which is the failure this claim exists to stop.\n#\n# The mesh's one resolver first (novox/hq ADR 0194, 0196), by address — a machine\n# cannot resolve the name of the thing it resolves names with. It answers the\n# mesh's names itself and forwards every other name. A public resolver second,\n# asked only when the first does not answer at all — its machine or the tunnel\n# down, a captive portal holding the tunnel back — so public names keep\n# resolving then. An answer from the first, \"no such name\" included, is final,\n# so a mesh name is never asked of the public one while the mesh's answers. One\n# second and one attempt, so the wait before the fallback is short. Containers\n# copy these two lines from their machine.\nnameserver ${bound:wildcard-resolution:address}\nnameserver 1.1.1.1\noptions timeout:1 attempts:1 edns0\n" - }, - { - "id": "runtime-config", - "type": "file", - "path": "/etc/docker/daemon.json", - "mode": "0644", - "into": "json", - "content": "{\"live-restore\": true}\n" - }, - { - "id": "runtime", - "type": "service", - "unit": "docker.service", - "state": "running", - "reload-on": [ - "runtime-config" - ] } ] }