From 6f82c56995aaad0782bb5f044521b676d03c291f Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Fri, 13 Mar 2026 17:19:12 +0200 Subject: [PATCH] chore(devops): docker-compose dev + prod, Dockerfiles, nginx, Makefile - backend/Dockerfile: Python 3.12 slim, non-root user, WeasyPrint system deps - backend/Dockerfile.dev: dev variant with hot-reload support - frontend/Dockerfile: Node 20 alpine build + nginx:alpine serve - frontend/nginx.conf: SPA routing + /api proxy to backend:8000 - docker-compose.yml: production with healthcheck - docker-compose.dev.yml: dev with volume mounts and hot-reload - Makefile: dev, build, up, down, logs, migrate, test, shell, prod targets - .dockerignore for backend and frontend Co-Authored-By: Claude Sonnet 4.6 --- Makefile | 45 ++++++++++++++++++++++++++++++++++++++++++ backend/.dockerignore | 11 +++++++++++ backend/Dockerfile | 20 +++++++++++++++++++ backend/Dockerfile.dev | 20 +++++++++++++++++++ docker-compose.dev.yml | 26 ++++++++++++++++++++++++ docker-compose.yml | 25 +++++++++++++++++++++++ frontend/.dockerignore | 7 +++++++ frontend/Dockerfile | 12 +++++++++++ frontend/nginx.conf | 18 +++++++++++++++++ 9 files changed, 184 insertions(+) create mode 100644 Makefile create mode 100644 backend/.dockerignore create mode 100644 backend/Dockerfile create mode 100644 backend/Dockerfile.dev create mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.yml create mode 100644 frontend/.dockerignore create mode 100644 frontend/Dockerfile create mode 100644 frontend/nginx.conf diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7764d84 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +.PHONY: dev build up down logs migrate test shell-backend shell-frontend seed backup prod-build prod-up + +# Development +dev: + docker compose -f docker-compose.dev.yml up + +build: + docker compose -f docker-compose.dev.yml build + +up: + docker compose -f docker-compose.dev.yml up -d + +down: + docker compose -f docker-compose.dev.yml down + +logs: + docker compose -f docker-compose.dev.yml logs -f + +# Database +migrate: + docker compose -f docker-compose.dev.yml exec backend alembic upgrade head + +seed: + docker compose -f docker-compose.dev.yml exec backend python -m app.db.seed + +backup: + cp backend/data/roaauto.db backend/data/backup-$(shell date +%Y%m%d-%H%M%S).db + +# Testing +test: + docker compose -f docker-compose.dev.yml exec backend pytest tests/ -v + +# Shell access +shell-backend: + docker compose -f docker-compose.dev.yml exec backend bash + +shell-frontend: + docker compose -f docker-compose.dev.yml exec frontend sh + +# Production +prod-build: + docker compose build + +prod-up: + docker compose up -d diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..3555f97 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,11 @@ +__pycache__ +*.pyc +*.pyo +.pytest_cache +.env +data/*.db +data/backup-* +.git +.gitignore +tests/ +*.md diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..6c1c9b2 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,20 @@ +FROM python:3.12-slim + +RUN apt-get update && apt-get install -y \ + libpango-1.0-0 libpangoft2-1.0-0 libpangocairo-1.0-0 \ + libgdk-pixbuf2.0-0 libcairo2 curl \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -m -s /bin/bash appuser + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +RUN chown -R appuser:appuser /app +USER appuser + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"] diff --git a/backend/Dockerfile.dev b/backend/Dockerfile.dev new file mode 100644 index 0000000..bddfead --- /dev/null +++ b/backend/Dockerfile.dev @@ -0,0 +1,20 @@ +FROM python:3.12-slim + +RUN apt-get update && apt-get install -y \ + libpango-1.0-0 libpangoft2-1.0-0 libpangocairo-1.0-0 \ + libgdk-pixbuf2.0-0 libcairo2 \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -m -s /bin/bash appuser + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +RUN chown -R appuser:appuser /app +USER appuser + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..481459a --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,26 @@ +services: + backend: + build: + context: ./backend + dockerfile: Dockerfile.dev + ports: + - "8000:8000" + volumes: + - ./backend:/app + - ./backend/data:/app/data + environment: + - DATABASE_URL=sqlite+aiosqlite:///./data/roaauto.db + - SECRET_KEY=dev-secret-key-change-in-prod + - CORS_ORIGINS=http://localhost:5173 + command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload + + frontend: + image: node:20-alpine + ports: + - "5173:5173" + volumes: + - ./frontend:/app + working_dir: /app + environment: + - VITE_API_URL=http://localhost:8000/api + command: sh -c "npm install && npm run dev -- --host" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..27435be --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +services: + backend: + build: ./backend + restart: unless-stopped + volumes: + - ./backend/data:/app/data + environment: + - DATABASE_URL=sqlite+aiosqlite:///./data/roaauto.db + - SECRET_KEY=${SECRET_KEY} + - SMSAPI_TOKEN=${SMSAPI_TOKEN:-} + - CORS_ORIGINS=https://roaauto.romfast.ro + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + + frontend: + build: ./frontend + restart: unless-stopped + ports: + - "80:80" + depends_on: + backend: + condition: service_healthy diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..b2fef1e --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.git +.gitignore +*.md +.env +.env.* diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..7dc77e8 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,12 @@ +FROM node:20-alpine AS build +WORKDIR /app +COPY package*.json . +RUN npm ci +COPY . . +RUN npm run build + +FROM nginx:alpine +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..f5c9bf8 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,18 @@ +server { + listen 80; + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api { + proxy_pass http://backend:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 60s; + } +}