diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..234cc32f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,74 @@ +db.sqlite3 +.secret +static.dist +c3nav.cfg +/src/data +loadproduction.sh +runtileserver.sh +test.py +test.svg + +.idea + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +#Ipython Notebook +.ipynb_checkpoints diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..8618f6fd --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,74 @@ +# syntax=docker/dockerfile:1.4 +FROM ubuntu:lunar as base +ENV DEBIAN_FRONTEND noninteractive + +RUN --mount=type=cache,target=/var/cache/apt --mount=type=tmpfs,target=/var/lib/apt/lists \ + apt-get update && apt-get install -y --no-install-recommends \ + python3.11=3.11.2-6ubuntu0.1 \ + libpython3.11=3.11.2-6ubuntu0.1 \ + python3.11-venv=3.11.2-6ubuntu0.1 \ + python3-pip=23.0.1+dfsg-1 \ + libpq5=15.3-0ubuntu0.23.04.1 \ + postgresql-client-15=15.3-0ubuntu0.23.04.1 \ + curl=7.88.1-8ubuntu2 \ + libpcre3=2:8.39-15 \ + librsvg2-2=2.54.5+dfsg-1ubuntu2 \ + gir1.2-rsvg-2.0=2.54.5+dfsg-1ubuntu2 \ + libgirepository-1.0-1=1.76.1-1 \ + tzdata=2023c-2exp1ubuntu1.1 \ + ca-certificates=20230311ubuntu0.23.04.1 +ENV PATH="/usr/lib/postgresql/14/bin/:$PATH" + + +FROM base as builder +RUN --mount=type=cache,target=/var/cache/apt --mount=type=tmpfs,target=/var/lib/apt/lists \ + apt-get update && apt-get install -y --no-install-recommends \ + build-essential=12.9ubuntu3 \ + python3.11-dev=3.11.2-6ubuntu0.1 \ + libpcre3-dev=2:8.39-15 \ + libpq-dev=15.3-0ubuntu0.23.04.1 \ + libgirepository1.0-dev=1.76.1-1 + + +COPY --link /src /app +WORKDIR /app + +RUN --mount=type=cache,target=/pip-cache \ + python3.11 -m venv env && \ + . /app/env/bin/activate && \ + pip install --cache-dir /pip-cache --upgrade pip wheel && \ + pip install --cache-dir /pip-cache \ + -r requirements/production.txt \ + -r requirements/htmlmin.txt \ + -r requirements/postgres.txt \ + -r requirements/redis.txt \ + -r requirements/rsvg.txt \ + -r requirements/server-asgi.txt && \ + pip install --cache-dir /pip-cache uwsgi + +FROM base as final +RUN groupadd -r -g 500 c3nav && useradd -r -u 500 -g 500 -G www-data c3nav +RUN mkdir /data && chown -R c3nav:c3nav /data +VOLUME /data + +COPY --link --chown=500:500 /src /app +COPY --from=builder --chown=500:500 /app/env /app/env +COPY --chown=root:root --chmod=0755 /docker/entrypoint.sh /usr/bin/entrypoint + +ENV C3NAV_DEBUG="" \ + C3NAV_LOGLEVEL="info" \ + C3NAV_DATA_DIR="/data" \ + MPLBACKEND="agg" \ + UWSGI_WORKERS="8" + +USER c3nav +WORKDIR /app + +RUN /app/env/bin/python manage.py collectstatic -l --no-input && \ + /app/env/bin/python manage.py compress && \ + rm -r /data/* + +EXPOSE 8000 5000 +#HEALTHCHECK --start-period=5s --interval=10s --timeout=1s CMD curl -f http://localhost:8000/check || exit 1 +ENTRYPOINT ["/usr/bin/entrypoint"] +CMD ["web"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 00000000..3c245499 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -e + +cd /app +# enable python virtual env +. /app/env/bin/activate + +case "$1" in +web) + exec /app/env/bin/uwsgi --master \ + --wsgi "c3nav.wsgi" \ + --pythonpath "/app/src" \ + --enable-threads --ignore-sigpipe --disable-logging --need-app \ + --stats ":5000" \ + --http "0.0.0.0:8000" + ;; +webstatic) + exec /app/env/bin/uwsgi --master \ + --wsgi "c3nav.wsgi" \ + --pythonpath "/app/src" \ + --enable-threads --ignore-sigpipe --disable-logging --need-app \ + --static-map "${C3NAV_STATIC_URL:-/static}=${C3NAV_STATIC_ROOT:-/app/c3nav/static.dist}" \ + --static-safe "/app/c3nav/static" \ + --stats ":5000" \ + --http "0.0.0.0:8000" + ;; +web-async) + exec python -m uvicorn --host 0.0.0.0 --proxy-headers --no-server-header ${*:2} c3nav.asgi:application + ;; +webstatic-async) + exec python -m uvicorn --host 0.0.0.0 --proxy-headers --no-server-header ${*:2} c3nav.asgi:static_app + ;; +worker) + exec celery -A c3nav worker --max-tasks-per-child 300 --concurrency 2 -l INFO -E + ;; +beat) + exec celery -A c3nav beat -l INFO + ;; +manage) + exec python manage.py ${*:2} + ;; +migrate) + exec python manage.py migrate ${*:2} + ;; +python) + exec python ${*:2} + ;; +celery) + exec celery -A c3nav ${*:2} + ;; +**) + exec bash -c "$@" +esac diff --git a/docker/local_build.sh b/docker/local_build.sh new file mode 100755 index 00000000..2e0e205a --- /dev/null +++ b/docker/local_build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -e + +PROJDIR="$(dirname "$(dirname "$(readlink -f "$0")")")" +cd "$PROJDIR" +COMMIT="$(git rev-parse HEAD)" +docker buildx build -f docker/Dockerfile --load -t "c3nav:${COMMIT}" . \ No newline at end of file