Boas Práticas de Flux CD: GitOps Alternativo com Kustomize e Helm Controller para Times Ágeis Já leu

O que é Flux CD e por que GitOps? Flux CD é um operador Kubernetes que implementa o padrão GitOps de forma declarativa. Diferente de ferramentas como ArgoCD que centralizam a lógica em um painel, Flux distribui a responsabilidade através de controllers específicos rodando diretamente no seu cluster. A ideia central é simples: seu repositório Git é a fonte de verdade, e o cluster converge automaticamente para o estado desejado descrito lá. O padrão GitOps resolve um problema fundamental em DevOps: rastreabilidade completa de mudanças infraestruturais. Toda alteração passa por Git, traz histórico, permite rollback e code review. Flux, ao contrário de soluções monolíticas, adota uma arquitetura modular onde cada controller tem responsabilidade bem definida. Você instala apenas o que precisa, reduzindo overhead e complexidade. Arquitetura do Flux: Componentes Principais Source Controller e seus tipos de fonte O Source Controller é responsável por monitorar repositórios e buscar manifests. Ele não aplica nada — apenas sincroniza a fonte desejada. Flux suporta

O que é Flux CD e por que GitOps?

Flux CD é um operador Kubernetes que implementa o padrão GitOps de forma declarativa. Diferente de ferramentas como ArgoCD que centralizam a lógica em um painel, Flux distribui a responsabilidade através de controllers específicos rodando diretamente no seu cluster. A ideia central é simples: seu repositório Git é a fonte de verdade, e o cluster converge automaticamente para o estado desejado descrito lá.

O padrão GitOps resolve um problema fundamental em DevOps: rastreabilidade completa de mudanças infraestruturais. Toda alteração passa por Git, traz histórico, permite rollback e code review. Flux, ao contrário de soluções monolíticas, adota uma arquitetura modular onde cada controller tem responsabilidade bem definida. Você instala apenas o que precisa, reduzindo overhead e complexidade.

Arquitetura do Flux: Componentes Principais

Source Controller e seus tipos de fonte

O Source Controller é responsável por monitorar repositórios e buscar manifests. Ele não aplica nada — apenas sincroniza a fonte desejada. Flux suporta múltiplas fontes: repositórios Git, buckets S3, registros Helm e OCI. Esse design permite usar a mesma ferramenta para cenários diversos sem criar abstrações artificiais.

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: app-repo
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/seu-usuario/seu-repo.git
  ref:
    branch: main
  secretRef:
    name: git-credentials

Este manifesto instrui o Source Controller a verificar o repositório a cada minuto. Se houver mudanças, ele as sincroniza localmente. Note que isso é puramente observação — nenhum recurso é criado ainda.

Kustomize Controller: composição declarativa

O Kustomize Controller aplica manifests gerados pelo Kustomize, uma ferramenta nativa do Kubernetes para template e patch de YAMLs. Diferente de Helm (que usa templates Go), Kustomize trabalha diretamente com manifests, o que mantém o resultado sempre válido no Kubernetes.

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: app-deployment
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: app-repo
  path: ./app/overlays/production
  prune: true
  wait: true

O path aponta para um diretório com kustomization.yaml. O campo prune: true significa que recursos deletados do Git também serão removidos do cluster. wait: true faz Flux aguardar deployments ficarem prontos antes de considerar a sincronização bem-sucedida.

Helm Controller: gerenciamento de charts

O Helm Controller gerencia releases Helm direto no cluster. Você não executa helm install manualmente — o controller observa e aplica. Isso funciona particularmente bem para dependências externas (databases, ingress controllers, monitoring stacks).

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
  name: bitnami
  namespace: flux-system
spec:
  interval: 1h
  url: https://charts.bitnami.com/bitnami

---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: postgresql
  namespace: databases
spec:
  interval: 30m
  chart:
    spec:
      chart: postgresql
      version: 13.1.x
      sourceRef:
        kind: HelmRepository
        name: bitnami
        namespace: flux-system
  values:
    auth:
      username: appuser
      password: secure-password
    persistence:
      size: 10Gi

Aqui temos duas fontes: uma apontando para o repositório Bitnami e outra descrevendo a release. O controller sincroniza automaticamente se o chart tiver novas versões compatíveis com 13.1.x.

Combinando Kustomize e Helm em uma estratégia real

Estrutura de projeto recomendada

Uma abordagem sólida separa concerns em diretórios. Helm para componentes reutilizáveis, Kustomize para customização ambiental. Vamos modelar um projeto real:

seu-repo/
├── clusters/
│   ├── staging/
│   │   └── flux-system.yaml
│   └── production/
│       └── flux-system.yaml
├── infrastructure/
│   ├── helm-repos.yaml
│   ├── ingress-controller/
│   │   └── helmrelease.yaml
│   └── cert-manager/
│       └── helmrelease.yaml
└── apps/
    ├── api-service/
    │   ├── kustomization.yaml
    │   ├── base/
    │   │   ├── kustomization.yaml
    │   │   ├── deployment.yaml
    │   │   └── service.yaml
    │   └── overlays/
    │       ├── staging/
    │       │   └── kustomization.yaml
    │       └── production/
    │           └── kustomization.yaml

Exemplo prático: aplicação com dependências Helm

Suponha uma aplicação que depende de PostgreSQL (Helm) e precisa ser deployada em ambientes diferentes. Começamos com a fonte e repositório Helm:

# clusters/production/flux-system.yaml
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: main-repo
  namespace: flux-system
spec:
  interval: 5m
  url: https://github.com/seu-usuario/seu-app.git
  ref:
    branch: main

---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
  name: bitnami
  namespace: flux-system
spec:
  interval: 1h
  url: https://charts.bitnami.com/bitnami

Agora a dependência externa via Helm:

# infrastructure/database/helmrelease.yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: db
  namespace: data-layer
spec:
  interval: 30m
  chart:
    spec:
      chart: postgresql
      version: 13.1.5
      sourceRef:
        kind: HelmRepository
        name: bitnami
        namespace: flux-system
  values:
    auth:
      username: appuser
      password: "${DB_PASSWORD}"
      database: myapp
    persistence:
      enabled: true
      size: 20Gi
    replica:
      replicaCount: 2
  postRenderers:
    - kustomize:
        patchesStrategicMerge:
          - apiVersion: v1
            kind: Service
            metadata:
              name: db-postgresql-primary
            spec:
              type: ClusterIP

E a aplicação em Kustomize:

# apps/api-service/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - deployment.yaml
  - service.yaml

commonLabels:
  app: api-service
  managed-by: flux

replicas:
  - name: api-service
    count: 1
# apps/api-service/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-service
spec:
  selector:
    matchLabels:
      app: api-service
  template:
    metadata:
      labels:
        app: api-service
    spec:
      containers:
        - name: api
          image: seu-registry/api-service:latest
          ports:
            - containerPort: 8080
          env:
            - name: DB_HOST
              value: "db-postgresql-primary.data-layer.svc.cluster.local"
            - name: DB_USER
              value: "appuser"
            - name: DB_NAME
              value: "myapp"

Para production, você aumenta replicas e adiciona configurações:

# apps/api-service/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
  - ../../base

replicas:
  - name: api-service
    count: 3

patchesStrategicMerge:
  - deployment.yaml

resources:
  - hpa.yaml
# apps/api-service/overlays/production/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-service
spec:
  template:
    spec:
      containers:
        - name: api
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: 1000m
              memory: 1Gi

Finalmente, a Kustomization que orquestra tudo:

# clusters/production/app.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: apps
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: main-repo
  path: ./apps/api-service/overlays/production
  prune: true
  wait: true
  dependsOn:
    - name: infrastructure

Note o campo dependsOn: Flux aplica infraestrutura primeiro, depois aplicações. Isso previne deployments falharem por dependências indisponíveis.

Fluxo de trabalho GitOps com Flux

Sincronização e reconciliação

Quando você faz push em Git, o Source Controller detecta mudanças (dentro do intervalo configurado, ou imediatamente se configurar webhooks). Os controllers então entram em um loop de reconciliação: eles buscam o estado desejado em Git e o estado atual no cluster, executando ações para convergir.

# Ver status das sincronizações
flux get kustomizations -A
flux get helmreleases -A
flux get sources git -A

# Ver logs detalhados
flux logs --all-namespaces --follow

# Forçar reconciliação imediatamente
flux reconcile kustomization app-deployment
flux reconcile source git app-repo

Se uma HelmRelease falhar, o Flux não desiste. Ele continua tentando no intervalo especificado. Você pode ver erros com flux get helmrelease postgresql -n databases:

NAME         READY  MESSAGE
postgresql   False  Helm upgrade failed: error validating values

Segredos e sensibilidade

Dados sensíveis em Git violam segurança. Flux integra-se com SOPS (Secrets Operations) e sealed-secrets do Bitnami. Com SOPS, você criptografa valores com uma chave pública — só o cluster com a chave privada consegue descriptografar:

# Criar segredo criptografado
echo "password: super-secreto" | sops -e /dev/stdin

# Resultado (encrypted)
password: ENC[AES256_GCM,data:h8k+...,iv:...,tag:...,type:str]

Flux detecta e descriptografa automaticamente se configurado:

apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: app-deployment
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: app-repo
  path: ./app/overlays/production
  decryption:
    provider: sops
    secretRef:
      name: sops-keys

Estratégia de branches e ambientes

Uma prática robusta usa branches para ambientes. GitOps puro significa cada branch = estado esperado de um ambiente:

# Staging recebe commits direto
git push origin feature-x

# Production requer pull request mergeado em main
git pull-request --branch=main

# Clusters sincronizam branches diferentes
# Staging: staging branch
# Production: main branch

Cada cluster aponta para seu branch via GitRepository:

# staging/flux-system.yaml
spec:
  ref:
    branch: staging

# production/flux-system.yaml
spec:
  ref:
    branch: main

Conclusão

Flux CD oferece uma arquitetura GitOps modular onde você compõe a solução desejada. A separação entre Source, Kustomize e Helm Controllers fornece flexibilidade: aplicações em Kustomize aproveitam versionamento semântico com Helm para infraestrutura crítica. O loop de reconciliação contínuo garante convergência automática, eliminando drift entre Git e cluster. Por fim, a integração com ferramentas como SOPS permite usar Git como single source of truth mesmo com dados sensíveis, mantendo auditoria completa de quem mudou o quê e quando.

Referências


Artigos relacionados