Settle the open points of the Ubuntu and nixpkgs image #42

Merged
clawbot merged 1 commits from issue-38-image-open-points into next 2026-10-04 02:42:58 +02:00
2 changed files with 79 additions and 27 deletions
+9 -4
View File
@@ -291,10 +291,15 @@ stand for the app's own options:
```bash ```bash
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
sleep 1
exec chpst -u app:app /usr/local/bin/app \ main() {
--listen 127.0.0.1:8081 \ sleep 1
--trusted-proxies 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32,::1/128 exec chpst -u app:app /usr/local/bin/app \
--listen 127.0.0.1:8081 \
--trusted-proxies 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32,::1/128
}
main "$@"
``` ```
- The image's entrypoint, `runsvinit`, has runit start `smallwebwaf` and the app - The image's entrypoint, `runsvinit`, has runit start `smallwebwaf` and the app
+70 -23
View File
@@ -1155,16 +1155,29 @@ The image holds:
- Ubuntu 26.04 LTS, the newest long-term support release of Ubuntu, pinned by - Ubuntu 26.04 LTS, the newest long-term support release of Ubuntu, pinned by
digest. The image moves to the next LTS release when that ships. digest. The image moves to the next LTS release when that ships.
- Three packages from Ubuntu, `ca-certificates`, `nix-bin` and `runit`,
installed from a dated snapshot of Ubuntu's archive and checked by hash (see
"Packages from Ubuntu" below). The Ubuntu image has no CA certificates, and
they come with `nix-bin` only because a library it uses recommends them, so
`ca-certificates` is installed by name. Without it Nix cannot download
packages, and `smallwebwaf`, unable to reach GeoJS, would count every visitor
as coming from an unknown country.
- Nix, the package manager, from Ubuntu's own `nix-bin` package, and nixpkgs, - Nix, the package manager, from Ubuntu's own `nix-bin` package, and nixpkgs,
the collection of packages Nix installs from, fixed at one commit (see the collection of packages Nix installs from, fixed at one commit (see
"Packages from nixpkgs" below). Root uses Nix directly, and no Nix daemon runs "Packages from nixpkgs" below). Root uses Nix directly, and no Nix daemon runs
in the container. in the container. Nix run by root expects a group of build users, `nixbld`,
- runit, from Ubuntu's own `runit` package, and `runsvinit` as the entrypoint. which `nix-bin` does not create, so the image writes `build-users-group =` to
Neither Ubuntu nor nixpkgs packages `runsvinit`, so the image builds it from `/etc/nix/nix.conf`, and root's builds then run without build users.
its source (`github.com/peterbourgon/runsvinit`) at a version fixed by hash. - runit, from Ubuntu's own `runit` package, and `runsvinit` as the entrypoint,
`runsvinit` starts runit's `runsvdir`, which starts a `runsv` for each as the owner's code style guide asks for service containers. Neither Ubuntu
directory under `/etc/service`; each `runsv` runs the `run` script in its nor nixpkgs packages `runsvinit`, so the image builds it from its source
directory, and runs it again whenever it exits. Ubuntu's runit looks for (`github.com/peterbourgon/runsvinit`) at a fixed commit hash. Its repository
is archived and has not changed since 2015, and its last tag is `v2.0.0`. It
has no `go.mod`, and `go build` of its directory needs one, so the build
writes one; since `runsvinit` uses only Go's standard library, that file names
nothing else. `runsvinit` starts runit's `runsvdir`, which starts a `runsv`
for each directory under `/etc/service`; each `runsv` runs the `run` script in
its directory, and runs it again whenever it exits. Ubuntu's runit looks for
services in `/etc/service` too, so when `docker stop` has `runsvinit` stop services in `/etc/service` too, so when `docker stop` has `runsvinit` stop
each service with runit's `sv`, `sv` finds it. each service with runit's `sv`, `sv` finds it.
- The `smallwebwaf` binary, and a user of its own, `smallwebwaf` (uid and gid - The `smallwebwaf` binary, and a user of its own, `smallwebwaf` (uid and gid
@@ -1179,8 +1192,9 @@ The image holds:
(`HEALTHCHECK`). (`HEALTHCHECK`).
Every `run` script, the app's included, is a bash script that starts with Every `run` script, the app's included, is a bash script that starts with
`#!/usr/bin/env bash` and `set -euo pipefail`, as the owner's code style guide `#!/usr/bin/env bash` and `set -euo pipefail` and puts its code in a `main`
asks; Ubuntu ships bash. function, called on its last line, as the owner's code style guide asks; Ubuntu
ships bash.
Beyond its `FROM` line, the app's Dockerfile adds: Beyond its `FROM` line, the app's Dockerfile adds:
@@ -1219,23 +1233,56 @@ with `app.run` beside the Dockerfile:
```bash ```bash
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
sleep 1
exec chpst -u app:app /usr/local/bin/app \ main() {
--listen 127.0.0.1:8081 \ sleep 1
--trusted-proxies 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32,::1/128 exec chpst -u app:app /usr/local/bin/app \
--listen 127.0.0.1:8081 \
--trusted-proxies 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.1/32,::1/128
}
main "$@"
``` ```
Packages from Ubuntu: the image installs `ca-certificates`, `nix-bin` and
`runit` from Ubuntu's snapshot service, which serves the archive as it was at a
given moment, rather than from the archive itself, whose packages change with
every update. The image's Dockerfile names that moment, in apt's
`--snapshot 20261001T000000Z` form, on both `apt-get update` and
`apt-get install`. That moment is never earlier than the date of the pinned
Ubuntu image, since packages from an older snapshot can need older versions of
packages the Ubuntu image already holds, and it moves forward whenever that
image's digest does. `apt-get update` keeps the snapshot's `InRelease` files,
which apt checks against the archive's signature, in `/var/lib/apt/lists/`; each
lists the SHA-256 hash of the package lists it covers, and each package list the
hash of every package in it. The Dockerfile also names the SHA-256 hash of each
`InRelease` file apt uses, and the build checks them after `apt-get update` and
before `apt-get install`, so every package apt installs is checked, through
those files, against hashes the Dockerfile names. The snapshot service is
reached over HTTPS, and the Ubuntu image has no CA certificates of its own, so
this one install uses those of the Go image that `smallwebwaf` is built in,
which is pinned by digest too: apt's `Acquire::https::CaInfo` option names that
image's CA certificate file, `/etc/ssl/certs/ca-certificates.crt`, copied into
the build.
Packages from nixpkgs: nixpkgs is fixed at one commit of its newest release Packages from nixpkgs: nixpkgs is fixed at one commit of its newest release
branch, `nixos-26.05` today. The image's Dockerfile names the commit and the branch, `nixos-26.05` today. For each commit of the branch that has passed its
hash of its contents, and the build checks that hash. nixpkgs is set up for root tests, the Nix project publishes a release on `releases.nixos.org`, such as
under the name `nixpkgs`, so the app's Dockerfile installs a package with `nixos-26.05.11045.774debe7a0d1`, and the image takes nixpkgs from that
`nix-env -iA nixpkgs.<name>`, and whatever it installs is on the `PATH` of every release's file `nixexprs.tar.xz`, not from a GitHub archive of the commit, whose
service. Because nixpkgs stays at that commit, an app built on the same bytes can change. The image's Dockerfile names the release and the SHA-256 hash
`smallwebwaf` image gets the same packages each time it is built. A newer commit of that file, which the release's page lists, and the build checks the hash
of the branch, with its security fixes, comes with a newer `smallwebwaf` image, before unpacking it. nixpkgs is set up for root under the name `nixpkgs`, so the
as do Ubuntu's own fixes; an app takes them by changing the digest in its `FROM` app's Dockerfile installs a package with `nix-env -iA nixpkgs.<name>`, and
line. When nixpkgs makes its next release, every six months, the image moves to whatever it installs is on the `PATH` of every service. Because nixpkgs stays at
that release's branch. that commit, an app built on the same `smallwebwaf` image gets the same packages
each time it is built. Unpacked, nixpkgs takes about 500 MiB of disk, more on
some filesystems such as ZFS, and each package an app installs from it adds its
own size, with everything it depends on. A newer commit of the branch, with its
security fixes, comes with a newer `smallwebwaf` image, as do Ubuntu's own
fixes; an app takes them by changing the digest in its `FROM` line. When nixpkgs
makes its next release, every six months, the image moves to that release's
branch.
The two processes: The two processes: