|
# Set the working directory globally |
|
ARG SOURCEDIR="app" |
|
|
|
# Pin the Python version to use |
|
# See the following article to learn more about choosing the right base image |
|
# https://pythonspeed.com/articles/base-image-python-docker-images |
|
ARG PYTHONVERSION="3.11-slim-bookworm" |
|
|
|
# Createh the base image for generating the requirements file |
|
FROM python:${PYTHONVERSION} AS builder |
|
|
|
# Reinitialise the "source directory" for the current stage |
|
ARG SOURCEDIR |
|
|
|
# Configure Python to not buffer "stdout" or create .pyc files |
|
ENV PYTHONBUFFERED=1 |
|
ENV PYTHONDONTWRITEBYTECODE=1 |
|
|
|
# Add a non-root user for security reasons |
|
RUN adduser --home /${SOURCEDIR} app-name |
|
USER app-name |
|
|
|
# Ensure the poetry binary is accessible and executable |
|
ENV PATH=/${SOURCEDIR}/.local/bin:$PATH |
|
|
|
# Update pip to start working with Python |
|
RUN python -m pip install pip~=23.0 \ |
|
--upgrade --no-cache-dir --disable-pip-version-check --no-compile && \ |
|
python -m pip install poetry~=1.0 \ |
|
--no-cache-dir --disable-pip-version-check --no-compile |
|
|
|
# Set the proper working directory to generate the "requirements.txt" file into |
|
WORKDIR /home/app-name/${SOURCEDIR} |
|
|
|
# Copy the necessary files for Poetry to the generate the requirements file from |
|
COPY ../pyproject.toml ../poetry.lock ./ |
|
|
|
# Create a "requirements.txt" file for the "runtime" stage |
|
RUN poetry export --output=requirements.txt --only=main |
|
|
|
# Base image for the "runtime" stage |
|
FROM python:${PYTHONVERSION} AS runtime |
|
|
|
# Reinitialise the working directory for the current stage |
|
ARG SOURCEDIR |
|
|
|
# Ensure the Poetry is accessible and executable |
|
ENV PATH=/${SOURCEDIR}/.local/bin:$PATH |
|
|
|
# Ensure the system is up-to-date with the latest security updates |
|
RUN apt-get update && \ |
|
apt-get upgrade --assume-yes && \ |
|
# cURL is necessary to invoke the "healthcheck" function using Docker |
|
apt-get install curl --assume-yes && \ |
|
rm --recursive --force /var/lib/apt/lists/* |
|
|
|
# See the following article for information on this regards: |
|
# https://pythonspeed.com/articles/root-capabilities-docker-security |
|
RUN adduser --home /${SOURCEDIR} app-name |
|
USER app-name |
|
|
|
# Set the working directory to a secure non-root location |
|
WORKDIR /home/app-name |
|
|
|
# Copy the necessary runtime files from the previous "builder" stage |
|
COPY --from=builder /home/app-name/${SOURCEDIR}/requirements.txt ./ |
|
|
|
# Install the runtime dependencies using pip and additionally cache the dependencies to optimise build times |
|
RUN --mount=type=cache,target=/root/.cache \ |
|
python -m pip install pip~=23.0 --upgrade --no-cache-dir \ |
|
--disable-pip-version-check --no-compile && \ |
|
python -m pip install --requirement "requirements.txt" \ |
|
--require-hashes --no-cache-dir --disable-pip-version-check --no-compile && \ |
|
rm --force "requirements.txt" |
|
|
|
# Copy the source code to the container |
|
COPY . ./${SOURCEDIR} |
|
|
|
# Document which port to export |
|
# TODO: Might remove this line if it proves to be a security bad practice |
|
EXPOSE 8000 |
|
|
|
# Invoke the Python entrypoint file to start the backend service |
|
CMD [ "python", "-m", "${SOURCEDIR}.main" ] |
|
|
|
# Perform a healthcheck to ensure the service is up and running |
|
HEALTHCHECK --interval=5s --timeout=5s --retries=5 CMD curl --include --request GET http://localhost:8000/healthcheck || exit 1 |