Pular para conteúdo

CI/CD e deploy

TLDR: build-push.dev.yml builda e publica a imagem no GHCR a cada push em main, sem mais fazer o deploy. O deploy é declarativo, via GitOps: o Argo CD reconcilia o que está em gitops/ automaticamente, sem step de pipeline nenhum aplicando no cluster. gitops-lint.yml valida o chart em todo PR que toque gitops/.

Termo Vá pra
O pipeline de build e push da imagem Pipeline de CI/CD
Como o deploy é declarado e reconciliado pelo Argo CD Deploy via GitOps
O lint que roda em todo PR que toca gitops/ GitOps Lint
Como o site de docs/ é publicado Publicação de docs/ no GitHub Pages

Pipeline de CI/CD

Definido em .github/workflows/build-push.dev.yml (renomeado de build-deploy.dev.yml quando o deploy virou GitOps, ver Deploy via GitOps abaixo). Gatilhos: dispatch manual, ou push em main que toque src/ ou .docker/. Concurrency build-deploy-dev, uma execução por vez.

flowchart LR
    PUSH["Push em main\nou dispatch manual"] --> CHECKOUT["Checkout"]
    CHECKOUT --> BUILDX["QEMU + Buildx"]
    BUILDX --> LOGIN["Login GHCR"]
    LOGIN --> BUILD["Build da imagem\ntarget service-runtime"]
    BUILD --> PUSH_IMG["Push ghcr.io/.../management-service:development"]
    PUSH_IMG -.->|Argo CD detecta\na imagem nova| SYNC["Reconciliação automática"]

Roda em ubuntu-latest: checkout, QEMU + Docker Buildx pra build multi-arquitetura, login no GHCR com GITHUB_TOKEN, build da imagem a partir de .docker/Containerfile (target service-runtime), push pra ghcr.io/<owner>/management-service:development. Build args BUILD_TIME/GIT_COMMIT_HASH pra rastreabilidade. Cache em duas camadas, GitHub Actions (type=gha) e registry (mode=max), pra build incremental rápido.

O workflow não aplica nada no cluster, diferente de antes. Nenhum step de lint (Biome), typecheck ou teste (Vitest) roda aqui tampouco, a validação de qualidade de código hoje é só local ou via AGENTS.md, ver Qualidade de código.

Deploy via GitOps

O deploy deixou de ser um script imperativo (helm upgrade rodado por um runner de CI) e virou declaração reconciliada pelo Argo CD (conceito e o padrão app-of-apps explicados na documentação da infrastructure, aqui só o fato deste serviço). A estrutura fica em gitops/:

gitops/
├── envs/development/applications/
│   ├── api.yaml     # Application do Argo CD pra API
│   └── waha.yaml    # Application do Argo CD pro WAHA
└── apps/
    ├── api/         # chart Helm local da API (Chart.yaml + values-development.yaml)
    └── waha/        # chart Helm local do WAHA

Duas Application (não uma) porque são dois releases Helm distintos, cada um com o seu nome. Cada Chart.yaml declara o chart genérico stakater/application (versão 6.0.2) como dependência, o mesmo chart que o script antigo usava, só que agora renderizado pelo Argo CD em vez de por helm upgrade manual.

# gitops/envs/development/applications/api.yaml (trecho)
spec:
  project: ladesa-satellites
  source:
    path: gitops/apps/api
    helm:
      releaseName: ladesa-ro-api
      valueFiles: [values-development.yaml]
  destination:
    namespace: ladesa-ro-development
  syncPolicy:
    automated: { prune: true, selfHeal: true }

automated: { prune: true, selfHeal: true } significa que o Argo CD aplica qualquer mudança em gitops/apps/api/values-development.yaml sozinho, assim que o PR é mergeado em main, sem step de CI/CD nenhum disparando o deploy. Trocar configuração é editar o values-development.yaml do componente e abrir um pull request, com revisão e histórico, ver Deploy.

Os dois PersistentVolumeClaim (upload da API, sessão do WAHA) não fazem parte de nenhum release Helm e continuam fora de gitops/, deliberadamente: spec de PVC é largamente imutável, declarar um que divirja do que já existe no cluster viraria erro de sincronização. Segredo nenhum vive em gitops/, os dois componentes consomem Secret do Kubernetes por referência, produzido a partir do Infisical (o operador que sincroniza o segredo pro cluster está documentado lá, não aqui).

HTTPS é obtido via cert-manager e Ingress, pré-configurado em values-development.yaml de cada componente:

ingress:
  enabled: true
  annotations:
    cert-manager.io/cluster-issuer: ladesa-ro-issuer-production
  hosts:
    - host: dev.ladesa.com.br
      paths:
        - path: /api/v1
          pathType: ImplementationSpecific

GitOps Lint

.github/workflows/gitops-lint.yml roda em todo PR que toque gitops/, e também no push em main. Pra cada chart em gitops/apps/*: helm dependency build, helm lint contra o values-development.yaml, e helm template renderizando o manifesto final. Um step adicional falha o build se algum manifesto renderizado tiver imagem sem tag nem digest (image: repositorio sem :tag no final), a mesma prática de supply chain que a infrastructure documenta pro cluster inteiro.

Publicação de docs/ no GitHub Pages

.github/workflows/docs.yml builda com mkdocs build --strict --site-dir _site e publica via actions/upload-pages-artifact + actions/deploy-pages. Gatilho: push em main tocando docs/, mkdocs.yml ou requirements-docs.txt, mais dispatch manual. concurrency: pages garante uma publicação por vez. Se este workflow divergir do esperado, o mesmo workflow na infrastructure serve de referência pra comparar.

flowchart LR
    PUSH["Push em main\ntocando docs/"] --> BUILD["mkdocs build --strict"]
    BUILD --> ARTIFACT["upload-pages-artifact"]
    ARTIFACT --> DEPLOY["deploy-pages"]

O workflow builda e falha se mkdocs build --strict encontrar link interno ou âncora quebrada, mas isso só acontece depois do merge em main, não é um check de PR, ver Qualidade da documentação. A publicação em si depende de uma configuração que não é feita por workflow nenhum: o Pages do repositório no GitHub precisa ter a fonte de build definida como "GitHub Actions" (Settings > Pages), sem isso o job deploy falha mesmo com o build passando, ver Pendências.