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..198b43b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,3 +12,24 @@ 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 + env: + SSH_AUTH_SOCK: /tmp/ssh_agent.sock + run: | + ssh-agent -a $SSH_AUTH_SOCK > /dev/null + ssh-add - <<< "${{ secrets.DEPLOY_KEY }}" + docker build \ + --build-arg PYTHON_VERSION_CONSTRAINT="${{ steps.detect-versions.outputs.python-version-constraint }}" \ + --build-arg POETRY_VERSION="${{ steps.detect-versions.outputs.poetry-version }}" \ + --ssh default=$SSH_AUTH_SOCK -t sepacetamol-ci . +# TODO: share image tag when pushing part is implemented diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b7aaabb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,60 @@ +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 openssh-client \ + && 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=ssh --mount=type=cache,target=/root/.cache \ + mkdir -p -m 0600 ~/.ssh && \ + ssh-keyscan github.com >> ~/.ssh/known_hosts && \ + 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..3a0b6b0 --- /dev/null +++ b/docker-gunicorn.conf.py @@ -0,0 +1,11 @@ +bind = "0.0.0.0:8000" +worker = 2 +threads = 8 +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