Workflow: Docker Builds¶
Builds automatizados de imagens Docker para os serviços.
Visão Geral¶
O projeto usa Docker para containerização de dois serviços principais:
| Serviço | Imagem | Registry |
|---|---|---|
| Scraper API | scraper |
GCP Artifact Registry |
| Portal | portal |
GCP Artifact Registry |
flowchart LR
subgraph "Scraper API"
A[Push main] --> B[Build]
B --> F1[Artifact Registry]
F1 --> G1[Cloud Run]
end
subgraph "Portal"
D[Push main] --> E[Build]
E --> F[Artifact Registry]
F --> G[Cloud Run]
end
Build do Scraper API¶
Arquivo: scraper/.github/workflows/scraper-api-deploy.yaml
O workflow faz build da imagem Docker e deploy automático no Cloud Run em push para main.
Trigger¶
on:
push:
branches: [main]
paths:
- 'src/**'
- 'docker/**'
- 'pyproject.toml'
workflow_dispatch:
Pipeline¶
- Build da imagem Docker
- Push para GCP Artifact Registry
- Deploy no Cloud Run (
destaquesgovbr-scraper-api)
Dockerfile¶
Localizado em scraper/docker/Dockerfile.
Execução¶
# Deploy automático em push para main
# Manual
gh workflow run scraper-api-deploy.yaml -R destaquesgovbr/scraper
Build do Portal¶
Arquivo: portal/.github/workflows/deploy-production.yml
O build do portal está integrado ao workflow de deploy (ver portal-deploy.md).
Dockerfile do Portal (Multistage)¶
# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@latest --activate
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --prod --frozen-lockfile
# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
# Copiar node_modules
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Args de build
ARG TYPESENSE_HOST
ARG TYPESENSE_PORT
ARG TYPESENSE_PROTOCOL
ARG TYPESENSE_API_KEY
# Variáveis de ambiente para build
ENV TYPESENSE_HOST=$TYPESENSE_HOST
ENV TYPESENSE_PORT=$TYPESENSE_PORT
ENV TYPESENSE_PROTOCOL=$TYPESENSE_PROTOCOL
ENV TYPESENSE_API_KEY=$TYPESENSE_API_KEY
ENV NEXT_TELEMETRY_DISABLED=1
# Build Next.js standalone
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm build
# Stage 3: Production
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Criar usuário não-root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copiar artifacts de build
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
CMD ["node", "server.js"]
Otimizações¶
- Multistage: Reduz tamanho final da imagem
- Standalone output: Next.js gera servidor independente
- Non-root user: Segurança
- Layer caching: Deps em stage separado
GCP Artifact Registry¶
Autenticação¶
# Via gcloud
gcloud auth configure-docker us-east1-docker.pkg.dev
Push de imagem¶
docker push us-east1-docker.pkg.dev/PROJECT_ID/destaquesgovbr/portal:TAG
Build Local¶
Scraper API¶
cd scraper
# Build
docker build -f docker/Dockerfile -t scraper-api .
# Executar
docker run --env-file .env -p 8080:8080 scraper-api
Portal¶
cd portal
# Build (precisa das vars de ambiente)
docker build \
--build-arg TYPESENSE_HOST=localhost \
--build-arg TYPESENSE_PORT=8108 \
--build-arg TYPESENSE_PROTOCOL=http \
--build-arg TYPESENSE_API_KEY=xyz \
-t portal .
# Executar
docker run -p 3000:3000 portal
Boas Práticas¶
1. Cache de layers¶
# ❌ Ruim - invalida cache a cada mudança
COPY . .
RUN pnpm install
# ✅ Bom - aproveita cache de deps
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
2. Imagens pequenas¶
# ❌ Ruim - imagem base grande
FROM node:20
# ✅ Bom - imagem Alpine menor
FROM node:20-alpine
3. Non-root user¶
RUN adduser -D appuser
USER appuser
4. Multi-stage build¶
FROM node:20-alpine AS builder
# ... build ...
FROM node:20-alpine AS runner
COPY --from=builder /app/dist ./
Troubleshooting¶
Build falha¶
- Verificar Dockerfile syntax
- Verificar se todas as deps estão listadas
- Verificar logs do build
Push falha¶
- Verificar autenticação
- Verificar permissões no registry
- Verificar nome da imagem
Imagem muito grande¶
- Usar imagem base Alpine
- Usar multi-stage build
- Limpar cache de package managers
- Usar .dockerignore
.dockerignore¶
Scraper¶
.git
.github
.env*
*.pyc
__pycache__
.pytest_cache
.mypy_cache
tests/
docs/
Portal¶
.git
.github
node_modules
.next
.env*
*.md
tests/
Links Relacionados¶
- Pipeline Scraper - Uso da imagem
- Deploy Portal - Build + Deploy
- Setup Backend - Desenvolvimento local
- Setup Frontend - Desenvolvimento local