From 61bbc1238850b8b052e3cc5743990682e7d66fbf Mon Sep 17 00:00:00 2001 From: Abiodun Sotunde Date: Mon, 20 Nov 2023 11:29:55 +0100 Subject: [PATCH] feat(docker): add docker file for production ready image --- .dockerignore | 2 ++ .github/workflows/ci.yml | 17 ++++++++++++ Dockerfile | 58 ++++++++++++++++++++++++++++++++++++++++ docker-gunicorn.conf.py | 11 ++++++++ 4 files changed, 88 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-gunicorn.conf.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..969b765 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +.tmp +*.sqlite3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e77ffce..251725a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,3 +12,20 @@ jobs: - uses: moneymeets/action-setup-python-poetry@master - uses: moneymeets/moneymeets-composite-actions/lint-python@master + + build-image: + runs-on: ubuntu-22.04 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - uses: moneymeets/moneymeets-composite-actions/detect-python-version@master + id: 'detect-versions' + + - name: Build image + run: | + docker build \ + --build-arg PYTHON_VERSION_CONSTRAINT="${{ steps.detect-versions.outputs.python-version-constraint }}" \ + --build-arg POETRY_VERSION="${{ steps.detect-versions.outputs.poetry-version }}" \ + -t sepacetamol-ci . +# TODO: share image tag when pushing part is implemented diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f39765c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +ARG PYTHON_VERSION_CONSTRAINT +FROM python:${PYTHON_VERSION_CONSTRAINT}-slim-bookworm as python-base + +LABEL maintainer="moneymeets GmbH " + +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + APP_PATH="/opt/app" \ + POETRY_HOME="/opt/poetry" \ + POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_IN_PROJECT=true \ + VENV_PATH="/opt/app/.venv" + +ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH" + +ARG POETRY_VERSION +FROM python-base as builder-deps + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt install -y curl git \ + && apt-get install -y --no-install-recommends build-essential \ + && curl -sSL https://install.python-poetry.org | python - --yes --version=${POETRY_VERSION} \ + && apt remove -y --purge curl \ + && rm -rf /var/lib/apt/lists/* + +COPY .git/ ./.git/ + +RUN git archive -v -o app.tar.gz --format=tar.gz HEAD + +WORKDIR $APP_PATH + +ADD poetry.lock pyproject.toml ./ + +RUN --mount=type=cache,target=/root/.cache \ + poetry install --without dev + + +FROM python-base as prod + +RUN apt update \ + && DEBIAN_FRONTEND=noninteractive apt install -y curl \ + && rm -rf /var/lib/apt/lists/* + + +# Copy Python dependencies from the previous build stage +COPY --from=builder-deps $APP_PATH $APP_PATH + +RUN useradd -m appuser -d $APP_PATH && chown appuser:appuser -R $APP_PATH + +USER appuser + +WORKDIR $APP_PATH + +COPY --from=builder-deps app.tar.gz $APP_PATH + +RUN tar -xvf app.tar.gz && rm -rf app.tar.gz + +ENTRYPOINT [ "bash", "-c", "gunicorn -c ./docker-gunicorn.conf.py" ] diff --git a/docker-gunicorn.conf.py b/docker-gunicorn.conf.py new file mode 100644 index 0000000..380cfbe --- /dev/null +++ b/docker-gunicorn.conf.py @@ -0,0 +1,11 @@ +bind = "0.0.0.0:8000" +worker = 2 +threads = 4 +keepalive = 5 +wsgi_app = "config.wsgi" +loglevel = "debug" +access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" "%(M)s"' +errorlog = "-" # log to stderr +accesslog = "-" # log to stdout +# Enable inheritance for stdio file descriptors in daemon mode, allows to stream more logs to stdout +enable_stdio_inheritance = True