Um pipeline de CI/CD de qualidade não é uma sequência de scripts colados — é um produto de engenharia com suas próprias preocupações de confiabilidade, manutenibilidade e experiência do usuário. O desenvolvedor que faz um push é o usuário desse produto. O feedback que recebe — rápido ou lento, claro ou confuso, confiável ou instável — determina diretamente a velocidade e a segurança com que o time entrega software.
O pipeline completo do capstone integra todas as práticas abordadas na série: testes automatizados com cobertura mínima, scanning de segurança em múltiplas camadas, build de imagens otimizado com cache, deploy via GitOps com ArgoCD, verificação pós-deploy com rollback automático e notificações contextuais. Para um monorepo com cinco serviços, o pipeline detecta inteligentemente quais serviços foram modificados e executa apenas o necessário — evitando o custo de buildar e deployar tudo a cada commit.
Detecção de Mudanças no Monorepo
O primeiro desafio de um monorepo é determinar quais serviços foram afetados por um conjunto de commits. A solução usa git diff para comparar os arquivos modificados com os prefixos de cada serviço:
# .github/workflows/detectar-mudancas.yml
# Workflow reutilizável — detecta quais serviços foram modificados
name: Detectar Mudanças
on:
workflow_call:
outputs:
catalog:
value: ${{ jobs.detectar.outputs.catalog }}
user:
value: ${{ jobs.detectar.outputs.user }}
order:
value: ${{ jobs.detectar.outputs.order }}
notification:
value: ${{ jobs.detectar.outputs.notification }}
api-gateway:
value: ${{ jobs.detectar.outputs.api-gateway }}
infraestrutura:
value: ${{ jobs.detectar.outputs.infraestrutura }}
jobs:
detectar:
runs-on: ubuntu-latest
outputs:
catalog: ${{ steps.diff.outputs.catalog }}
user: ${{ steps.diff.outputs.user }}
order: ${{ steps.diff.outputs.order }}
notification: ${{ steps.diff.outputs.notification }}
api-gateway: ${{ steps.diff.outputs.api-gateway }}
infraestrutura: ${{ steps.diff.outputs.infraestrutura }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detecta serviços modificados
id: diff
run: |
# Compara com o commit anterior em push, ou com a base em PR
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE="${{ github.event.pull_request.base.sha }}"
else
BASE="${{ github.event.before }}"
# Primeiro push — compara com HEAD~1
if [ "$BASE" = "0000000000000000000000000000000000000000" ]; then
BASE="HEAD~1"
fi
fi
ARQUIVOS_MODIFICADOS=$(git diff --name-only "$BASE" HEAD)
echo "Arquivos modificados:"
echo "$ARQUIVOS_MODIFICADOS"
# Verifica cada serviço
for SERVICO in catalog user order notification api-gateway; do
if echo "$ARQUIVOS_MODIFICADOS" | grep -q "^services/${SERVICO}-service/\|^packages/"; then
echo "${SERVICO}=true" >> $GITHUB_OUTPUT
echo "✓ ${SERVICO}-service: modificado"
else
echo "${SERVICO}=false" >> $GITHUB_OUTPUT
echo " ${SERVICO}-service: sem mudanças"
fi
done
# Verifica infraestrutura
if echo "$ARQUIVOS_MODIFICADOS" | grep -q "^infrastructure/"; then
echo "infraestrutura=true" >> $GITHUB_OUTPUT
echo "✓ infraestrutura: modificada"
else
echo "infraestrutura=false" >> $GITHUB_OUTPUT
fi
Pipeline Principal de CI
# .github/workflows/ci.yml
name: CI — Integração Contínua
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true # Cancela runs anteriores do mesmo branch
jobs:
# ── Detecção de mudanças ──────────────────────────────────────────
detectar:
uses: ./.github/workflows/detectar-mudancas.yml
# ── Segurança: secrets e SAST ─────────────────────────────────────
seguranca-base:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detecta segredos com Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Análise estática com Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >
p/nodejs
p/secrets
p/owasp-top-ten
.semgrep/regras-customizadas.yml
- name: Verifica IaC com Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: infrastructure/
framework: terraform,kubernetes,dockerfile
soft_fail: false
# ── CI de cada serviço (executado em paralelo) ────────────────────
ci-catalog:
needs: [detectar, seguranca-base]
if: needs.detectar.outputs.catalog == 'true'
uses: ./.github/workflows/ci-servico.yml
with:
servico: catalog
porta: 3001
secrets: inherit
ci-user:
needs: [detectar, seguranca-base]
if: needs.detectar.outputs.user == 'true'
uses: ./.github/workflows/ci-servico.yml
with:
servico: user
porta: 3002
secrets: inherit
ci-order:
needs: [detectar, seguranca-base]
if: needs.detectar.outputs.order == 'true'
uses: ./.github/workflows/ci-servico.yml
with:
servico: order
porta: 3003
secrets: inherit
ci-notification:
needs: [detectar, seguranca-base]
if: needs.detectar.outputs.notification == 'true'
uses: ./.github/workflows/ci-servico.yml
with:
servico: notification
porta: 3004
secrets: inherit
ci-api-gateway:
needs: [detectar, seguranca-base]
if: needs.detectar.outputs.api-gateway == 'true'
uses: ./.github/workflows/ci-servico.yml
with:
servico: api-gateway
porta: 3000
secrets: inherit
# ── Gate de qualidade — só prossegue se tudo passou ───────────────
ci-concluido:
needs: [ci-catalog, ci-user, ci-order, ci-notification, ci-api-gateway]
if: always()
runs-on: ubuntu-latest
steps:
- name: Verifica resultado de todos os CIs
run: |
RESULTADOS=(
"${{ needs.ci-catalog.result }}"
"${{ needs.ci-user.result }}"
"${{ needs.ci-order.result }}"
"${{ needs.ci-notification.result }}"
"${{ needs.ci-api-gateway.result }}"
)
for RESULTADO in "${RESULTADOS[@]}"; do
if [ "$RESULTADO" = "failure" ]; then
echo "::error::CI falhou — deploy bloqueado"
exit 1
fi
done
echo "✅ Todos os CIs passaram ou foram pulados"
Workflow Reutilizável de CI por Serviço
# .github/workflows/ci-servico.yml
name: CI Serviço (Reutilizável)
on:
workflow_call:
inputs:
servico:
required: true
type: string
porta:
required: true
type: number
jobs:
testar:
runs-on: ubuntu-latest
name: Testar ${{ inputs.servico }}-service
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: test_db
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_password
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 3s
--health-retries 10
ports:
- 5432:5432
redis:
image: redis:7-alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 3s
--health-retries 10
ports:
- 6379:6379
defaults:
run:
working-directory: services/${{ inputs.servico }}-service
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: |
services/${{ inputs.servico }}-service/package-lock.json
packages/core/package-lock.json
- name: Instala dependências do core
run: npm ci
working-directory: packages/core
- name: Instala dependências do serviço
run: npm ci
- name: Verifica lint
run: npm run lint
- name: Executa testes unitários
run: npm run test:unit -- --coverage
- name: Executa testes de integração
run: npm run test:integration
env:
DATABASE_URL: postgresql://test_user:test_password@localhost:5432/test_db
REDIS_URL: redis://localhost:6379
NODE_ENV: test
- name: Verifica cobertura mínima
run: |
COBERTURA=$(cat coverage/coverage-summary.json \
| jq '.total.lines.pct')
echo "Cobertura: ${COBERTURA}%"
if (( $(echo "$COBERTURA < 80" | bc -l) )); then
echo "::error::Cobertura abaixo do mínimo: ${COBERTURA}% (mínimo: 80%)"
exit 1
fi
- name: Upload cobertura para Codecov
uses: codecov/codecov-action@v4
with:
flags: ${{ inputs.servico }}
token: ${{ secrets.CODECOV_TOKEN }}
construir-imagem:
runs-on: ubuntu-latest
needs: testar
name: Construir imagem ${{ inputs.servico }}-service
outputs:
imagem: ${{ steps.build.outputs.imagem }}
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/cache@v4
with:
path: /tmp/.buildx-cache-${{ inputs.servico }}
key: ${{ runner.os }}-buildx-${{ inputs.servico }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-${{ inputs.servico }}-
- name: Extrai metadados da imagem
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/${{ inputs.servico }}-service
tags: |
type=sha,prefix=sha-,format=short
type=ref,event=branch
type=semver,pattern={{version}}
- name: Constrói e publica imagem
id: build
uses: docker/build-push-action@v5
with:
context: .
file: services/${{ inputs.servico }}-service/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache-${{ inputs.servico }}
cache-to: type=local,dest=/tmp/.buildx-cache-${{ inputs.servico }}-new,mode=max
provenance: true
sbom: true # Gera Software Bill of Materials
- name: Rotaciona cache do Buildx
run: |
rm -rf /tmp/.buildx-cache-${{ inputs.servico }}
mv /tmp/.buildx-cache-${{ inputs.servico }}-new \
/tmp/.buildx-cache-${{ inputs.servico }}
- name: Escaneia imagem com Trivy
if: github.event_name != 'pull_request'
uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/${{ github.repository_owner }}/${{ inputs.servico }}-service:sha-${{ github.sha }}
format: sarif
output: trivy-${{ inputs.servico }}.sarif
severity: CRITICAL,HIGH
exit-code: '1'
ignore-unfixed: true
- name: Upload resultados Trivy
if: always() && github.event_name != 'pull_request'
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-${{ inputs.servico }}.sarif
- name: Exporta outputs
id: exportar
run: |
IMAGEM="ghcr.io/${{ github.repository_owner }}/${{ inputs.servico }}-service:sha-${{ github.sha }}"
echo "imagem=${IMAGEM}" >> $GITHUB_OUTPUT
Pipeline de Deploy via GitOps
# .github/workflows/deploy.yml
name: Deploy — Produção
on:
push:
branches: [main]
jobs:
# ── Reutiliza o CI completo ────────────────────────────────────────
detectar:
uses: ./.github/workflows/detectar-mudancas.yml
ci:
needs: detectar
uses: ./.github/workflows/ci.yml
secrets: inherit
# ── Deploy em staging primeiro ────────────────────────────────────
deploy-staging:
needs: ci
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.loja.empresa.com
outputs:
sha-curto: ${{ steps.vars.outputs.sha-curto }}
steps:
- uses: actions/checkout@v4
- name: Exporta variáveis
id: vars
run: echo "sha-curto=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Clona repositório GitOps
uses: actions/checkout@v4
with:
repository: empresa/gitops-loja
token: ${{ secrets.GITOPS_TOKEN }}
path: gitops
- name: Atualiza imagens no staging
run: |
cd gitops
SHA="${{ steps.vars.outputs.sha-curto }}"
# Atualiza a tag de cada serviço modificado
for SERVICO in catalog user order notification api-gateway; do
MODIFICADO="needs.detectar.outputs.${SERVICO}"
if [ "${!MODIFICADO}" = "true" ] || true; then
cd workloads/${SERVICO}-service/staging
kustomize edit set image \
ghcr.io/empresa/${SERVICO}-service:sha-${SHA}
cd ../../..
fi
done
git config user.email "pipeline@empresa.com"
git config user.name "Pipeline CI/CD"
git add .
git diff --staged --quiet || git commit -m \
"chore(staging): deploy sha-${SHA}
Serviços atualizados pelo pipeline.
Repositório: ${{ github.repository }}
Run: ${{ github.run_id }}"
git push
- name: Aguarda sincronização do ArgoCD em staging
run: |
# Instala argocd CLI
curl -sSL -o argocd \
https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd
sudo mv argocd /usr/local/bin/
argocd login ${{ vars.ARGOCD_SERVER }} \
--auth-token ${{ secrets.ARGOCD_TOKEN }} \
--grpc-web
# Aguarda cada aplicação sincronizar e ficar saudável
for SERVICO in catalog user order notification api-gateway; do
argocd app wait loja-staging-${SERVICO} \
--sync \
--health \
--timeout 300
done
- name: Executa smoke tests em staging
run: |
BASE_URL="https://staging.loja.empresa.com"
echo "Verificando saúde dos serviços em staging..."
verificar() {
local URL="$1"
local DESCRICAO="$2"
local STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
--max-time 10 "$URL")
if [ "$STATUS" = "200" ]; then
echo " ✓ $DESCRICAO ($STATUS)"
else
echo " ✗ $DESCRICAO ($STATUS)"
return 1
fi
}
verificar "${BASE_URL}/api/health" "API Gateway health"
verificar "${BASE_URL}/api/v1/produtos" "Catálogo — listar produtos"
verificar "${BASE_URL}/api/v1/health/live" "Order service liveness"
echo "✅ Smoke tests em staging passaram"
# ── Deploy em produção com aprovação ─────────────────────────────
deploy-producao:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://loja.empresa.com
steps:
- uses: actions/checkout@v4
- name: Clona repositório GitOps
uses: actions/checkout@v4
with:
repository: empresa/gitops-loja
token: ${{ secrets.GITOPS_TOKEN }}
path: gitops
- name: Atualiza imagens em produção
run: |
cd gitops
SHA="${{ needs.deploy-staging.outputs.sha-curto }}"
for SERVICO in catalog user order notification api-gateway; do
cd workloads/${SERVICO}-service/producao
kustomize edit set image \
ghcr.io/empresa/${SERVICO}-service:sha-${SHA}
cd ../../..
done
git config user.email "pipeline@empresa.com"
git config user.name "Pipeline CI/CD"
git add .
git diff --staged --quiet || git commit -m \
"chore(producao): deploy sha-${SHA}
Deploy promovido do staging após aprovação.
Aprovador: ${{ github.actor }}
Run: ${{ github.run_id }}"
git push
- name: Aguarda sincronização do ArgoCD em produção
run: |
argocd login ${{ vars.ARGOCD_SERVER }} \
--auth-token ${{ secrets.ARGOCD_TOKEN }} \
--grpc-web
for SERVICO in catalog user order notification api-gateway; do
echo "Aguardando loja-producao-${SERVICO}..."
argocd app wait loja-producao-${SERVICO} \
--sync \
--health \
--timeout 600
done
- name: Verifica métricas pós-deploy
id: verificar-metricas
run: |
# Aguarda 2 minutos para métricas estabilizarem
echo "Aguardando estabilização das métricas..."
sleep 120
PROMETHEUS="${{ vars.PROMETHEUS_URL }}"
# Verifica taxa de erros (deve ser < 1%)
TAXA_ERROS=$(curl -s "${PROMETHEUS}/api/v1/query" \
--data-urlencode 'query=
sum(rate(http_requests_total{
status=~"5..",
namespace="producao"
}[2m]))
/
sum(rate(http_requests_total{
namespace="producao"
}[2m])) * 100
' | jq '.data.result[0].value[1] | tonumber')
echo "Taxa de erros: ${TAXA_ERROS}%"
# Verifica latência p99 (deve ser < 1s)
LATENCIA_P99=$(curl -s "${PROMETHEUS}/api/v1/query" \
--data-urlencode 'query=
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{
namespace="producao"
}[2m])) by (le)
)
' | jq '.data.result[0].value[1] | tonumber')
echo "Latência p99: ${LATENCIA_P99}s"
# Falha se métricas estiverem fora do threshold
if (( $(echo "$TAXA_ERROS > 1" | bc -l) )); then
echo "::error::Taxa de erros elevada: ${TAXA_ERROS}%"
echo "rollback=true" >> $GITHUB_OUTPUT
exit 1
fi
if (( $(echo "$LATENCIA_P99 > 1" | bc -l) )); then
echo "::error::Latência p99 elevada: ${LATENCIA_P99}s"
echo "rollback=true" >> $GITHUB_OUTPUT
exit 1
fi
echo "✅ Métricas pós-deploy dentro dos thresholds"
echo "rollback=false" >> $GITHUB_OUTPUT
- name: Rollback automático em caso de falha
if: failure() && steps.verificar-metricas.outputs.rollback == 'true'
run: |
echo "⚠️ Iniciando rollback automático..."
argocd login ${{ vars.ARGOCD_SERVER }} \
--auth-token ${{ secrets.ARGOCD_TOKEN }} \
--grpc-web
for SERVICO in catalog user order notification api-gateway; do
argocd app rollback loja-producao-${SERVICO} --hard-refresh || true
done
echo "Rollback concluído"
- name: Notifica resultado do deploy
if: always()
uses: slackapi/slack-github-action@v1.26.0
with:
channel-id: ${{ vars.SLACK_DEPLOYS_CHANNEL }}
payload: |
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "${{ job.status == 'success' && '✅ Deploy em Produção — Sucesso' || '❌ Deploy em Produção — Falha' }}"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*SHA:*\n`${{ needs.deploy-staging.outputs.sha-curto }}`"
},
{
"type": "mrkdwn",
"text": "*Deployado por:*\n${{ github.actor }}"
},
{
"type": "mrkdwn",
"text": "*Branch:*\n${{ github.ref_name }}"
},
{
"type": "mrkdwn",
"text": "*Status:*\n${{ job.status }}"
}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": { "type": "plain_text", "text": "Ver Pipeline" },
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
},
{
"type": "button",
"text": { "type": "plain_text", "text": "Grafana" },
"url": "${{ vars.GRAFANA_URL }}/d/loja-overview"
}
]
}
]
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
Pipeline de Infraestrutura
# .github/workflows/deploy-infraestrutura.yml
name: Deploy — Infraestrutura
on:
push:
branches: [main]
paths:
- 'infrastructure/terraform/**'
pull_request:
branches: [main]
paths:
- 'infrastructure/terraform/**'
workflow_dispatch:
inputs:
ambiente:
description: 'Ambiente alvo'
required: true
type: choice
options: [staging, production]
acao:
description: 'Ação Terraform'
required: true
type: choice
options: [plan, apply]
default: plan
jobs:
validar:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "~1.7"
- name: Terraform Format Check
run: terraform fmt -check -recursive infrastructure/
- name: Terraform Validate — Staging
run: |
cd infrastructure/terraform/environments/staging
terraform init -backend=false
terraform validate
- name: Terraform Validate — Production
run: |
cd infrastructure/terraform/environments/production
terraform init -backend=false
terraform validate
- name: Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: infrastructure/terraform/
framework: terraform
plan-staging:
needs: validar
runs-on: ubuntu-latest
environment: staging
if: github.event_name == 'pull_request' || inputs.ambiente == 'staging'
permissions:
contents: read
id-token: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_TERRAFORM_ROLE_ARN }}
aws-region: us-east-1
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "~1.7"
- name: Terraform Init
run: |
cd infrastructure/terraform/environments/staging
terraform init \
-backend-config="bucket=${{ vars.TF_STATE_BUCKET }}" \
-backend-config="key=staging/terraform.tfstate" \
-backend-config="region=us-east-1" \
-backend-config="dynamodb_table=${{ vars.TF_LOCK_TABLE }}"
- name: Terraform Plan
id: plan
run: |
cd infrastructure/terraform/environments/staging
terraform plan \
-var="environment=staging" \
-no-color \
-out=tfplan \
2>&1 | tee plan-output.txt
# Extrai sumário do plano
echo "SUMARIO<<EOF" >> $GITHUB_ENV
grep -E "^Plan:|^No changes" plan-output.txt || echo "Plano gerado"
echo "EOF" >> $GITHUB_ENV
- name: Comenta plano no PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const planOutput = fs.readFileSync(
'infrastructure/terraform/environments/staging/plan-output.txt',
'utf8'
);
// Trunca se muito longo
const truncated = planOutput.length > 65000
? planOutput.substring(0, 65000) + '\n... (truncado)'
: planOutput;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Terraform Plan — Staging\n\`\`\`\n${truncated}\n\`\`\``
});
apply-producao:
needs: validar
runs-on: ubuntu-latest
environment: production
if: |
github.event_name == 'push' && github.ref == 'refs/heads/main' ||
(inputs.ambiente == 'production' && inputs.acao == 'apply')
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_TERRAFORM_ROLE_ARN }}
aws-region: us-east-1
- uses: hashicorp/setup-terraform@v3
- name: Terraform Init
run: |
cd infrastructure/terraform/environments/production
terraform init \
-backend-config="bucket=${{ vars.TF_STATE_BUCKET }}" \
-backend-config="key=production/terraform.tfstate" \
-backend-config="region=us-east-1"
- name: Terraform Plan
run: |
cd infrastructure/terraform/environments/production
terraform plan \
-var="environment=production" \
-out=tfplan
- name: Terraform Apply
run: |
cd infrastructure/terraform/environments/production
terraform apply -auto-approve tfplan
Configuração do ArgoCD para o Capstone
# infrastructure/kubernetes/platform/argocd/apps-loja.yaml
# App of Apps — ArgoCD gerencia todas as aplicações da loja
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: loja-apps
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/empresa/gitops-loja
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
---
# apps/loja-producao-order.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: loja-producao-order
namespace: argocd
spec:
project: loja-producao
source:
repoURL: https://github.com/empresa/gitops-loja
targetRevision: main
path: workloads/order-service/producao
destination:
server: https://kubernetes.default.svc
namespace: producao
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=false
- PrunePropagationPolicy=foreground
retry:
limit: 3
backoff:
duration: 5s
factor: 2
maxDuration: 3m
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas # Gerenciado pelo HPA
O Que Vem a Seguir
O próximo e último artigo do capstone — e da série — implementa as operações em produção: dashboards de observabilidade calibrados para a plataforma de e-commerce, alertas com runbooks detalhados, um experimento de Chaos Engineering executado no sistema completo e uma retrospectiva sobre a jornada de doze meses desta série.
Referências para Aprofundamento
GitHub Actions - GitHub Actions Documentation — docs.github.com — Documentação completa do GitHub Actions com referência de sintaxe de workflows, contexts, expressions e os runners disponíveis. - Reusable Workflows — docs.github.com — Guia completo de workflows reutilizáveis no GitHub Actions com exemplos de passagem de inputs, outputs e secrets entre workflows.
GitOps e ArgoCD - ArgoCD App of Apps Pattern — argo-cd.readthedocs.io — Documentação do padrão App of Apps no ArgoCD para gerenciamento de múltiplas aplicações a partir de um único repositório GitOps. - GitOps with ArgoCD and Kustomize — codefresh.io — Guia prático de GitOps combinando ArgoCD e Kustomize para gerenciamento de múltiplos ambientes com overlays.