diff --git a/Dockerfile b/Dockerfile index 219891aa..7a7d02f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,12 @@ -# This Dockerfile has four stages: +# This Dockerfile has three stages: # # base-image # Updates the base Python image with security patches and common system # packages. This image becomes the base of all other images. -# dependencies-image -# Installs third-party dependencies (requirements/main.txt) into a virtual -# environment. This virtual environment is ideal for copying across build -# stages. # install-image -# Installs the app into the virtual environment. +# Installs third-party dependencies (requirements/main.txt) and the +# application into a virtual environment. This virtual environment is +# ideal for copying across build stages. # runtime-image # - Copies the virtual environment into place. # - Runs a non-root user. @@ -20,7 +18,7 @@ FROM python:3.12.1-slim-bullseye as base-image COPY scripts/install-base-packages.sh . RUN ./install-base-packages.sh && rm ./install-base-packages.sh -FROM base-image AS dependencies-image +FROM base-image AS install-image # Install system packages only needed for building dependencies. COPY scripts/install-dependency-packages.sh . @@ -29,8 +27,10 @@ RUN ./install-dependency-packages.sh # Create a Python virtual environment ENV VIRTUAL_ENV=/opt/venv RUN python -m venv $VIRTUAL_ENV + # Make sure we use the virtualenv ENV PATH="$VIRTUAL_ENV/bin:$PATH" + # Put the latest pip and setuptools in the virtualenv RUN pip install --upgrade --no-cache-dir pip setuptools wheel @@ -38,24 +38,20 @@ RUN pip install --upgrade --no-cache-dir pip setuptools wheel COPY requirements/main.txt ./requirements.txt RUN pip install --quiet --no-cache-dir -r requirements.txt -FROM dependencies-image AS install-image - -# Use the virtualenv -ENV PATH="/opt/venv/bin:$PATH" - +# Install the application. COPY . /workdir WORKDIR /workdir RUN pip install --no-cache-dir . FROM base-image AS runtime-image -# Create a non-root user +# Create a non-root user. RUN useradd --create-home appuser -# Copy the virtualenv +# Copy the virtualenv. COPY --from=install-image /opt/venv /opt/venv -# Make sure we use the virtualenv +# Make sure we use the virtualenv. ENV PATH="/opt/venv/bin:$PATH" # Switch to the non-root user. diff --git a/scripts/install-base-packages.sh b/scripts/install-base-packages.sh index 620781c1..2fd02247 100755 --- a/scripts/install-base-packages.sh +++ b/scripts/install-base-packages.sh @@ -1,7 +1,7 @@ #!/bin/bash -# This script updates packages in the base Docker image that's used by both the -# build and runtime images, and gives us a place to install additional +# This script updates packages in the base Docker image that's used by both +# the build and runtime images, and gives us a place to install additional # system-level packages with apt-get. # # Based on the blog post: @@ -9,26 +9,21 @@ # Bash "strict mode", to help catch problems and bugs in the shell # script. Every bash script you write should include this. See -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ for -# details. +# http://redsymbol.net/articles/unofficial-bash-strict-mode/ for details. set -euo pipefail # Display each command as it's run. set -x -# Tell apt-get we're never going to be able to give manual -# feedback: +# Tell apt-get we're never going to be able to give manual feedback. export DEBIAN_FRONTEND=noninteractive -# Update the package listing, so we know what packages exist: +# Update the package listing, so we know what packages exist. apt-get update -# Install security updates: +# Install security updates. apt-get -y upgrade -# Example of installing a new package, without unnecessary packages: -apt-get -y install --no-install-recommends git - -# Delete cached files we don't need anymore: +# Delete cached files we don't need anymore. apt-get clean rm -rf /var/lib/apt/lists/* diff --git a/scripts/install-dependency-packages.sh b/scripts/install-dependency-packages.sh index f63ef751..e75df482 100755 --- a/scripts/install-dependency-packages.sh +++ b/scripts/install-dependency-packages.sh @@ -10,25 +10,26 @@ # Bash "strict mode", to help catch problems and bugs in the shell # script. Every bash script you write should include this. See -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ for -# details. +# http://redsymbol.net/articles/unofficial-bash-strict-mode/ for details. set -euo pipefail # Display each command as it's run. set -x -# Tell apt-get we're never going to be able to give manual -# feedback: +# Tell apt-get we're never going to be able to give manual feedback. export DEBIAN_FRONTEND=noninteractive -# Update the package listing, so we know what packages exist: +# Update the package listing, so we know what packages exist. apt-get update -# Install build-essential because sometimes Python dependencies need to build -# C modules, particularly when upgrading to newer Python versions. libffi-dev -# is sometimes needed to build cffi (a cryptography dependency). -apt-get -y install --no-install-recommends build-essential libffi-dev +# Install various dependencies that may be required to install JupyterHub or +# our add-on modules, or are wanted at runtime: +# +# build-essential: sometimes needed to build Python modules +# git: required by setuptools_scm +# libffi-dev: sometimes needed to build cffi, a cryptography dependency +apt-get -y install --no-install-recommends build-essential git libffi-dev -# Delete cached files we don't need anymore: +# Delete cached files we don't need anymore. apt-get clean rm -rf /var/lib/apt/lists/*