diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5cc07db --- /dev/null +++ b/Dockerfile @@ -0,0 +1,64 @@ +# Stage 1: Build the requirements.txt using Poetry +FROM python:3.12-slim AS builder + +# Set environment variables for Python +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 +ENV PATH="${PATH}:/root/.local/bin" + +# Install system dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + curl \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Install Poetry +RUN curl -sSL https://install.python-poetry.org | python3 - + +# Copy only the poetry.lock/pyproject.toml to leverage Docker cache +WORKDIR /app +COPY pyproject.toml poetry.lock /app/ + +# Install dependencies and create requirements.txt +RUN poetry self add poetry-plugin-export && poetry export --format=requirements.txt --output=requirements.txt --only=main --without-hashes + +# Stage 2: Install dependencies and run the Django application +FROM python:3.12-slim AS runner + +# Set environment variables for Python +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# Create a non-root user +RUN useradd -ms /bin/bash appuser + +# Install system dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libpq-dev \ + git \ + netcat-openbsd \ + && rm -rf /var/lib/apt/lists/* + +# Copy the generated requirements.txt from the builder stage +WORKDIR /app +COPY --from=builder /app/requirements.txt /app/ + +# Install application dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the rest of the application code +COPY . /app/ + +# Change ownership of the application directory to the non-root user +RUN chown -R appuser:appuser /app + +# Switch to the non-root user +USER appuser + +# The port the application will listen on +EXPOSE 8000 + +# Run startup script +CMD ["./docker-entrypoint.sh"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..eb372cc --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +# Exit on error +set -e + +# Print commands and their arguments as they are executed. +set -x + +# Wait for database +echo "Waiting for database" +while ! nc -z "$PGHOST" "$PGPORT"; do + sleep 0.1 +done +echo "Database started" + +# Django entrypoint script +# 1. Collect static files +echo "Collect static files" +python manage.py collectstatic --noinput +echo "Collect static files done" + +# 2. Apply database migrations +echo "Apply database migrations" +python manage.py migrate +echo "Apply database migrations done" + +# https://docs.gunicorn.org/en/stable/design.html#how-many-workers +num_cores=$(nproc --all) +workers=$((2 * num_cores + 1)) + +# 3. Start server +echo "Starting server with $workers workers" +gunicorn --workers=$workers --bind=0.0.0.0:8000 feedvault.wsgi:application --log-level=info --access-logfile=- --error-logfile=- --forwarded-allow-ips="172.*,192.*" --proxy-allow-from="172.*,192.*" +echo "Bye, love you"