From c429e603d70c93a905944cdfb350600907369eb5 Mon Sep 17 00:00:00 2001 From: JuruSysadmin Date: Thu, 8 Jan 2026 09:32:16 -0300 Subject: [PATCH] : --- .dockerignore | 17 +++++++++++ Dockerfile | 27 +++++++++++++++++ docker-compose.swarm.yml | 61 +++++++++++++++++++++++++++++++++++++ docker-compose.yml | 29 ++++++++++++++++++ gitea/workflows/deploy.yml | 62 ++++++++++++++++++++++++++++++++++++++ nginx.conf | 36 ++++++++++++++++++++++ 6 files changed, 232 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.swarm.yml create mode 100644 docker-compose.yml create mode 100644 gitea/workflows/deploy.yml create mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ad663cc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +node_modules +npm-debug.log +dist +.git +.gitignore +.env +.env.local +.env.*.local +*.md +!README.md +.vscode +.idea +coverage +.DS_Store +Thumbs.db +*.log +.cache diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6513530 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +# Multi-stage build para otimizar o tamanho da imagem + +# Stage 1: Build +FROM node:20-alpine AS builder + +WORKDIR /app + +COPY package*.json ./ +RUN npm install --legacy-peer-deps +COPY . . + +RUN npm run build + +# Stage 2: Production +FROM nginx:alpine + +RUN apk add --no-cache curl + +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost/ || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker-compose.swarm.yml b/docker-compose.swarm.yml new file mode 100644 index 0000000..eaff060 --- /dev/null +++ b/docker-compose.swarm.yml @@ -0,0 +1,61 @@ +version: '3.8' + +services: + vendaweb-frontend: + image: vendaweb-react:latest + deploy: + replicas: 3 + update_config: + parallelism: 1 + delay: 10s + failure_action: rollback + order: start-first + rollback_config: + parallelism: 1 + delay: 5s + restart_policy: + condition: on-failure + delay: 5s + max_attempts: 3 + window: 120s + placement: + constraints: + - node.role == worker + preferences: + - spread: node.id + resources: + limits: + cpus: '0.5' + memory: 512M + reservations: + cpus: '0.25' + memory: 256M + labels: + - "traefik.enable=true" + - "traefik.http.routers.vendaweb.rule=Host(`venda.jurunense.com`)" + - "traefik.http.routers.vendaweb.entrypoints=websecure" + - "traefik.http.routers.vendaweb.tls.certresolver=letsencrypt" + - "traefik.http.services.vendaweb.loadbalancer.server.port=80" + - "traefik.http.services.vendaweb.loadbalancer.healthcheck.path=/health" + - "traefik.http.services.vendaweb.loadbalancer.healthcheck.interval=10s" + ports: + - target: 80 + published: 3035 + protocol: tcp + mode: ingress + networks: + - vendaweb-network + - traefik-public + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost/health" ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +networks: + vendaweb-network: + driver: overlay + attachable: true + traefik-public: + external: true diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d0eded0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: '3.8' + +services: + vendaweb-frontend: + build: + context: . + dockerfile: Dockerfile + image: vendaweb-react:latest + container_name: vendaweb-frontend + ports: + - "3035:80" + environment: + - NODE_ENV=production + restart: unless-stopped + networks: + - vendaweb-network + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost/health" ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + labels: + - "com.vendaweb.description=Plataforma Smart Jurunense - Frontend" + - "com.vendaweb.version=1.0.0" + +networks: + vendaweb-network: + driver: bridge diff --git a/gitea/workflows/deploy.yml b/gitea/workflows/deploy.yml new file mode 100644 index 0000000..afbe1ac --- /dev/null +++ b/gitea/workflows/deploy.yml @@ -0,0 +1,62 @@ +name: Build and Deploy Vendaweb React + +on: + push: + branches: + - main + +jobs: + build-and-push: + name: Build Docker Image and Push to Harbor + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Harbor Registry + run: echo "${{ secrets.HARBOR_PASSWORD }}" | docker login 10.1.1.124:8082 -u ${{ secrets.HARBOR_USERNAME }} --password-stdin + + - name: Extract Branch Name + id: extract_branch + run: | + BRANCH=${GITHUB_REF#refs/heads/} + echo "branch=$BRANCH" >> $GITHUB_OUTPUT + + - name: Build and Push Docker Image + run: | + REPO="10.1.1.124:8082/library/vendaweb-react" + VERSION="v${{ gitea.run_number }}" + BRANCH="${{ steps.extract_branch.outputs.branch }}" + COMMIT_SHA="${{ gitea.sha }}" + SHORT_SHA="${COMMIT_SHA:0:7}" + + docker buildx build \ + --cache-from=$REPO:latest \ + --build-arg BUILDKIT_INLINE_CACHE=1 \ + --tag $REPO:$VERSION \ + --tag $REPO:latest \ + --tag $REPO:$BRANCH \ + --tag $REPO:$SHORT_SHA \ + --platform linux/amd64 \ + --push \ + . + + - name: Trigger Portainer Webhook + if: success() + run: | + RESPONSE=$(curl -X POST "${{ secrets.PORTAINER_WEBHOOK_FRONT }}" -w "\n%{http_code}" -s -o /dev/null) + if [ "$RESPONSE" -eq 200 ] || [ "$RESPONSE" -eq 201 ]; then + exit 0 + else + exit 1 + fi + + - name: Cleanup + if: always() + run: | + docker logout 10.1.1.124:8082 + docker system prune -f --volumes || true \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..a8089b0 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,36 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "no-referrer-when-downgrade" always; + + # Cache static assets + location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # SPA fallback - todas as rotas retornam index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Health check endpoint + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +}