From 5901059ca543271f39e97db289897af022574fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Mon, 20 Nov 2023 09:53:15 +0100 Subject: [PATCH 1/9] feat: Create app image from venv + source This change slims down the app image, reducing the space requirements by about 400MB: build-essential (370MB) and poetry (30MB) don't get included. --- .../Dockerfile | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index 57e926d7..3f7823c1 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -1,6 +1,10 @@ # syntax=docker/dockerfile:1 ARG PYTHON_VERSION={{ cookiecutter.python_version }} FROM {{ cookiecutter.docker_image }} AS base + +# Remove docker-clean so we can keep the apt cache in Docker build cache. +RUN rm /etc/apt/apt.conf.d/docker-clean + {%- if cookiecutter.development_environment == "strict" %} # Configure Python to print tracebacks on crash [1], and to not buffer stdout and stderr [2]. @@ -10,18 +14,6 @@ ENV PYTHONFAULTHANDLER 1 ENV PYTHONUNBUFFERED 1 {%- endif %} -# Install Poetry. -ENV POETRY_VERSION 1.6.1 -RUN --mount=type=cache,target=/root/.cache/pip/ \ - pip install poetry~=$POETRY_VERSION - -# Install compilers that may be required for certain packages or platforms. -RUN rm /etc/apt/apt.conf.d/docker-clean -RUN --mount=type=cache,target=/var/cache/apt/ \ - --mount=type=cache,target=/var/lib/apt/ \ - apt-get update && \ - apt-get install --no-install-recommends --yes build-essential - # Create a non-root user and switch to it [1]. # [1] https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user ARG UID=1000 @@ -39,6 +31,27 @@ ENV VIRTUAL_ENV /opt/{{ cookiecutter.__package_name_kebab_case }}-env # Set the working directory. WORKDIR /workspaces/{{ cookiecutter.__package_name_kebab_case }}/ +FROM base as builder + +USER root + +# Install Poetry in separate venv so it doesn't pollute the main venv. +ENV POETRY_VERSION 1.6.1 +ENV POETRY_VIRTUAL_ENV /opt/poetry-env +RUN --mount=type=cache,target=/root/.cache/pip/ \ + python3 -m venv $POETRY_VIRTUAL_ENV && \ + $POETRY_VIRTUAL_ENV/bin/pip install -U pip setuptools && \ + $POETRY_VIRTUAL_ENV/bin/pip install poetry~=$POETRY_VERSION +RUN ln -s $POETRY_VIRTUAL_ENV/bin/poetry /usr/bin/poetry + +# Install compilers that may be required for certain packages or platforms. +RUN --mount=type=cache,target=/var/cache/apt/ \ + --mount=type=cache,target=/var/lib/apt/ \ + apt-get update && \ + apt-get install --no-install-recommends --yes build-essential + +USER user + # Install the run time Python dependencies in the virtual environment. COPY --chown=user:user poetry.lock* pyproject.toml /workspaces/{{ cookiecutter.__package_name_kebab_case }}/ RUN mkdir -p /home/user/.cache/pypoetry/ && mkdir -p /home/user/.config/pypoetry/ && \ @@ -51,7 +64,7 @@ RUN --mount=type=cache,uid=$UID,gid=$GID,target=/home/user/.cache/pypoetry/ \ -FROM base as ci +FROM builder as ci # Allow CI to run as root. USER root @@ -71,7 +84,7 @@ RUN --mount=type=cache,target=/root/.cache/pypoetry/ \ -FROM base as dev +FROM builder as dev # Install development tools: curl, git, gpg, ssh, starship, sudo, vim, and zsh. USER root @@ -124,6 +137,9 @@ RUN ln -s /run/secrets/poetry-auth /home/user/.config/pypoetry/auth.toml FROM base AS app +# Copy the virtual environment from the builder stage +COPY --from=builder $VIRTUAL_ENV $VIRTUAL_ENV + # Copy the package source code to the working directory. COPY --chown=user:user . . From 4df178fcaf036ac89387bfde546b23104466385b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Mon, 20 Nov 2023 09:54:31 +0100 Subject: [PATCH 2/9] feat: Don't include .git in the app image --- {{ cookiecutter.__package_name_kebab_case }}/.dockerignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 {{ cookiecutter.__package_name_kebab_case }}/.dockerignore diff --git a/{{ cookiecutter.__package_name_kebab_case }}/.dockerignore b/{{ cookiecutter.__package_name_kebab_case }}/.dockerignore new file mode 100644 index 00000000..191381ee --- /dev/null +++ b/{{ cookiecutter.__package_name_kebab_case }}/.dockerignore @@ -0,0 +1 @@ +.git \ No newline at end of file From ea06cbb1a62a3623cdb52e6dba0259a70327ac36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Wed, 22 Nov 2023 13:05:22 +0100 Subject: [PATCH 3/9] chore: Add period Co-authored-by: Laurent Sorber --- {{ cookiecutter.__package_name_kebab_case }}/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index 3f7823c1..9e7f1b72 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -137,7 +137,7 @@ RUN ln -s /run/secrets/poetry-auth /home/user/.config/pypoetry/auth.toml FROM base AS app -# Copy the virtual environment from the builder stage +# Copy the virtual environment from the builder stage. COPY --from=builder $VIRTUAL_ENV $VIRTUAL_ENV # Copy the package source code to the working directory. From a8c3d1fe8ec562403b83311617cc6ff2ca58f5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Wed, 22 Nov 2023 17:21:03 +0100 Subject: [PATCH 4/9] chore: Simplify Poetry installation --- {{ cookiecutter.__package_name_kebab_case }}/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index 9e7f1b72..0f29342c 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -39,10 +39,9 @@ USER root ENV POETRY_VERSION 1.6.1 ENV POETRY_VIRTUAL_ENV /opt/poetry-env RUN --mount=type=cache,target=/root/.cache/pip/ \ - python3 -m venv $POETRY_VIRTUAL_ENV && \ - $POETRY_VIRTUAL_ENV/bin/pip install -U pip setuptools && \ + python -m venv $POETRY_VIRTUAL_ENV && \ $POETRY_VIRTUAL_ENV/bin/pip install poetry~=$POETRY_VERSION -RUN ln -s $POETRY_VIRTUAL_ENV/bin/poetry /usr/bin/poetry +RUN ln -s $POETRY_VIRTUAL_ENV/bin/poetry /usr/local/bin/poetry # Install compilers that may be required for certain packages or platforms. RUN --mount=type=cache,target=/var/cache/apt/ \ From 748521e8bc87c0da05e8b1ef8ae6e0764b54f230 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Wed, 22 Nov 2023 17:21:49 +0100 Subject: [PATCH 5/9] chore: Simplify virtualenv initialization --- {{ cookiecutter.__package_name_kebab_case }}/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index 0f29342c..c65459d4 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -24,9 +24,9 @@ RUN groupadd --gid $GID user && \ USER user # Create and activate a virtual environment. -RUN python -m venv /opt/{{ cookiecutter.__package_name_kebab_case }}-env -ENV PATH /opt/{{ cookiecutter.__package_name_kebab_case }}-env/bin:$PATH ENV VIRTUAL_ENV /opt/{{ cookiecutter.__package_name_kebab_case }}-env +ENV PATH $VIRTUAL_ENV/bin:$PATH +RUN python -m venv $VIRTUAL_ENV # Set the working directory. WORKDIR /workspaces/{{ cookiecutter.__package_name_kebab_case }}/ From 55ad80a72c02a3c0d3ad700d7cafe74562ff732b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Wed, 22 Nov 2023 17:22:11 +0100 Subject: [PATCH 6/9] chore: Rename `builder` stage to `poetry` --- .../Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index c65459d4..eb62e9ab 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -31,7 +31,7 @@ RUN python -m venv $VIRTUAL_ENV # Set the working directory. WORKDIR /workspaces/{{ cookiecutter.__package_name_kebab_case }}/ -FROM base as builder +FROM base as poetry USER root @@ -63,7 +63,7 @@ RUN --mount=type=cache,uid=$UID,gid=$GID,target=/home/user/.cache/pypoetry/ \ -FROM builder as ci +FROM poetry as ci # Allow CI to run as root. USER root @@ -83,7 +83,7 @@ RUN --mount=type=cache,target=/root/.cache/pypoetry/ \ -FROM builder as dev +FROM poetry as dev # Install development tools: curl, git, gpg, ssh, starship, sudo, vim, and zsh. USER root @@ -136,8 +136,8 @@ RUN ln -s /run/secrets/poetry-auth /home/user/.config/pypoetry/auth.toml FROM base AS app -# Copy the virtual environment from the builder stage. -COPY --from=builder $VIRTUAL_ENV $VIRTUAL_ENV +# Copy the virtual environment from the poetry stage. +COPY --from=poetry $VIRTUAL_ENV $VIRTUAL_ENV # Copy the package source code to the working directory. COPY --chown=user:user . . From 76894c9ec03d4276f1dfd2589bca4d4990ba8876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Wed, 22 Nov 2023 17:38:39 +0100 Subject: [PATCH 7/9] chore: Use three newlines between stages --- {{ cookiecutter.__package_name_kebab_case }}/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index eb62e9ab..d3747021 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -31,6 +31,8 @@ RUN python -m venv $VIRTUAL_ENV # Set the working directory. WORKDIR /workspaces/{{ cookiecutter.__package_name_kebab_case }}/ + + FROM base as poetry USER root From 64a7e09ece63d38755befde27d830f78f9fa57eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Wed, 22 Nov 2023 19:23:35 +0100 Subject: [PATCH 8/9] chore: Merge two RUN layers --- {{ cookiecutter.__package_name_kebab_case }}/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index d3747021..f85d99ed 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -42,8 +42,8 @@ ENV POETRY_VERSION 1.6.1 ENV POETRY_VIRTUAL_ENV /opt/poetry-env RUN --mount=type=cache,target=/root/.cache/pip/ \ python -m venv $POETRY_VIRTUAL_ENV && \ - $POETRY_VIRTUAL_ENV/bin/pip install poetry~=$POETRY_VERSION -RUN ln -s $POETRY_VIRTUAL_ENV/bin/poetry /usr/local/bin/poetry + $POETRY_VIRTUAL_ENV/bin/pip install poetry~=$POETRY_VERSION && \ + ln -s $POETRY_VIRTUAL_ENV/bin/poetry /usr/local/bin/poetry # Install compilers that may be required for certain packages or platforms. RUN --mount=type=cache,target=/var/cache/apt/ \ From e991c945ba82a252969ea344949942a639e374e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Go=C3=A1s=20Aguililla?= Date: Thu, 23 Nov 2023 14:03:11 +0100 Subject: [PATCH 9/9] chore: Remove extraneous newline --- {{ cookiecutter.__package_name_kebab_case }}/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile index f85d99ed..2ee279c3 100644 --- a/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile +++ b/{{ cookiecutter.__package_name_kebab_case }}/Dockerfile @@ -4,7 +4,6 @@ FROM {{ cookiecutter.docker_image }} AS base # Remove docker-clean so we can keep the apt cache in Docker build cache. RUN rm /etc/apt/apt.conf.d/docker-clean - {%- if cookiecutter.development_environment == "strict" %} # Configure Python to print tracebacks on crash [1], and to not buffer stdout and stderr [2].