1
0
mirror of https://github.com/docker/docs.git synced 2026-10-23 18:09:02 +03:00
Files
docs/Dockerfile
David Karlsson 2b12ac0ef8 build: vendor API reference data to speed up site builds (#26182)
API generation introduced in #26048 added roughly five minutes to site
builds: median successful main-branch build-workflow duration rose from
4m 05s to 8m 48s across September 3–25. The pre-build command took 4m
41s–4m 53s in each of four jobs on the merge commit.

Vendor the generated presentation model in `data/api-reference.json`,
mark it as generated, and let Docker, Netlify, and local Hugo builds
consume it directly. Keep the existing rendered-output checks.

Move generator tests, strict spec validation, and a byte-for-byte
regeneration check into `docker buildx bake validate-api-reference`,
inheriting the shared Docker base stage. The target uses the pinned
Vacuum release binary with Dockerfile ADD checksum verification and
archive extraction instead of compiling Vacuum from source. The existing
build workflow runs this target alongside the other validation matrix
entries. Only this matrix entry is advisory; its failures do not block
site builds or deployment.

Validated locally with the Docker target, rejection of deliberately
stale data, repeatable generation across directories, a production Hugo
build and verification of 453 API HTML/Markdown page pairs, workflow
syntax checks, and scoped documentation lint. The prebuilt-binary CI
check passed in 1m 40s, down from 5m 15s with source compilation. Remote
layer-cache settings were subsequently removed; local Go cache mounts
remain.

Generated by Codex
2026-09-25 18:45:09 +02:00

210 lines
6.5 KiB
Docker

# syntax=docker/dockerfile:1
# check=skip=InvalidBaseImagePlatform
ARG ALPINE_VERSION=3.23
ARG GO_VERSION=1.26
ARG HTMLTEST_VERSION=0.17.0
ARG VALE_VERSION=3.17.0
ARG HUGO_VERSION=0.163.0
ARG NODE_VERSION=24
ARG PAGEFIND_VERSION=1.5.2
ARG TARGETARCH
# base defines the generic base stage
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base
RUN apk add --no-cache \
git \
nodejs \
npm \
gcompat \
rsync
# npm downloads Node.js dependencies
FROM base AS npm
ENV NODE_ENV="production"
WORKDIR /out
RUN --mount=source=package.json,target=package.json \
--mount=source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci
# hugo downloads the Hugo binary
FROM base AS hugo
ARG TARGETARCH
ARG HUGO_VERSION
WORKDIR /out
ADD https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-${TARGETARCH}.tar.gz .
RUN tar xvf hugo_extended_${HUGO_VERSION}_linux-${TARGETARCH}.tar.gz
# build-base is the base stage used for building the site
FROM base AS build-base
WORKDIR /project
COPY --from=hugo /out/hugo /bin/hugo
COPY --from=npm /out/node_modules node_modules
COPY . .
# build creates production builds with Hugo
FROM build-base AS build
# HUGO_ENV sets the hugo.Environment (production, development, preview)
ARG HUGO_ENV="development"
# DOCS_URL sets the base URL for the site
ARG DOCS_URL="https://docs.docker.com"
ENV HUGO_CACHEDIR="/tmp/hugo_cache"
RUN --mount=type=cache,target=/tmp/hugo_cache \
hugo \
--gc \
--minify \
--panicOnWarning \
--printPathWarnings \
--printUnusedTemplates \
-b $DOCS_URL \
-e $HUGO_ENV
RUN node --test hack/test/flatten-and-resolve.mjs
RUN node hack/flatten-and-resolve.js public
RUN node hack/api-docs/verify-output.mjs public
# lint lints markdown files
FROM ghcr.io/rvben/rumdl:0.2.49-alpine AS lint
RUN --mount=type=bind,target=. rumdl check content
# vacuum downloads the prebuilt validator for the target architecture
FROM scratch AS vacuum-amd64
ADD --unpack --checksum=sha256:973b8ed30cd36533da4cdb76729e833324a3043bad48c74f61b6a1cc3df40b78 \
https://github.com/daveshanley/vacuum/releases/download/v0.30.3/vacuum_0.30.3_linux_x86_64.tar.gz /out/
FROM scratch AS vacuum-arm64
ADD --unpack --checksum=sha256:04b604df0b1b570d5abd58b577c816122da162eb8ba12a7f70c3060aec12b3a9 \
https://github.com/daveshanley/vacuum/releases/download/v0.30.3/vacuum_0.30.3_linux_arm64.tar.gz /out/
FROM vacuum-${TARGETARCH} AS vacuum
# validate-api-reference checks the vendored presentation data
FROM base AS validate-api-reference
RUN apk add --no-cache bash
WORKDIR /project
COPY --from=vacuum /out/vacuum /usr/local/bin/vacuum
COPY hack/api-docs ./hack/api-docs
COPY content/reference/api ./content/reference/api
COPY data/api-reference.json ./data/api-reference.json
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build <<"EOT"
set -eu
cp data/api-reference.json /tmp/api-reference-committed.json
./hack/api-docs/run.sh test
./hack/api-docs/run.sh generate
if ! cmp -s /tmp/api-reference-committed.json data/api-reference.json; then
echo >&2 'ERROR: API reference data is stale. Run ./hack/api-docs/run.sh generate and commit data/api-reference.json.'
exit 1
fi
EOT
# test validates HTML output and checks for broken links
FROM wjdp/htmltest:v${HTMLTEST_VERSION} AS test
WORKDIR /test
COPY --from=build /project/public ./public
ADD .htmltest.yml .htmltest.yml
RUN htmltest
# vale
FROM jdkato/vale:v${VALE_VERSION} AS vale-run
WORKDIR /src
ARG GITHUB_ACTIONS
RUN --mount=type=bind,target=.,rw <<EOT
set -e
mkdir /out
args=""
[ "$GITHUB_ACTIONS" = "true" ] && args="--output=.vale-rdjsonl.tmpl"
set -x
vale sync
vale $args content/ | tee /out/vale.out
EOT
FROM scratch AS vale
COPY --from=vale-run /out/vale.out /
# update-modules downloads and vendors Hugo modules
FROM build-base AS update-modules
# MODULE is the Go module path and version of the module to update
ARG MODULE
RUN <<"EOT"
set -ex
if [ -n "$MODULE" ]; then
hugo mod get ${MODULE}
else
echo "no module set";
fi
EOT
RUN hugo mod vendor
# vendor is an empty stage with only vendored Hugo modules
FROM scratch AS vendor
COPY --from=update-modules /project/_vendor /_vendor
COPY --from=update-modules /project/go.* /
FROM base AS validate-vendor
RUN --mount=target=/context \
--mount=type=bind,from=vendor,target=/out \
--mount=target=.,type=tmpfs <<EOT
set -e
rsync -a /context/. .
git add -A
rm -rf _vendor
cp -rf /out/* .
if [ -n "$(git status --porcelain -- go.mod go.sum _vendor)" ]; then
echo >&2 'ERROR: Vendor result differs. Please vendor your package with "make vendor"'
git status --porcelain -- go.mod go.sum _vendor
exit 1
fi
EOT
# build-upstream builds an upstream project with a replacement module
FROM build-base AS build-upstream
# UPSTREAM_MODULE_NAME is the canonical upstream repository name and namespace (e.g. moby/buildkit)
ARG UPSTREAM_MODULE_NAME
# UPSTREAM_REPO is the repository of the project to validate (e.g. dvdksn/buildkit)
ARG UPSTREAM_REPO
# UPSTREAM_COMMIT is the commit hash of the upstream project to validate
ARG UPSTREAM_COMMIT
# HUGO_MODULE_REPLACEMENTS is the replacement module for the upstream project
ENV HUGO_MODULE_REPLACEMENTS="github.com/${UPSTREAM_MODULE_NAME} -> github.com/${UPSTREAM_REPO} ${UPSTREAM_COMMIT}"
RUN hugo --ignoreVendorPaths "github.com/${UPSTREAM_MODULE_NAME}"
# validate-upstream validates HTML output for upstream builds
FROM wjdp/htmltest:v${HTMLTEST_VERSION} AS validate-upstream
WORKDIR /test
COPY --from=build-upstream /project/public ./public
ADD .htmltest.yml .htmltest.yml
RUN htmltest
# unused-media checks for unused graphics and other media
FROM alpine:${ALPINE_VERSION} AS unused-media
RUN apk add --no-cache fd ripgrep
WORKDIR /test
RUN --mount=type=bind,target=. ./hack/test/unused_media
# pagefind installs the Pagefind runtime
FROM base AS pagefind
ARG PAGEFIND_VERSION
COPY --from=build /project/public ./public
RUN --mount=type=bind,src=pagefind.yml,target=pagefind.yml \
npx pagefind@v${PAGEFIND_VERSION} --output-path "/pagefind"
# index generates a Pagefind index
FROM scratch AS index
COPY --from=pagefind /pagefind .
# test-go-redirects checks that the /go/ redirects are valid
FROM alpine:${ALPINE_VERSION} AS test-go-redirects
WORKDIR /work
RUN apk add yq
COPY --from=build /project/public ./public
RUN --mount=type=bind,target=. <<"EOT"
set -ex
./hack/test/go_redirects
EOT
# release is an empty scratch image with only compiled assets
FROM scratch AS release
COPY --from=build /project/public /
COPY --from=pagefind /pagefind /pagefind