From 0daa708a050f6141ea7751fdbf910155ee5cd67b Mon Sep 17 00:00:00 2001 From: Michael Manganiello Date: Sat, 22 Jun 2024 18:11:46 -0300 Subject: [PATCH] misc: Simplify backend environment configuration in Docker image This change moves the virtualenv creation in the `Dockerfile` to a separate stage, to simplify isolating the process and reduce the need for uninstalling build dependencies. The approach is similar to the one explained in [1]. It relies on building a virtualenv folder, and copying it in the final stage. Changing the `PATH` environment variable makes the virtualenv usable by default, without affecting the default Python installation. Also, added Dockerfile arguments for Alpine, nginx, and Python versions, as some of them are reused, and also simplifies testing new versions. An extra side effect is that the image size for the final stage is reduced from 315MB to 262MB. [1] https://scribe.rip/@albertazzir/blazing-fast-python-docker-builds-with-poetry-a78a66f5aed0 --- docker/Dockerfile | 82 +++++++++++++++------------------------- docker/init_scripts/init | 4 -- 2 files changed, 31 insertions(+), 55 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 81d53758c..05941cf39 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,11 +1,33 @@ +ARG ALPINE_VERSION=3.19 +ARG NGINX_VERSION=1.27.0 +ARG PYTHON_VERSION=3.11 + # Build frontend -FROM node:lts-alpine as front-build-stage +FROM node:lts-alpine${ALPINE_VERSION} as front-build-stage WORKDIR /front COPY ./frontend ./ RUN npm install && npm run build +# Build backend environment +FROM python:${PYTHON_VERSION}-alpine${ALPINE_VERSION} AS backend-build + +RUN apk add --no-cache \ + gcc \ + mariadb-connector-c-dev \ + musl-dev + +RUN pip install poetry + +ENV POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_IN_PROJECT=1 + +WORKDIR /src + +COPY ./pyproject.toml ./poetry.lock /src/ +RUN poetry install --no-ansi --no-cache --only main + # Setup frontend and backend -FROM nginx:1.27.0-alpine3.19-slim as production-stage +FROM nginx:${NGINX_VERSION}-alpine${ALPINE_VERSION}-slim as production-stage ARG WEBSERVER_FOLDER=/var/www/html COPY --from=front-build-stage /front/dist ${WEBSERVER_FOLDER} @@ -19,58 +41,11 @@ RUN mkdir -p ${WEBSERVER_FOLDER}/assets/romm && \ # Install required packages and dependencies RUN apk add --no-cache \ bash \ - curl \ - libffi \ mariadb-connector-c \ - netcat-openbsd \ python3 \ tzdata \ - gcc \ - libffi-dev \ - mariadb-connector-c-dev \ - musl-dev \ - python3-dev \ - py3-pip \ - git \ - coreutils \ - make \ - openssl-dev \ redis -# Create python venv and install dependencies -COPY ./pyproject.toml ./poetry.lock / -RUN python3 -m venv /backend/ && \ - . /backend/bin/activate && \ - pip install --no-cache --upgrade pip && \ - pip install --no-cache git+https://github.com/radoering/poetry.git@non-package-mode && \ - pip freeze | awk -F= '{print $1}' > /installed_pip_requirements.txt && \ - mkdir -p /root/.cache/pypoetry/virtualenvs && \ - python3 -m poetry config --no-cache virtualenvs.create false && \ - python3 -m poetry env use 3.11 && \ - python3 -m poetry install --no-interaction --no-ansi --no-cache --only main && \ - python3 -m poetry export --without-hashes --only main --without-urls | awk -F= '{print $1}' > /installed_poetry_requirements.txt && \ - grep -v -x -f /installed_poetry_requirements.txt /installed_pip_requirements.txt > /build_requirements.txt && \ - pip uninstall -y -r /build_requirements.txt - -# Cleanup unnecessary packages and files -RUN apk del \ - gcc \ - libffi-dev \ - mariadb-connector-c-dev \ - musl-dev \ - python3-dev \ - py3-pip \ - git \ - coreutils \ - make \ - openssl-dev && \ - rm -r \ - /pyproject.toml \ - /poetry.lock \ - /installed_pip_requirements.txt \ - /installed_poetry_requirements.txt \ - /build_requirements.txt - COPY ./backend /backend # Setup init script and config files @@ -83,13 +58,18 @@ RUN addgroup -g 1000 -S romm && adduser -u 1000 -D -S -G romm romm && \ # Move everything to final stage FROM scratch as final-stage + COPY --from=production-stage / / +COPY --from=backend-build /src/.venv /src/.venv +# Fix virtualenv link to python binary +RUN ln -sf "$(which python)" /src/.venv/bin/python +ENV PATH="/src/.venv/bin:${PATH}" + # Declare the supported volumes VOLUME ["/romm/resources", "/romm/library", "/romm/assets", "/romm/config", "/redis-data"] # Expose ports and start -EXPOSE 8080 -EXPOSE 6379/tcp +EXPOSE 8080 6379/tcp WORKDIR /romm CMD ["/init"] diff --git a/docker/init_scripts/init b/docker/init_scripts/init index 3c0a19ead..b071b9aec 100755 --- a/docker/init_scripts/init +++ b/docker/init_scripts/init @@ -5,10 +5,6 @@ set -o nounset # treat unset variables as an error set -o pipefail # treat errors in pipes as fatal shopt -s inherit_errexit # inherit errexit -# use virtualenvs -# shellcheck disable=SC1091 -source /backend/bin/activate - # make it possible to disable the inotify watcher process ENABLE_RESCAN_ON_FILESYSTEM_CHANGE="${ENABLE_RESCAN_ON_FILESYSTEM_CHANGE:="true"}"