chore(docker): default web + model-server bases to non-DHI images

Merged
JM
2mo ago
+170-98

Summary

web/Dockerfile and backend/Dockerfile.model_server pulled their bases straight from dhi.io, so every local docker build / docker compose --build needed a Docker account with Docker Hardened Image (DHI) catalog access. This makes the base images build args that default to the public Docker Hub images, and passes the DHI references from CI/CD instead.

Released and CI-tested images still ship on the same DHI bases at the same digests.

Changes

  • web/Dockerfile: NODE_BUILDER_IMAGE / NODE_RUNTIME_IMAGE args, defaulting to a digest-pinned node:24-trixie-slim (Debian trixie matches the DHI debian13 line, and glibc keeps the bun binary working). Added an explicit USER node so the default image also runs non-root, like the DHI runtime.
  • backend/Dockerfile.model_server: PYTHON_BUILDER_IMAGE / PYTHON_RUNTIME_IMAGE args, defaulting to the same digest-pinned python:3.13-slim that backend/Dockerfile already uses.
  • Both defaults route through BASE_IMAGE_REGISTRY, so the ECR pull-through cache still applies.
  • New .github/actions/dhi-base-images composite action: logs in to dhi.io and exports the four pinned DHI references, so the digests live in one place.
  • Every build step with an inline dhi.io login now calls that action and forwards the references as build args: four web builds and two model-server builds in deployment.yml, the web build in pr-playwright-tests.yml, and build-model-server-image/action.yml.
  • CONTRIBUTING.md: dropped the docker login dhi.io prerequisite for local builds.

Notes

CI paths that build these images through compose (e.g. pr-craft-compose-integration.yml) pass no build args, so they now use the public bases. Say the word if we want those on DHI too.

Testing

  • prek run --files ... (zizmor, actionlint, YAML checks) passes on the changed files.
  • Verified with BuildKit's own Dockerfile parser that the ARG defaults expand and both FROM lines resolve to the intended images.
  • Not run: an actual image build (no Docker daemon in the dev container) — CI covers it.

šŸ¤– Generated with Claude Code


Summary by cubic

Defaults the web and model-server Dockerfiles to digest-pinned public Docker Hub bases while keeping CI/release images on the same DHI digests. Previously all builds pulled from dhi.io; now local builds and fork PRs need no DHI access, and CI only uses DHI bases when credentials are available.

  • Adds NODE_BUILDER_IMAGE/NODE_RUNTIME_IMAGE in web/Dockerfile and PYTHON_BUILDER_IMAGE/PYTHON_RUNTIME_IMAGE in backend/Dockerfile.model_server, defaulting to public images and honoring BASE_IMAGE_REGISTRY for ECR pull-through.
  • Sets USER node in the web runtime to preserve non-root behavior when using public Node images.
  • Introduces ./.github/actions/dhi-base-images: conditionally logs into dhi.io when docker-username/docker-token are provided, exports DHI_NODE_BUILD_ARGS/DHI_PYTHON_BUILD_ARGS (complete build-arg lines). Without creds, it exports nothing and builds use public defaults.
  • Updates deployment.yml, pr-playwright-tests.yml, and .github/actions/build-model-server-image to use the composite action and forward DHI_* build args; Docker credentials are now optional. Adds the action to workflow path filters so digest bumps trigger rebuilds.
  • Updates CONTRIBUTING.md to remove docker login dhi.io for local builds and note that published images differ in base layers.

Required migration

  • If you maintain custom workflows that must stay on DHI bases, call ./.github/actions/dhi-base-images and pass the exported NODE_*/PYTHON_* build args to your docker build. No changes are needed for local builds or fork PRs without credentials.