diff --git a/apps/api_v2/Dockerfile.prod b/apps/api_v2/Dockerfile.prod index 7c399f0..98f67d0 100644 --- a/apps/api_v2/Dockerfile.prod +++ b/apps/api_v2/Dockerfile.prod @@ -1,16 +1,14 @@ -FROM golang:1.22-alpine AS builder +FROM golang:1.25-alpine AS builder WORKDIR /app -ENV GO111MODULE=off \ - GOPATH=/go \ - CGO_ENABLED=0 +ENV CGO_ENABLED=0 + +COPY go.mod ./ +RUN go mod download COPY . . -# Fetch runtime dependency in GOPATH mode because this project currently uses relative imports. -RUN go get github.com/gofiber/fiber/v2 -RUN go test ./... RUN go build -o /out/api ./cmd/app FROM alpine:3.20 @@ -21,7 +19,7 @@ RUN adduser -D -u 10001 appuser COPY --from=builder /out/api /usr/local/bin/api -EXPOSE 8080 +EXPOSE 4000 USER appuser diff --git a/apps/web/Dockerfile.prod b/apps/web/Dockerfile.prod index baa42bb..2e48129 100644 --- a/apps/web/Dockerfile.prod +++ b/apps/web/Dockerfile.prod @@ -9,7 +9,7 @@ RUN npm install COPY . . -ARG VITE_API_URL=http://localhost:3000 +ARG VITE_API_URL=/api ENV VITE_API_URL=$VITE_API_URL # Build the Vite application diff --git a/apps/web/nginx.prod.conf b/apps/web/nginx.prod.conf index 22cc3f6..5e27e92 100644 --- a/apps/web/nginx.prod.conf +++ b/apps/web/nginx.prod.conf @@ -36,7 +36,7 @@ server { # Reverse proxy to internal API container. # Browser calls /api/* on the same public origin; nginx forwards inside Docker. location /api/ { - proxy_pass http://api:3000/; + proxy_pass http://apiv2:4000/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/apps/web/src/api/client.js b/apps/web/src/api/client.js index a7d0820..66c60ac 100644 --- a/apps/web/src/api/client.js +++ b/apps/web/src/api/client.js @@ -1,6 +1,6 @@ import axios from 'axios'; -const baseURL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; +const baseURL = import.meta.env.VITE_API_URL || '/api'; const client = axios.create({ baseURL, diff --git a/docker-compose.yml b/docker-compose.yml index 33e2920..7c1b2ac 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,179 +1,74 @@ # PRODUCTION ENVIRONMENT -# Use: docker-compose -f docker-compose.prod.yml up -d +# Use: docker compose -f docker-compose.yml up -d --build version: "3.9" services: - api: + apiv2: build: - context: ./apps/api + context: ./apps/api_v2 dockerfile: Dockerfile.prod - command: node dist/main.js restart: always expose: - - "${API_PORT:-3000}" - depends_on: - - postgres - - redis + - "${APIV2_PORT:-4000}" + env_file: + - .env.production environment: - - NODE_ENV=${NODE_ENV} - - PORT=${PORT} - - CORS_ORIGIN=${CORS_ORIGIN} - - POSTGRES_HOST=${POSTGRES_HOST} - - POSTGRES_PORT=${POSTGRES_PORT} - - POSTGRES_USER=${POSTGRES_USER} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - - POSTGRES_DB=${POSTGRES_DB} - - REDIS_HOST=${REDIS_HOST} - - REDIS_PORT=${REDIS_PORT} - - REDIS_PASSWORD=${REDIS_PASSWORD} - - GEMINI_API_KEY=${GEMINI_API_KEY} - networks: - - judge_net - healthcheck: - test: ["CMD-SHELL", "node -e \"require('http').get('http://localhost:3000/health', (r) => {if (r.statusCode !== 200) process.exit(1)})\""] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - deploy: - resources: - limits: - cpus: '1' - memory: 1G - - web: - build: - context: ./apps/web - dockerfile: Dockerfile.prod - args: - - VITE_API_URL=${VITE_API_URL} - restart: always - ports: - - "${WEB_PORT:-5173}:5173" + - APIV2_PORT=${APIV2_PORT:-4000} + - RABBITMQ_URL=${RABBITMQ_URL:-amqp://guest:guest@rabbitmq:5672/} + depends_on: + rabbitmq: + condition: service_healthy networks: - judge_net - healthcheck: - test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:5173/health"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 20s - deploy: - resources: - limits: - cpus: '0.5' - memory: 512M - postgres: - image: postgres:16-alpine + rabbitmq: + image: rabbitmq:3.13-management restart: always - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} - volumes: - - pgdata_prod:/var/lib/postgresql/data - - ./apps/api/migrations:/docker-entrypoint-initdb.d:ro - networks: - - judge_net + expose: + - "5672" + - "15672" healthcheck: - test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB || exit 1"] - interval: 10s + test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] + interval: 5s timeout: 5s - retries: 15 - start_period: 40s - deploy: - resources: - limits: - cpus: '1' - memory: 1G - - redis: - image: redis:7-alpine - container_name: juez_redis_prod - restart: always - volumes: - - redis_data:/data + retries: 20 networks: - judge_net - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 15 - start_period: 30s - - runner-python: - profiles: ["judge"] - build: - context: ./apps/api/src/runners/python - image: juez_runner_python:prod - restart: "no" - runner-node: - profiles: ["judge"] + worker-python: build: - context: ./apps/api/src/runners/node - image: juez_runner_node:prod - restart: "no" - - runner-cpp: - profiles: ["judge"] - build: - context: ./apps/api/src/runners/cpp - image: juez_runner_cpp:prod - restart: "no" - - runner-java: - profiles: ["judge"] - build: - context: ./apps/api/src/runners/java - image: juez_runner_java:prod - restart: "no" - - worker: - profiles: ["judge"] - build: - context: ./apps/api - dockerfile: Dockerfile.worker - args: - - NODE_ENV=production - command: npm run worker + context: ./apps/workers/python + dockerfile: Dockerfile + working_dir: /app + command: python main.py restart: always + env_file: + - .env.production + environment: + - API_BASE_URL=http://apiv2:${APIV2_PORT:-4000} + - RABBITMQ_URL=${RABBITMQ_URL:-amqp://guest:guest@rabbitmq:5672/} + - QUEUE_NAME=${PYTHON_QUEUE:-python.queue} volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - submissions_data:/usr/src/app/data + - /var/run/docker.sock:/var/run/docker.sock depends_on: - - runner-python - - runner-node - - runner-cpp - - runner-java - - postgres - - redis - environment: - - NODE_ENV=${NODE_ENV} - - POSTGRES_HOST=${POSTGRES_HOST} - - POSTGRES_PORT=${POSTGRES_PORT} - - POSTGRES_USER=${POSTGRES_USER} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - - POSTGRES_DB=${POSTGRES_DB} - - REDIS_HOST=${REDIS_HOST} - - REDIS_PORT=${REDIS_PORT} - - REDIS_PASSWORD=${REDIS_PASSWORD} - - HOST_SUBMISSIONS_DIR=${HOST_SUBMISSIONS_DIR} + apiv2: + condition: service_started + rabbitmq: + condition: service_healthy networks: - judge_net - deploy: - resources: - limits: - cpus: '2' - memory: 2G - -volumes: - pgdata_prod: - redis_data: - submissions_data: - + web: + build: + context: ./apps/web + dockerfile: Dockerfile.prod + ports: + - "${WEB_PORT:-5173}:5173" + env_file: + - .env.production + networks: + - judge_net + depends_on: + - apiv2 networks: judge_net: driver: bridge diff --git a/example.env b/example.env new file mode 100644 index 0000000..06c4e9c --- /dev/null +++ b/example.env @@ -0,0 +1,59 @@ +#------------------------| Frontend |----------------------------# + +# Vite Configuration +VITE_API_URL=http://localhost:4000 +WEB_PORT=5137 + +# Node Environment +NODE_ENV=development/production + + +#--------------------------| API V2 |------------------------------# + +# API Configuration +APIV2_PORT=4000 +APIV2_BASE_URL=http://apiv2:4000 + +# Roble Configuration - Dev +ROBLE_PROJECT= +ROBLE_BASE_URL=https://roble-api.openlab.uninorte.edu.co + +# Test user configuration +INTERNAL_USER_EMAIL= +INTERNAL_USER_PASSWORD= + +# Worker Environment Variables +WORKER_KEY= +PYTHON_QUEUE=python.queue +JAVA_QUEUE=java.queue +CPP_QUEUE=cpp.queue + +# RabbitMQ Configuration +RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/ + +# AI API keys +GEMINI_API_KEY= + + +#------------------------------------------------------------------# +# DEPRECATED # +#------------------------------------------------------------------# + +#--------------------------| API V1 |------------------------------# +# PostgreSQL Configuration +POSTGRES_USER=juez_prod +POSTGRES_PASSWORD= +POSTGRES_DB=juez_db_prod +POSTGRES_HOST=postgres +POSTGRES_PORT=5432 + +# Redis Configuration (optional, leave empty for no password) +REDIS_PASSWORD= +REDIS_HOST=redis +REDIS_PORT=6379 + +# Worker Configuration +HOST_SUBMISSIONS_DIR=/data/submissions + +# API Configuration +API_PORT=4000 \ No newline at end of file