From 1e59f29290f2ca5a93e1794196a4ce95614c0179 Mon Sep 17 00:00:00 2001 From: JuruSysadmin Date: Wed, 7 Jan 2026 18:43:35 -0300 Subject: [PATCH] feat: Introduce Dockerfile, Docker Compose, and Gitea workflow for API containerization and deployment. --- .dockerignore | 55 +++++++++++++++++++ Dockerfile | 93 +++++++++++++++++++++++++++++++++ docker-compose.yml | 55 +++++++++++++++++++ gitea/workflows/deploy-api.yaml | 30 +++++++++++ 4 files changed, 233 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 gitea/workflows/deploy-api.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6dddc32 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,55 @@ +# Dependências +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Build +dist/ +build/ + +# Testes +coverage/ +.nyc_output/ + +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore + +# Env +.env +.env.local +.env.*.local + +# Logs +logs/ +*.log + +# Temporários +tmp/ +temp/ +*.tmp + +# Documentação +README.md +docs/ + +# CI/CD +.github/ +.gitlab-ci.yml + +# Docker +Dockerfile +docker-compose*.yml +.dockerignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1141451 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,93 @@ +# ============================================ +# Stage 1: Dependencies +# ============================================ +FROM node:24-bookworm-slim AS dependencies + +WORKDIR /app + +COPY package*.json ./ + +RUN npm ci --only=production --ignore-scripts && \ + npm cache clean --force + +# ============================================ +# Stage 2: Builder +# ============================================ +FROM node:24-bookworm-slim AS builder + +WORKDIR /app + +COPY package*.json ./ + +RUN npm ci --ignore-scripts && \ + npm cache clean --force + +COPY . . + +RUN npm run build + +# ============================================ +# Stage 3: Oracle Instant Client +# ============================================ +FROM node:24-bookworm-slim AS oracle-client + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libaio1 \ + wget \ + unzip \ + ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /opt/oracle && \ + wget --progress=dot:giga \ + https://download.oracle.com/otn_software/linux/instantclient/2360000/instantclient-basic-linux.x64-23.6.0.24.10.zip \ + -O /tmp/instantclient.zip && \ + unzip -q /tmp/instantclient.zip -d /opt/oracle && \ + rm /tmp/instantclient.zip && \ + mv /opt/oracle/instantclient_* /opt/oracle/instantclient + +# ============================================ +# Stage 4: Production +# ============================================ +FROM node:24-bookworm-slim AS production + +LABEL maintainer="Joelson" +LABEL description="API Controle Saída Loja - NestJS + Oracle" +LABEL version="1.0" +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libaio1 \ + dumb-init && \ + rm -rf /var/lib/apt/lists/* && \ + apt-get clean + +RUN groupadd -r nodejs && \ + useradd -r -g nodejs -s /bin/bash -d /home/nodejs nodejs && \ + mkdir -p /home/nodejs && \ + chown -R nodejs:nodejs /home/nodejs + +COPY --from=oracle-client /opt/oracle/instantclient /opt/oracle/instantclient + +ENV LD_LIBRARY_PATH=/opt/oracle/instantclient +ENV ORACLE_HOME=/opt/oracle/instantclient +ENV NODE_ENV=production +ENV NPM_CONFIG_LOGLEVEL=warn + +WORKDIR /app + +COPY --from=dependencies --chown=nodejs:nodejs /app/node_modules ./node_modules + +COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist +COPY --chown=nodejs:nodejs package*.json ./ + +USER nodejs + +EXPOSE 3001 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ + CMD node -e "require('http').get('http://localhost:3001/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +CMD ["node", "dist/main.js"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..060a7b7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,55 @@ +version: '3.8' + +services: + api: + build: + context: . + dockerfile: Dockerfile + target: production + image: api-controle-saida-loja:latest + container_name: api-controle-saida-loja + restart: unless-stopped + ports: + - "3001:3001" + environment: + NODE_ENV: production + PORT: 3001 + + ORACLE_USER: ${ORACLE_USER} + ORACLE_PASSWORD: ${ORACLE_PASSWORD} + ORACLE_CONNECTION_STRING: ${ORACLE_CONNECTION_STRING} + ORACLE_LIB_DIR: /opt/oracle/instantclient + + JWT_SECRET: ${JWT_SECRET} + + env_file: + - .env + + healthcheck: + test: [ "CMD", "node", "-e", "require('http').get('http://localhost:3001/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + deploy: + resources: + limits: + cpus: '1' + memory: 512M + reservations: + cpus: '0.5' + memory: 256M + + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + networks: + - api-network + +networks: + api-network: + driver: bridge diff --git a/gitea/workflows/deploy-api.yaml b/gitea/workflows/deploy-api.yaml new file mode 100644 index 0000000..b9bdf0a --- /dev/null +++ b/gitea/workflows/deploy-api.yaml @@ -0,0 +1,30 @@ +name: Deploy NestJS API +on: [push] + +jobs: + build-and-push-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Login no Harbor + run: | + echo "${{ secrets.HARBOR_PASSWORD }}" | docker login 10.1.1.124:8082 -u ${{ secrets.HARBOR_USERNAME }} --password-stdin + + - name: Build e Push + run: | + # Usando o short SHA para uma tag mais limpa + TAG=$(echo ${{ gitea.sha }} | cut -c1-7) + IMAGE_NAME="10.1.1.124:8082/library/controle-saida-loja-api" + + docker build -t $IMAGE_NAME:$TAG . + docker tag $IMAGE_NAME:$TAG $IMAGE_NAME:latest + + docker push $IMAGE_NAME:$TAG + docker push $IMAGE_NAME:latest + + - name: Notificar Portainer via Webhook + run: | + # O segredo PORTAINER_WEBHOOK_CONTROLE_SAIDA_LOJA deve conter a URL completa gerada na Stack + curl -f -X POST "${{ secrets.PORTAINER_WEBHOOK_CONTROLE_SAIDA_LOJA }}" \ No newline at end of file