Skip to content

Docker images are built without a .dockerignore or a lockfile #3375

Description

@adamtheturtle

What happens

src/mock_vws/_flask_server/Dockerfile does:

COPY --chown=10001:10001 . /app
...
RUN uv sync --no-cache

There is no .dockerignore in the repository, and no uv.lock.

Three consequences.

Everything is copied into the image. .git, tests/, docs/, newsfragments/, secrets.tar.gpg, and any local .venv or docker_venvs a contributor has, all land in /app in the published images. check-manifest already maintains a list of what does not belong in the distribution, in [tool.check-manifest], but nothing applies an equivalent to the image.

The dependency layer is invalidated by any source edit. Because the copy precedes uv sync, changing one line in src/mock_vws/target.py re-resolves and re-installs every dependency. docker-build.yml builds for linux/amd64 and linux/arm64, so that cost is paid twice per build.

Image builds are not reproducible. With no lockfile and >= constraints throughout [project.dependencies], uv sync resolves afresh at build time. Two builds of the same commit on different days can ship different versions of flask, numpy, opencv-contrib-python-headless, pillow and the rest. A released image tag is therefore not a fixed artefact, and a bug reproducible in one build of :latest may not reproduce in another.

Why it matters

The reproducibility point is the one that matters. The Docker images are the supported way to use this mock from languages other than Python, so they are a release artefact in their own right, and they are currently the only part of the project without pinned dependencies — optional-dependencies.dev pins every development tool to an exact version.

The other two are build time and image size, which are cheap to fix at the same time.

Suggested resolution

  1. Add a .dockerignore. The [tool.check-manifest] ignore list is a reasonable starting point for its contents.
  2. Commit a uv.lock and build with uv sync --locked, so the image contents follow from the commit. Dependabot already updates dependencies here, so keeping the lockfile current fits the existing workflow.
  3. Copy pyproject.toml and the lockfile, run uv sync, then copy the source, so that source edits do not invalidate the dependency layer.

Worth checking whether adding a lockfile interacts with setuptools-scm and the SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 workaround already in the Dockerfile.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions