diff --git a/.dockerignore b/.dockerignore index d9b625e..3f2b844 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,9 +1,13 @@ +.env .git -__pycache__/ -*.py[cod] +.gitignore +README.md +Dockerfile +.dockerignore +.air.toml +tmp/ +.vscode/ +.idea/ *.log -!.env -venv/ -.venv/ -dist/ -build/ \ No newline at end of file +coverage.out +rideaware-api \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index c72dff0..7aa361b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,53 +1,52 @@ -FROM python:3.10-slim AS builder - -ENV PYTHONDONTWRITEBYTECODE=1 \ - PYTHONUNBUFFERED=1 \ - PIP_NO_CACHE_DIR=1 +# Build stage +FROM golang:1.21-alpine AS builder +# Set working directory WORKDIR /app -RUN apt-get update && apt-get install -y --no-install-recommends \ - build-essential gcc \ - && rm -rf /var/lib/apt/lists/* +# Install git (needed for some Go modules) +RUN apk add --no-cache git -COPY requirements.txt . +# Copy go mod files +COPY go.mod go.sum ./ -RUN python -m pip install --upgrade pip && \ - pip wheel --no-deps -r requirements.txt -w /wheels && \ - pip wheel --no-deps gunicorn -w /wheels +# Download dependencies +RUN go mod download -FROM python:3.10-slim AS runtime +# Copy source code +COPY . . -ENV PYTHONDONTWRITEBYTECODE=1 \ - PYTHONUNBUFFERED=1 \ - PIP_NO_CACHE_DIR=1 \ - PORT=5000 \ - WSGI_MODULE=server:app \ - GUNICORN_WORKERS=2 \ - GUNICORN_THREADS=4 \ - GUNICORN_TIMEOUT=60 \ - FLASK_APP=server.py +# Build the application +RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o rideaware-api . -WORKDIR /app +# Production stage +FROM alpine:latest -RUN groupadd -g 10001 app && useradd -m -u 10001 -g app app +# Install ca-certificates for HTTPS requests and timezone data +RUN apk --no-cache add ca-certificates tzdata -COPY --from=builder /wheels /wheels -RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels +# Create non-root user +RUN addgroup -g 1001 -S appgroup && \ + adduser -u 1001 -S appuser -G appgroup -# Install python-dotenv if not already in requirements.txt -RUN pip install python-dotenv +# Set working directory +WORKDIR /home/appuser -USER app +# Copy binary from builder stage +COPY --from=builder /app/rideaware-api . -COPY --chown=app:app . . +# Change ownership to non-root user +RUN chown -R appuser:appgroup /home/appuser -# Copy .env file specifically -COPY --chown=app:app .env .env +# Switch to non-root user +USER appuser -EXPOSE 5000 +# Expose port +EXPOSE 8080 -HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ - CMD python -c "import os,socket; s=socket.socket(); s.settimeout(2); s.connect(('127.0.0.1', int(os.getenv('PORT', '5000')))); s.close()" +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1 -CMD ["sh", "-c", "exec gunicorn $WSGI_MODULE --bind=0.0.0.0:$PORT --workers=$GUNICORN_WORKERS --threads=$GUNICORN_THREADS --timeout=$GUNICORN_TIMEOUT --access-logfile=- --error-logfile=- --keep-alive=5"] \ No newline at end of file +# Run the application +CMD ["./rideaware-api"] \ No newline at end of file