diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4d4f73b --- /dev/null +++ b/.env.example @@ -0,0 +1,7 @@ +BACKEND_TAG=latest +FRONTEND_TAG=latest +VITE_API_BASE=/taller/api +JENKINS_BASE_URL=http://host.docker.internal:8080 +JENKINS_JOB_NAME=TallerCiCd +JENKINS_USER= +JENKINS_TOKEN= diff --git a/Jenkinsfile.cd b/Jenkinsfile.cd index af4c8e4..d766f1b 100644 --- a/Jenkinsfile.cd +++ b/Jenkinsfile.cd @@ -2,13 +2,36 @@ pipeline { agent none options { + disableConcurrentBuilds() timestamps() } + parameters { + string( + name: 'JENKINS_BASE_URL', + defaultValue: 'https://openbokeron.org/jenkins', + description: 'Base URL del Jenkins objetivo' + ) + string( + name: 'JENKINS_JOB_NAME', + defaultValue: 'CD', + description: 'Nombre del job que se consulta en Jenkins' + ) + string( + name: 'VITE_API_BASE', + defaultValue: '/taller/api', + description: 'Base path/API para el frontend (build time)' + ) + } + environment { NODE_OPTIONS = '--max_old_space_size=2048' APP_VERSION = "1.0.${BUILD_NUMBER}" DOCKER_BUILDKIT = '1' + JENKINS_BASE_URL = "${params.JENKINS_BASE_URL}" + JENKINS_JOB_NAME = "${params.JENKINS_JOB_NAME}" + VITE_API_BASE = "${params.VITE_API_BASE}" + PYTHONDONTWRITEBYTECODE = 1 } stages { @@ -18,9 +41,6 @@ pipeline { ========================= */ stage('Backend: test (main)') { - when { - branch 'main' - } agent { docker { image 'python:3.11-slim' @@ -47,9 +67,6 @@ pipeline { ========================= */ stage('Docker: build images') { - when { - branch 'main' - } agent any steps { @@ -72,13 +89,12 @@ pipeline { --build-arg GIT_COMMIT=${COMMIT_SHORT} \ --build-arg COMMIT_AUTHOR="${COMMIT_AUTHOR}" \ --build-arg BUILD_NUMBER=${BUILD_NUMBER} \ - -t cafeteria-backend:${BUILD_NUMBER} \ - -t cafeteria-backend:latest \ + -t cafeteria-backend:${APP_VERSION} \ ./backend docker build \ - -t cafeteria-frontend:${BUILD_NUMBER} \ - -t cafeteria-frontend:latest \ + --build-arg VITE_API_BASE=${VITE_API_BASE} \ + -t cafeteria-frontend:${APP_VERSION} \ ./frontend ''' } @@ -89,14 +105,7 @@ pipeline { ========================= */ stage('Deploy (docker compose)') { - when { - branch 'main' - } agent any - environment { - JENKINS_BASE_URL = 'http://jenkins:8080' - JENKINS_JOB_NAME = 'Espetos' - } steps { withCredentials([ usernamePassword( @@ -108,17 +117,16 @@ pipeline { sh ''' set -e - echo "Deploying backend ${BUILD_NUMBER}" + echo "Deploying ${APP_VERSION}" - echo "BACKEND_TAG=${BUILD_NUMBER}" > .env - echo "FRONTEND_TAG=${BUILD_NUMBER}" >> .env - - docker-compose up -d + BACKEND_TAG=${APP_VERSION} FRONTEND_TAG=${APP_VERSION} docker compose up -d ''' } } } + + stage('Cleanup') { agent any steps { diff --git a/Jenkinsfile.ci b/Jenkinsfile.ci index fac7695..3d26508 100644 --- a/Jenkinsfile.ci +++ b/Jenkinsfile.ci @@ -41,6 +41,11 @@ pipeline { args '-u root' } } + + environment { + PYTHONDONTWRITEBYTECODE = 1 + } + steps { dir('backend') { sh ''' diff --git a/README.md b/README.md index 6b2a65c..c2ec283 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,16 @@ - Python 3.11+ y `pip` - Node 18+ y `npm` +## Configuracion de entorno (local/prod) +Variables que usa `docker-compose` y el frontend: +```bash +cp .env.example .env +``` +Notas: +- `VITE_API_BASE` por defecto apunta a `/taller/api` y el frontend proxya a la API. +- Para Jenkins local en contenedor: `JENKINS_BASE_URL=http://jenkins:8080`. Se hace necesario que back y jenkins estén en la misma red de Docker si se quiere probar en local. +- Para VPS: `JENKINS_BASE_URL=https://openbokeron.org/jenkins`. + ## Backend (FastAPI) ```bash cd backend @@ -42,6 +52,7 @@ cd frontend npm install npm run dev -- --host --port 5173 ``` +Abrir `http://localhost:5173/taller/`. Tests, lint/check: ```bash cd frontend diff --git a/backend/Dockerfile b/backend/Dockerfile index bd6c2c7..dc40fc3 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim AS builder +FROM docker.io/library/python:3.11-slim AS builder WORKDIR /build RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -9,7 +9,7 @@ COPY requirements.txt . RUN pip wheel --no-cache-dir --no-deps -r requirements.txt -w /build/wheels -FROM python:3.11-slim +FROM docker.io/library/python:3.11-slim WORKDIR /app # ---- Build args (desde Jenkins) ---- diff --git a/backend/app/settings.py b/backend/app/settings.py index 79c78a5..6c9d46d 100644 --- a/backend/app/settings.py +++ b/backend/app/settings.py @@ -24,7 +24,10 @@ class RuntimeConfig: git_commit: str = os.getenv("GIT_COMMIT", "local") build_number: str = os.getenv("BUILD_NUMBER", "-") commit_author: str = os.getenv("COMMIT_AUTHOR", "local") - jenkins_base_url: str = os.getenv("JENKINS_BASE_URL", "localhost:8080") + jenkins_base_url: str = os.getenv( + "JENKINS_BASE_URL", + "http://localhost:8080" + ).rstrip("/") jenkins_job_name: str = os.getenv("JENKINS_JOB_NAME", "") jenkins_user: str = os.getenv("JENKINS_USER", "") jenkins_token: str = os.getenv("JENKINS_TOKEN", "") diff --git a/docker-compose.yml b/docker-compose.yml index 5bc14c9..7692ea1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,14 +2,16 @@ services: backend: build: context: ./backend - image: cafeteria-backend:${BACKEND_TAG} + image: cafeteria-backend:${BACKEND_TAG:-latest} + networks: + - cafeteria ports: - "8000:8000" environment: - JENKINS_BASE_URL: ${JENKINS_BASE_URL} - JENKINS_JOB_NAME: ${JENKINS_JOB_NAME} - JENKINS_USER: ${JENKINS_USER} - JENKINS_TOKEN: ${JENKINS_TOKEN} + JENKINS_BASE_URL: ${JENKINS_BASE_URL:-http://jenkins:8080} + JENKINS_JOB_NAME: ${JENKINS_JOB_NAME:-TallerCiCd} + JENKINS_USER: ${JENKINS_USER:-} + JENKINS_TOKEN: ${JENKINS_TOKEN:-} restart: unless-stopped healthcheck: test: @@ -26,10 +28,21 @@ services: frontend: build: context: ./frontend - image: cafeteria-frontend:${FRONTEND_TAG} + args: + VITE_API_BASE: ${VITE_API_BASE:-/taller/api} + image: cafeteria-frontend:${FRONTEND_TAG:-latest} + networks: + - cafeteria ports: - - "80:80" + - "8081:8081" depends_on: backend: condition: service_healthy restart: unless-stopped + +networks: + cafeteria: + enable_ipv6: true + ipam: + config: + - subnet: 2001:db8::/64 diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 12c2eae..b453d1b 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,12 +1,14 @@ -FROM node:20-slim AS build +FROM docker.io/library/node:20-slim AS build WORKDIR /app COPY package*.json ./ +ARG VITE_API_BASE +ENV VITE_API_BASE=$VITE_API_BASE RUN npm install --no-progress COPY . . RUN npm run build -FROM nginx:1.27-alpine AS final +FROM docker.io/library/nginx:1.27-alpine AS final COPY nginx.conf /etc/nginx/conf.d/default.conf -COPY --from=build /app/dist /usr/share/nginx/html -EXPOSE 80 +COPY --from=build /app/dist /usr/share/nginx/html/taller +EXPOSE 8081 CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/nginx.conf b/frontend/nginx.conf index bb3f608..6225c35 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -1,11 +1,24 @@ server { - listen 80; + listen 8081; server_name _; root /usr/share/nginx/html; index index.html; - location / { - try_files $uri /index.html; + location = /taller { + return 301 /taller/; + } + + location /taller/api/ { + proxy_pass http://backend:8000/; + proxy_http_version 1.1; + 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; + } + + location /taller/ { + try_files $uri $uri/ /taller/index.html; } } diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 5e1298b..12f227d 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -96,8 +96,8 @@ along with this program. If not, see . if (!ENABLE_POLLING) return; - const pricesInterval = setInterval(fetchPrices, 8000); - const ciInterval = setInterval(fetchCiStatus, 10000); + const pricesInterval = setInterval(fetchPrices, 180000); + const ciInterval = setInterval(fetchCiStatus, 300000); return () => { clearInterval(pricesInterval); @@ -467,7 +467,7 @@ along with this program. If not, see .