X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/50995366c1728536907fbeded492f681c56c1b0d..e6239f4e83a99503be4c09c329029df1d3f2b5b9:/Dockerfile diff --git a/Dockerfile b/Dockerfile index b23530b9c..08ec72375 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,32 @@ -FROM python:3.9-trixie AS base +# Wolne Lektury images. +# +# Stages marked with ##### are build targets: +# deps dev image (docker-compose.yml, code mounted) +# test docker-compose.test.yml +# prod production app image (default, last stage) +# nginx production nginx with static files +# postgres Postgres with Polish dictionary +# Stages marked with ===== are intermediate. -ARG UID=1000 -ARG GID=1000 + +# Global build arguments. Stages using UID/GID must redeclare them +# (bare `ARG UID`) to bring them into scope; the defaults are set here. + +ARG PYTHON_IMAGE=python:3.10-trixie +ARG UID=8100 +ARG GID=8100 + + +########## +# deps ############################################################# +# +# Base system and requirements. +# Used directly as the dev image, with code mounted. +# +FROM ${PYTHON_IMAGE} AS deps + +ARG UID +ARG GID RUN apt-get update && apt-get install -y \ git \ @@ -18,8 +43,10 @@ RUN apt-get update && apt-get install -y \ COPY requirements/requirements.txt requirements.txt -RUN pip install --no-cache-dir -r requirements.txt -RUN pip install --no-cache-dir \ +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install -r requirements.txt +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install \ psycopg2-binary \ django-debug-toolbar==3.2.2 @@ -38,36 +65,113 @@ WORKDIR /app/src RUN mkdir /app/.ipython +#=======# +# app #============================================================= +# +# Code and production requirements. Not production yet: needs +# staticfiles.json manifest from static-builder. +# +FROM deps AS app +USER root -FROM base AS dev +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install gunicorn -#RUN pip install --no-cache-dir coverage +USER app +COPY src /app/src +#==================# +# static-builder #================================================== +# +# Static files are collected here. Statics are then copied into +# the nginx image, and staticfiles.json manifest is copied back +# into the test and prod images. +# +FROM app AS static-builder -FROM base AS prod +RUN python manage.py collectstatic --noinput -USER root -RUN pip install --no-cache-dir gunicorn +########### +# nginx ############################################################ +# +# Static files for production nginx. Config is mounted. +# +FROM nginx:alpine AS nginx -USER app +ARG UID +ARG GID -COPY src /app/src +# COPY nginx.conf conf.d/... +RUN addgroup -g $GID app && addgroup nginx app +COPY --from=static-builder /app/var/static /app/var/static +#===============# +# polish-dict #===================================================== +# +# Polish hunspell dictionary without diacritics, to allow +# full text search without diacritics. +# +FROM ${PYTHON_IMAGE} AS polish-dict -FROM prod AS static-builder +RUN apt-get update \ + && apt-get install -y --no-install-recommends hunspell-pl \ + && rm -rf /var/lib/apt/lists/* -RUN python manage.py collectstatic --noinput +COPY scripts/fold_hunspell.py /usr/local/bin/fold_hunspell.py +RUN set -eu; \ + mkdir /out; cd /tmp; \ + enc="$(sed -n 's/^SET[[:space:]]*//p' /usr/share/hunspell/pl_PL.aff | tr -d '\r')"; \ + iconv -f "${enc:-UTF-8}" -t UTF-8 /usr/share/hunspell/pl_PL.dic > pl.dict; \ + iconv -f "${enc:-UTF-8}" -t UTF-8 /usr/share/hunspell/pl_PL.aff > pl.affix; \ + python3 /usr/local/bin/fold_hunspell.py pl.dict pl.affix \ + /out/polish.dict /out/polish.affix; \ + dpkg-query -W -f='hunspell-pl ${Version}\n' hunspell-pl > /out/polish.version -FROM nginx:alpine AS nginx +############## +# postgres ######################################################### +# +# Postgres with the dictionary from polish-dict. +# +FROM postgres:18 AS postgres -# COPY nginx.conf conf.d/... +COPY --from=polish-dict /out/ /tmp/polish-dict/ +RUN mv /tmp/polish-dict/* "/usr/share/postgresql/$PG_MAJOR/tsearch_data/" \ + && rmdir /tmp/polish-dict -COPY --from=static-builder /app/var/static /app/var/static +COPY scripts/postgres-polish.sql /docker-entrypoint-initdb.d/10-postgres-polish.sql + + +########## +# test ############################################################# +# +# Production image plus test requirements. Defined before `prod`, +# so that `prod` stays the default (last) stage. +# +FROM app AS test + +USER root +COPY requirements/requirements-test.txt /tmp/ +RUN --mount=type=cache,target=/root/.cache/pip \ + pip install -r /tmp/requirements-test.txt +USER app +RUN mkdir -p /app/var/counters +COPY --from=static-builder /app/var/static/staticfiles.json /app/var/static/staticfiles.json +CMD ["./manage.py", "test"] + + +########## +# prod ############################################################# +# +# Production image: app + staticfiles.json manifest. +# +FROM app AS prod + +COPY --from=static-builder /app/var/static/staticfiles.json /app/var/static/staticfiles.json