|
3 | 3 | # docker build -t vfb-static-builder . |
4 | 4 | # docker run --rm -v "$PWD:/src" -v vfb_cache:/tmp vfb-static-builder |
5 | 5 | # |
6 | | -# v0.164.0 is the newest stable Hugo (released 2026-07-06) and the site builds |
7 | | -# clean on it: 186 pages, no WARN, no ERROR. Pinned rather than :latest so |
8 | | -# rebuilding this image cannot silently change the site. |
9 | | -# |
10 | | -# The theme's declared minimum is 0.128.0 (`[pagination] pagerSize`). It does |
11 | | -# also build on 0.122.0, which is what rcourt/docsy-builder:Feb2023 carries, but |
12 | | -# that image has no rsync and warns about the declared minimum. |
13 | | -# |
14 | | -# Base is Alpine 3.22, so apk is correct. The upstream image already carries |
15 | | -# git, Node, npm and Dart Sass. This site needs none of them — the theme ships |
16 | | -# plain CSS concatenated by Hugo, so even the extended edition is optional — but |
17 | | -# they come with the official image and are not worth stripping out. |
18 | | -# |
19 | | -# bash and rsync are for deploy.sh, which stages the build and syncs it into the |
20 | | -# served directory rather than writing there directly. findutils replaces |
21 | | -# busybox find so the page-count gate behaves predictably. |
22 | | -FROM ghcr.io/gohugoio/hugo:v0.164.0 |
| 6 | +# Pinned to Hugo 0.122.0 rather than the newest release. That is a deliberate |
| 7 | +# step backwards and the reason is measured, not suspected. |
| 8 | +# |
| 9 | +# The content tree is ~763k generated term pages, ~650k of them in a single |
| 10 | +# directory (content/en/blog/ontologies/vfb), reached over NFSv3 from a Synology |
| 11 | +# volume whose btrfs metadata sits on RAID5 spinning disks. Measured on that |
| 12 | +# volume: plain readdir runs at 5-29k entries/s, but readdir+stat runs at |
| 13 | +# 253/s — ~4ms per inode, a disk seek, nothing cached. NFSv3 uses READDIRPLUS, |
| 14 | +# so the server stats every entry it enumerates. Per-page filesystem cost is |
| 15 | +# therefore the dominant term in this build, far above template or render cost. |
| 16 | +# |
| 17 | +# Hugo's per-page filesystem cost rose at v0.123.0, which rewrote page assembly. |
| 18 | +# Counted with strace over an identical 25k-page corpus on local disk: |
| 19 | +# |
| 20 | +# 0.122.0 75,658 openat 76,997 newfstatat 3.06 stat/page |
| 21 | +# 0.128.0 100,788 openat 101,527 newfstatat 4.04 stat/page |
| 22 | +# 0.140.2 100,813 openat 101,485 newfstatat 4.03 stat/page |
| 23 | +# 0.164.0 100,844 openat 101,488 newfstatat 4.03 stat/page |
| 24 | +# |
| 25 | +# Flat from 0.128 onward, so this is one regression at 0.123, not a drift. At |
| 26 | +# 763k pages and 253 stat/s that extra stat per page is ~49 min on top of a |
| 27 | +# build already costing ~2.6h of pure metadata I/O. |
| 28 | +# |
| 29 | +# 0.122.0 is the last version known to complete this build: the live term pages |
| 30 | +# carry `generator: Hugo 0.122.0` and were written 2026-08-05 17:59. No 0.16x |
| 31 | +# build has ever finished — each ran 17h+ with one thread in uninterruptible |
| 32 | +# sleep on the vfb/ directory and not a single page written. |
| 33 | +# |
| 34 | +# This pin is a workaround. The fix is to stop holding 650k files in one |
| 35 | +# directory (shard vfbterms.py's output) and to pin the volume's btrfs metadata |
| 36 | +# to its SSD cache. When either lands, raise HUGO_VERSION — it is an ARG so that |
| 37 | +# is a one-line change. |
| 38 | +# |
| 39 | +# Debian rather than Alpine, and the tarball rather than ghcr.io/gohugoio/hugo: |
| 40 | +# that registry has no v0.122.0 tag (it begins around v0.140), and the extended |
| 41 | +# release binary is glibc-linked — `ldd` gives /lib64/ld-linux-x86-64.so.2 plus |
| 42 | +# libstdc++.so.6 — so musl with gcompat is not a safe host for it. |
| 43 | +# |
| 44 | +# Extended edition, matching the rcourt/docsy-builder:Feb2023 that produced the |
| 45 | +# last good site. The theme ships plain CSS and needs no Sass, so the standard |
| 46 | +# edition would also serve and is statically linked; keeping extended here |
| 47 | +# changes one variable at a time relative to the last build known to work. |
| 48 | +# |
| 49 | +# The theme declares min_version 0.128.0 for `[pagination] pagerSize`, so 0.122 |
| 50 | +# emits one WARN and falls back to 10 items per page. Nothing on the site |
| 51 | +# paginates today, so that is latent rather than active. |
| 52 | +FROM debian:bookworm-slim |
| 53 | + |
| 54 | +ARG HUGO_VERSION=0.122.0 |
| 55 | + |
| 56 | +# bash and find are already in the base image. rsync is for deploy.sh, which |
| 57 | +# stages the build and syncs it into the served directory rather than writing |
| 58 | +# there directly. libstdc++6 is what the extended Hugo binary links against. |
| 59 | +RUN apt-get update \ |
| 60 | + && apt-get install -y --no-install-recommends rsync ca-certificates libstdc++6 \ |
| 61 | + && rm -rf /var/lib/apt/lists/* |
| 62 | + |
| 63 | +ADD https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz /tmp/hugo.tgz |
| 64 | +RUN tar xzf /tmp/hugo.tgz -C /usr/local/bin hugo \ |
| 65 | + && rm -f /tmp/hugo.tgz \ |
| 66 | + && hugo version |
23 | 67 |
|
24 | | -# Deliberately root, unlike the upstream image's hugo:hugo. The published tree |
25 | | -# on the NFS volume is owned by root from the klakegg-era builds, so an |
26 | | -# unprivileged rsync could not overwrite it. |
| 68 | +# Deliberately root. The published tree on the NFS volume is owned by root from |
| 69 | +# the klakegg-era builds, so an unprivileged rsync could not overwrite it. |
27 | 70 | USER root |
28 | | -RUN apk add --no-cache bash rsync findutils |
29 | 71 |
|
30 | | -# The upstream image sets HUGO_CACHEDIR=/cache and WORKDIR /project. Both are |
31 | | -# wrong here and neither can be left to deploy.sh's defaults: the script uses |
32 | | -# ${HUGO_CACHEDIR:-/tmp/hugo_cache}, which never fires while the image has the |
33 | | -# variable set, so the cache would land in the container's writable layer |
34 | | -# instead of the volume mounted at /tmp — discarded every run, and growing host |
35 | | -# disk in between. Rancher mounts the workspace at /src and the cache at /tmp. |
| 72 | +# deploy.sh uses ${HUGO_CACHEDIR:-/tmp/hugo_cache}, so this must be set |
| 73 | +# explicitly: Rancher mounts the workspace at /src and the cache volume at /tmp. |
36 | 74 | ENV HUGO_CACHEDIR=/tmp/hugo_cache |
37 | 75 | WORKDIR /src |
38 | 76 |
|
|
0 commit comments