<h2>O que é Flux CD e por que GitOps?</h2>
<p>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á.</p>
<p>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.</p>
<h2>Arquitetura do Flux: Componentes Principais</h2>
<h3>Source Controller e seus tipos de fonte</h3>
<p>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.</p>
<pre><code class="language-yaml">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</code></pre>
<p>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.</p>
<h3>Kustomize Controller: composição declarativa</h3>
<p>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.</p>
<pre><code class="language-yaml">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</code></pre>
<p>O <code>path</code> aponta para um diretório com <code>kustomization.yaml</code>. O campo <code>prune: true</code> significa que recursos deletados do Git também serão removidos do cluster. <code>wait: true</code> faz Flux aguardar deployments ficarem prontos antes de considerar a sincronização bem-sucedida.</p>
<h3>Helm Controller: gerenciamento de charts</h3>
<p>O Helm Controller gerencia releases Helm direto no cluster. Você não executa <code>helm install</code> manualmente — o controller observa e aplica. Isso funciona particularmente bem para dependências externas (databases, ingress controllers, monitoring stacks).</p>
<pre><code class="language-yaml">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</code></pre>
<p>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 <code>13.1.x</code>.</p>
<h2>Combinando Kustomize e Helm em uma estratégia real</h2>
<h3>Estrutura de projeto recomendada</h3>
<p>Uma abordagem sólida separa concerns em diretórios. Helm para componentes reutilizáveis, Kustomize para customização ambiental. Vamos modelar um projeto real:</p>
<pre><code>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</code></pre>
<h3>Exemplo prático: aplicação com dependências Helm</h3>
<p>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:</p>
<pre><code class="language-yaml"># 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</code></pre>
<p>Agora a dependência externa via Helm:</p>
<pre><code class="language-yaml"># 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</code></pre>
<p>E a aplicação em Kustomize:</p>
<pre><code class="language-yaml"># 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</code></pre>
<pre><code class="language-yaml"># 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"</code></pre>
<p>Para production, você aumenta replicas e adiciona configurações:</p>
<pre><code class="language-yaml"># 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</code></pre>
<pre><code class="language-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</code></pre>
<p>Finalmente, a Kustomization que orquestra tudo:</p>
<pre><code class="language-yaml"># 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</code></pre>
<p>Note o campo <code>dependsOn</code>: Flux aplica infraestrutura primeiro, depois aplicações. Isso previne deployments falharem por dependências indisponíveis.</p>
<h2>Fluxo de trabalho GitOps com Flux</h2>
<h3>Sincronização e reconciliação</h3>
<p>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.</p>
<pre><code class="language-bash"># 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</code></pre>
<p>Se uma HelmRelease falhar, o Flux não desiste. Ele continua tentando no intervalo especificado. Você pode ver erros com <code>flux get helmrelease postgresql -n databases</code>:</p>
<pre><code>NAME READY MESSAGE
postgresql False Helm upgrade failed: error validating values</code></pre>
<h3>Segredos e sensibilidade</h3>
<p>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:</p>
<pre><code class="language-bash"># Criar segredo criptografado
echo "password: super-secreto" | sops -e /dev/stdin
Resultado (encrypted)
password: ENC[AES256_GCM,data:h8k+...,iv:...,tag:...,type:str]</code></pre>
<p>Flux detecta e descriptografa automaticamente se configurado:</p>
<pre><code class="language-yaml">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</code></pre>
<h3>Estratégia de branches e ambientes</h3>
<p>Uma prática robusta usa branches para ambientes. GitOps puro significa cada branch = estado esperado de um ambiente:</p>
<pre><code class="language-bash"># 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</code></pre>
<p>Cada cluster aponta para seu branch via GitRepository:</p>
<pre><code class="language-yaml"># staging/flux-system.yaml
spec:
ref:
branch: staging
production/flux-system.yaml
spec:
ref:
branch: main</code></pre>
<h2>Conclusão</h2>
<p>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.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://fluxcd.io/" target="_blank" rel="noopener noreferrer">Flux CD Documentação Oficial</a></li>
<li><a href="https://kustomize.io/" target="_blank" rel="noopener noreferrer">Kustomize - Kubernetes Customization</a></li>
<li><a href="https://helm.sh/" target="_blank" rel="noopener noreferrer">Helm Package Manager for Kubernetes</a></li>
<li><a href="https://martinfowler.com/articles/gitops.html" target="_blank" rel="noopener noreferrer">GitOps: What You Need to Know - Martin Fowler</a></li>
<li><a href="https://github.com/mozilla/sops" target="_blank" rel="noopener noreferrer">SOPS - Secrets Operations</a></li>
</ul>
<p><!-- FIM --></p>