Dockerfile#

# Dockerfile for ML Weather Application
# Base image: Ubuntu 22.04 LTS
FROM ubuntu:22.04

# Arguments for user and group IDs, typically passed from docker-compose for permission consistency
ARG HOST_UID=1000
ARG HOST_GID=1000

# Set environment variables for non-interactive installs and Python behavior
ENV DEBIAN_FRONTEND=noninteractive \
    PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PYTHONPATH=/app

# Set working directory for the application
WORKDIR /app

# Install Python 3.10, pip, venv, gosu, and clean up apt cache
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3 \
    python3-pip \
    python3-venv \
    gosu \
    curl \
    jq \
    && rm -rf /var/lib/apt/lists/*

# Copy only requirements first to leverage Docker layer caching for dependencies
COPY src/app/requirements.txt .
RUN pip3 install --cache-dir "/root/.cache/pip" -r requirements.txt

# Copy the entire application codebase into the container
COPY src/app/ ./app

# Create an 'appuser' with dynamic UID/GID to avoid permission conflicts with host
# Remove any existing user with the same UID (except 'appuser')
RUN if id -u $HOST_UID >/dev/null 2>&1; then \
        existing_user=$(id -nu $HOST_UID); \
        if [ "$existing_user" != "appuser" ]; then \
            userdel -f "$existing_user" 2>/dev/null || true; \
        fi; \
    fi

# Create group and user with the specified GID/UID, or rename existing group to 'appuser'
RUN if ! getent group $HOST_GID >/dev/null 2>&1; then \
        groupadd -g $HOST_GID appuser; \
    else \
        existing_group=$(getent group $HOST_GID | cut -d: -f1); \
        if [ "$existing_group" != "appuser" ]; then \
            groupmod -n appuser "$existing_group"; \
        fi; \
    fi

RUN if ! id -u appuser >/dev/null 2>&1; then \
        useradd -u $HOST_UID -g $HOST_GID -m -s /bin/bash appuser; \
    fi

# Ensure correct ownership of the application directory
RUN chown -R appuser:appuser /app

# Copy entrypoint script, make it executable, and set as ENTRYPOINT
COPY fastapi_entrypoint.sh /usr/local/bin/fastapi_entrypoint.sh
RUN chmod +x /usr/local/bin/fastapi_entrypoint.sh

ENTRYPOINT ["/usr/local/bin/fastapi_entrypoint.sh"]
# Do not set USER here; gosu in entrypoint handles user switching

EXPOSE 8000

# Default command executed by the entrypoint script as 'appuser'
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]