Crossplane: O Plano de Controle Universal para Infraestrutura

admin 28 Jan 2026 22 min de leitura

Crossplane: Transformando Kubernetes em um Plano de Controle Universal

O Problema que Voce Provavelmente Enfrenta Hoje

Voce se reconhece em algum desses cenarios?

Cenario 1 — O Labirinto dos Tickets: Voce precisa de um novo ambiente Azure. Abre um ticket. Espera 3 dias. Infra cria o Resource Group, Redes configura a VNet, DevOps provisiona o AKS. Uma semana depois, alguem deleta o NSG “por acidente”. Tudo cai. Ninguem sabe quem fez o que.

Cenario 2 — O Terror do Terraform State: Voce usa Terraform, mas o .tfstate e uma bomba-relogio. Alguem rodou terraform apply com a subscription errada. Recurso sumiu. Recuperacao levou 4 horas. Agora ninguem quer mexer no codigo de infra.

Cenario 3 — O Custo Invisivel: Voce paga R$25k/mes em Azure, mas ninguem tem visibilidade real. ACR esta ocioso. NSG tem 50 regras nao utilizadas. Clusters de staging rodam 24/7 sem ninguem usar.

Se voce se reconheceu em UM desses cenarios, este guia e para voce.


O que voce vai aprender neste guia:

Ao final da leitura e execucao deste guia, voce sera capaz de:

  • Entender o que e Crossplane: Compreender a filosofia, arquitetura e por que ele esta mudando o jogo de IaC.
  • Dominar os Conceitos Fundamentais: Providers, Managed Resources, ProviderConfig, Compositions e Claims.
  • Entender o Loop de Reconciliacao: Como o Crossplane garante que a realidade SEMPRE reflita o estado desejado.
  • Configurar um Cluster de Gestao: Preparar o Crossplane para gerenciar multiplas clouds.
  • Provisionar Infraestrutura Completa: Criar AKS, ACR, VNet, NSG com um unico kubectl apply.
  • Preparar para GitOps: Versionar infraestrutura no Git, pronta para integracao com ArgoCD (artigo futuro).

Crossplane: Transformando Kubernetes em um Plano de Controle Universal


Sobre a CodeSolve

┌─────────────────────────────────────────────────────────────────────────────┐
│                                                                             │
│      ██████╗ ██████╗ ██████╗ ███████╗███████╗ ██████╗ ██╗    ██╗   ██╗███████╗│
│     ██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔════╝██╔═══██╗██║    ██║   ██║██╔════╝│
│     ██║     ██║   ██║██║  ██║█████╗  ███████╗██║   ██║██║    ██║   ██║█████╗  │
│     ██║     ██║   ██║██║  ██║██╔══╝  ╚════██║██║   ██║██║    ╚██╗ ██╔╝██╔══╝  │
│     ╚██████╗╚██████╔╝██████╔╝███████╗███████║╚██████╔╝███████╗╚████╔╝ ███████╗│
│      ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝ ╚══════╝ ╚═══╝  ╚══════╝│
│                                                                             │
│                      A Arte de Resolver Problemas                           │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Minha profissao e resolver problemas. Ha 22 anos uso tecnologia como ferramenta para isso.

Sou Alexandre Carvalho, fundador da CodeSolve. Ao longo dessas duas decadas, passei por infraestrutura, desenvolvimento, arquitetura e, mais recentemente, mergulhei fundo no universo DevOps e Cloud Native. A CodeSolve nasceu dessa jornada — da vontade de compartilhar conhecimento e ajudar empresas a modernizarem suas operacoes de forma pratica e segura.

O que fazemos:

  • Consultoria em DevOps, CI/CD e Kubernetes
  • Implementacao de pipelines com Tekton, GitLab CI, ArgoCD
  • Migracao e operacao em Cloud (AWS, GCP, Azure, OCI)
  • Observabilidade, Seguranca e Infraestrutura como Codigo

Contato:


Afinal, o que diabos e Crossplane?

Crossplane e um projeto open-source que transforma qualquer cluster Kubernetes em um plano de controle universal para infraestrutura. Em termos simples: voce usa kubectl para criar recursos na AWS, Azure, GCP, ou qualquer outro provedor — da mesma forma que cria Pods e Deployments.

Lancado em 2018 pela Upbound e promovido a Incubating na CNCF em 2021, o Crossplane nasceu de uma ideia revolucionaria: e se o Kubernetes pudesse gerenciar nao apenas containers, mas QUALQUER recurso de infraestrutura?

┌─────────────────────────────────────────────────────────────────────────────┐
│                                                                             │
│                        O QUE E CROSSPLANE?                                  │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                      KUBERNETES (etcd)                              │   │
│  │                                                                     │   │
│  │   Pods     Deployments    Services    ConfigMaps    Secrets         │   │
│  │    ▲           ▲            ▲            ▲            ▲             │   │
│  │    │           │            │            │            │             │   │
│  │    └───────────┴────────────┴────────────┴────────────┘             │   │
│  │                            │                                        │   │
│  │                    RECURSOS NATIVOS K8S                             │   │
│  │                                                                     │   │
│  │  ─────────────────────────────────────────────────────────────────  │   │
│  │                                                                     │   │
│  │                    + CROSSPLANE ADICIONA:                           │   │
│  │                            │                                        │   │
│  │    ┌───────────┬───────────┼───────────┬───────────┐                │   │
│  │    ▼           ▼           ▼           ▼           ▼                │   │
│  │   VPC        RDS       AKS         S3        CosmosDB              │   │
│  │  (AWS)     (AWS)     (Azure)     (AWS)      (Azure)                │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  RESULTADO: Kubernetes como PLANO DE CONTROLE UNIVERSAL                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Os 4 Pilares do Crossplane

1. Providers (Os Tradutores)

Providers sao plugins que ensinam o Crossplane a “falar” com uma cloud especifica. Cada provider adiciona novos CRDs (Custom Resource Definitions) ao Kubernetes.

1
2
3
4
5
6
7
# Exemplo: Instalando o Provider Azure
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-azure-network
spec:
  package: xpkg.upbound.io/upbound/provider-azure-network:v2.3.0

Quando voce instala o provider-azure-network, ele registra CRDs como:

  • VirtualNetwork
  • Subnet
  • NetworkSecurityGroup
  • PublicIPAddress

Agora voce pode criar esses recursos com kubectl apply!

2. Managed Resources (Os Recursos Reais)

Managed Resources sao representacoes 1:1 de recursos de infraestrutura. Cada Managed Resource corresponde a UM recurso na cloud.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Isso cria um Resource Group REAL na Azure
apiVersion: azure.upbound.io/v1beta1
kind: ResourceGroup
metadata:
  name: meu-app-prod-rg
spec:
  forProvider:
    location: brazilsouth
    tags:
      environment: production
  providerConfigRef:
    name: azure-provider

3. ProviderConfig (A Credencial)

O ProviderConfig conecta o Crossplane a sua conta na cloud. Ele referencia um Secret com as credenciais.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: azure.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: azure-provider
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: azure-creds
      key: credentials

4. O Loop de Reconciliacao (A Magia)

Aqui esta o diferencial BRUTAL do Crossplane: ele nao executa uma vez e esquece (como Terraform). Ele reconcilia continuamente.

┌─────────────────────────────────────────────────────────────────────────────┐
│                                                                             │
│                    LOOP DE RECONCILIACAO CROSSPLANE                         │
│                                                                             │
│     ┌──────────────┐         ┌──────────────┐         ┌──────────────┐     │
│     │              │         │              │         │              │     │
│     │  ESTADO      │         │  CROSSPLANE  │         │   CLOUD      │     │
│     │  DESEJADO    │◄───────►│  CONTROLLER  │◄───────►│   (AZURE)    │     │
│     │  (YAML)      │         │              │         │              │     │
│     │              │         │              │         │              │     │
│     └──────────────┘         └──────────────┘         └──────────────┘     │
│            │                        │                        │             │
│            │                        │                        │             │
│            ▼                        ▼                        ▼             │
│     ┌──────────────────────────────────────────────────────────────┐       │
│     │                                                              │       │
│     │   1. Usuario aplica YAML  ──────────────────────────────►    │       │
│     │                                                              │       │
│     │   2. Controller le o YAML ◄──────────────────────────────    │       │
│     │                                                              │       │
│     │   3. Controller chama API Azure ─────────────────────────►   │       │
│     │                                                              │       │
│     │   4. Azure cria/atualiza recurso ◄───────────────────────    │       │
│     │                                                              │       │
│     │   5. Controller atualiza status ─────────────────────────►   │       │
│     │                                                              │       │
│     │   6. REPETE A CADA 60 SEGUNDOS (drift detection!)            │       │
│     │                                                              │       │
│     └──────────────────────────────────────────────────────────────┘       │
│                                                                             │
│   SE ALGUEM DELETAR O RECURSO NA AZURE MANUALMENTE:                        │
│   ──────────────────────────────────────────────────                       │
│   O Crossplane detecta o drift e RECRIA automaticamente!                   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Por que isso e revolucionario?

Com Terraform, se alguem deleta um recurso manualmente, voce so descobre no proximo terraform plan. Com Crossplane, o recurso e recriado automaticamente em ate 60 segundos. Isso e self-healing infrastructure.

E o Proximo Nivel? Compositions e XRDs

Os 4 pilares acima sao a base. Mas o Crossplane vai muito alem: Compositions e XRDs (Composite Resource Definitions) permitem criar abstracoes poderosas — tipo “pedir um banco de dados” sem saber se e RDS, CloudSQL ou Azure SQL por baixo.

┌─────────────────────────────────────────────────────────────────────────────┐
│                     O PROXIMO NIVEL: ABSTRACOES                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   DESENVOLVEDOR                      PLATAFORMA                             │
│   ─────────────                      ──────────                             │
│                                                                             │
│   "Preciso de um banco"              XRD: Database                          │
│         │                                  │                                │
│         ▼                                  ▼                                │
│   kind: Database               ┌─── Composition ───┐                        │
│   spec:                        │                   │                        │
│     engine: postgres           │  Se AWS: RDS      │                        │
│     size: small                │  Se Azure: FlexDB │                        │
│                                │  Se GCP: CloudSQL │                        │
│                                └───────────────────┘                        │
│                                                                             │
│   RESULTADO: Dev nao precisa saber detalhes de cloud!                       │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Quer aprender Compositions e XRDs?

Este guia foca nos fundamentos. No proximo artigo, vamos construir Compositions completas para abstrair a complexidade da cloud. Fique ligado!


Crossplane vs Terraform: A Batalha Final

Essa e a pergunta de 1 milhao de dolares. Vamos ser honestos:

AspectoTerraformCrossplane
ModeloImperativo (apply/destroy)Declarativo (reconciliacao continua)
EstadoArquivo .tfstate (fragil)Kubernetes etcd (robusto)
Drift DetectionManual (terraform plan)Automatico (a cada 60s)
Self-HealingNao temNativo
GitOpsRequer wrappers (Atlantis)Nativo com ArgoCD/Flux
Multi-tenancyComplexo (workspaces)Natural (namespaces)
LinguagemHCL (proprietaria)YAML (universal)
Curva de AprendizadoMenorMaior (precisa saber K8s)
Maturidade10+ anos5 anos
EcossistemaGiganteCrescendo rapido

Quando usar Terraform?

  • Equipe nao conhece Kubernetes
  • Projeto simples e isolado
  • Ja tem muito codigo Terraform

Quando usar Crossplane?

  • Ja usa Kubernetes para workloads
  • Quer GitOps de verdade
  • Precisa de self-healing e drift detection
  • Multi-cloud / Multi-tenant

Nossa escolha: Crossplane

Nosso cluster de gestao ja e Kubernetes. Faz sentido usar a mesma linguagem (YAML), o mesmo fluxo (GitOps com ArgoCD), e o mesmo tooling (kubectl) para gerenciar infraestrutura. O Crossplane unifica tudo.


O Problema que Estamos Resolvendo

Imagine que voce precisa criar um ambiente completo na Azure: cluster Kubernetes, registry de imagens, rede privada, firewall… Como e o processo hoje na sua empresa?

O Modelo Tradicional (O Labirinto):

Voce abre um ticket. A equipe de Cloud recebe. Alguem da equipe de Infra cria o Resource Group. Outra pessoa, da equipe de Redes, configura a VNet. A equipe de Kubernetes provisiona o AKS. Dias (ou semanas) depois, o ambiente chega para voce. Frustrante, ne?

O Modelo Crossplane (O Portal Magico):

Com o Crossplane, voce nao pede mais infraestrutura, voce a declara. Um arquivo YAML descreve exatamente o que voce quer, e o Crossplane reconcilia esse estado desejado com a realidade na cloud. E GitOps puro: versionado, auditavel, reproduzivel.

┌─────────────────────────────────────────────────────────────────────────────┐
│                                                                             │
│   MODELO TRADICIONAL              MODELO CROSSPLANE                         │
│   ──────────────────              ─────────────────                         │
│                                                                             │
│   [Ticket] ──► [Infra]            [Git Push] ──► [Crossplane]               │
│      │            │                    │              │                     │
│      ▼            ▼                    ▼              ▼                     │
│   [Rede] ──► [DevOps]              [YAML] ──────► [Azure]                   │
│      │            │                                   │                     │
│      ▼            ▼                                   ▼                     │
│   [Dias...]    [Ambiente]          [Minutos!]    [Ambiente]                 │
│                                                                             │
│   Tempo: Dias/Semanas              Tempo: 15-20 minutos                     │
│   Erro humano: Alto                Erro humano: Minimo                      │
│   Rastreabilidade: Baixa           Rastreabilidade: Git                     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Nosso Laboratorio: A Arquitetura Multi-Tenant

Antes de mergulhar nos comandos, e crucial entender nosso campo de batalha:

┌─────────────────────────────────────────────────────────────────────────────┐
│                         CLUSTER DE GESTAO (Minikube)                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │                      CROSSPLANE SYSTEM                                │  │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐                    │  │
│  │  │ Provider    │  │ Provider    │  │ Provider    │                    │  │
│  │  │ Azure       │  │ Azure       │  │ Azure       │                    │  │
│  │  │ Network     │  │ Container   │  │ Managed     │                    │  │
│  │  │             │  │ Service     │  │ Identity    │                    │  │
│  │  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘                    │  │
│  │         │                │                │                           │  │
│  │         └────────────────┼────────────────┘                           │  │
│  │                          │                                            │  │
│  │                    ┌─────▼─────┐                                      │  │
│  │                    │ Provider  │                                      │  │
│  │                    │ Config    │                                      │  │
│  │                    │ (Secret)  │                                      │  │
│  │                    └─────┬─────┘                                      │  │
│  └──────────────────────────┼────────────────────────────────────────────┘  │
│                             │                                               │
└─────────────────────────────┼───────────────────────────────────────────────┘
                              │
                              │ Azure API
                              ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                              AZURE CLOUD                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    TENANT: produto-env-rg                           │   │
│  │  ┌─────────────────────────────────────────────────────────────┐    │   │
│  │  │                    VNet 10.x.0.0/16                         │    │   │
│  │  │  ┌─────────────────────┐  ┌─────────────────────┐           │    │   │
│  │  │  │ snet-aks            │  │ snet-endpoints      │           │    │   │
│  │  │  │ 10.x.0.0/22         │  │ 10.x.4.0/24         │           │    │   │
│  │  │  │                     │  │                     │           │    │   │
│  │  │  │  ┌───────────────┐  │  │                     │           │    │   │
│  │  │  │  │ AKS Cluster   │  │  │                     │           │    │   │
│  │  │  │  │ (Kubenet)     │  │  │                     │           │    │   │
│  │  │  │  └───────────────┘  │  │                     │           │    │   │
│  │  │  └─────────────────────┘  └─────────────────────┘           │    │   │
│  │  └─────────────────────────────────────────────────────────────┘    │   │
│  │                                                                     │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐                  │   │
│  │  │ ACR         │  │ Managed     │  │ NSG         │                  │   │
│  │  │ (Registry)  │  │ Identity    │  │ (Firewall)  │                  │   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘                  │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

O que cada recurso faz?

RecursoProposito
Resource GroupContainer logico que agrupa todos os recursos do tenant
VNetRede privada isolada para o tenant
Subnet AKSRede onde os nodes do Kubernetes rodam
Subnet EndpointsRede para Private Endpoints (banco, storage)
NSGFirewall de rede (regras de entrada/saida)
AKSCluster Kubernetes gerenciado
ACRRegistry privado de imagens Docker
Managed IdentityIdentidade para workloads acessarem recursos Azure

Por que esse desenho importa?

Este nao e um lab de brinquedo. Ao usar VNet dedicada, subnets segregadas e NSG, garantimos:

  • Isolamento de rede entre tenants
  • Seguranca com firewall dedicado
  • Escalabilidade para adicionar mais recursos depois
  • O tenant se comporta como um ambiente de producao, so que em escala reduzida.

Pre-requisitos

Ferramentas Necessarias

1
2
3
4
5
# Verificar instalacao
az version          # azure-cli 2.x
kubectl version --client  # v1.28+
kustomize version   # v5.x
yq --version        # v4.x

Crossplane: Este guia foi validado com Crossplane v1.18.x e Providers Azure v2.3.0. Versoes mais recentes devem funcionar, mas verifique a documentacao oficial em caso de breaking changes.

Instalacao (se necessario):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# Kustomize
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
sudo mv kustomize /usr/local/bin/

# yq
sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq
sudo chmod +x /usr/local/bin/yq

Acesso ao Cluster de Gestao

1
2
# Verificar acesso ao Crossplane
kubectl --context minikube get pods -n crossplane-system

Por que validar isso antes?

Porque a maioria dos problemas em provisionamentos Crossplane comeca aqui:

  • Cluster de gestao inacessivel
  • Providers nao instalados
  • ProviderConfig ausente
  • Credenciais expiradas

Validando esses pontos antes, eliminamos erros dificeis de diagnosticar durante o deploy.


Parte 1 — Preparando o Ambiente

1.1 Login Azure

1
2
3
az login
az account set --subscription "SUA_SUBSCRIPTION_ID"
az account show

1.2 Registrar Resource Providers

A Azure exige que certos “Resource Providers” estejam ativos na subscription antes de criar recursos:

1
2
3
4
5
6
7
8
az provider register --namespace Microsoft.ContainerService --wait
az provider register --namespace Microsoft.Network --wait
az provider register --namespace Microsoft.ContainerRegistry --wait
az provider register --namespace Microsoft.ManagedIdentity --wait
az provider register --namespace Microsoft.Authorization --wait

# Verificar
az provider show -n Microsoft.ContainerService --query "registrationState" -o tsv

1.3 Verificar Quota de vCPU

Antes de provisionar, confira se ha quota disponivel:

1
2
3
az vm list-usage --location <SUA_REGIAO> \
  --query "[?contains(name.value, 'cores')].{Nome:name.localizedValue, Usado:currentValue, Limite:limit}" \
  --output table

Por que verificar quota?

Se a quota estiver esgotada, o AKS vai ficar em estado Creating eternamente, sem erro claro. Melhor descobrir isso antes de esperar 15 minutos.


Parte 2 — Configurando Crossplane

2.1 Instalar Providers Azure (v2.3.0)

Os providers sao os “plugins” que ensinam o Crossplane a falar com a Azure:

1
2
3
4
kubectl --context minikube apply -f platform/providers/azure-providers.yaml

# Aguardar (5-10 min) - todos devem ficar HEALTHY=True
watch kubectl --context minikube get providers

Esperado: 6 providers com HEALTHY=True

2.2 Criar ProviderConfig

O ProviderConfig conecta o Crossplane a sua subscription Azure:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 1. Criar Service Principal
az ad sp create-for-rbac \
  --name "crossplane-provider-azure" \
  --role Contributor \
  --scopes /subscriptions/$(az account show --query id -o tsv) \
  --sdk-auth > /tmp/azure-credentials.json

# 1.1 Proteger credenciais (evitar leitura por outros usuarios)
chmod 600 /tmp/azure-credentials.json

# 2. Criar Secret no Kubernetes
kubectl --context minikube create secret generic azure-secret \
  -n crossplane-system \
  --from-file=creds=/tmp/azure-credentials.json

# 3. Criar ProviderConfig
cat <<EOF | kubectl --context minikube apply -f -
apiVersion: azure.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: azure-provider-prod
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: azure-secret
      key: creds
EOF

# 4. Limpar credenciais locais
rm /tmp/azure-credentials.json

Parte 3 — POC: Testando a Conectividade

Antes de criar a infraestrutura completa, vamos testar se o Crossplane consegue criar recursos na Azure:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# Criar RG de teste
cat <<EOF | kubectl --context minikube apply -f -
apiVersion: azure.upbound.io/v1beta1
kind: ResourceGroup
metadata:
  name: poc-teste-rg
spec:
  forProvider:
    location: canadacentral
    tags:
      purpose: poc
  providerConfigRef:
    name: azure-provider-prod
  deletionPolicy: Delete
EOF

# Verificar (READY=True em ~30s)
kubectl --context minikube get resourcegroup poc-teste-rg

# Limpar
kubectl --context minikube delete resourcegroup poc-teste-rg

Por que fazer uma POC primeiro?

Se esse Resource Group simples nao funcionar, nada vai funcionar. E muito mais facil debugar um recurso do que onze.


Parte 4 — Criando o Tenant

4.1 Definir Variaveis

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# === PREENCHA AQUI ===
export TENANT_PRODUCT="meuproduto"          # Nome do produto (minusculo, sem espacos)
export TENANT_ENV="staging"                 # dev, staging ou prod
export TENANT_REGION="canadacentral"        # Regiao Azure
export TENANT_VNET_CIDR="10.200.0.0/16"     # CIDR unico (nao conflitar com outros tenants)
export TENANT_KVERSION="1.30.6"             # Versao do Kubernetes
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_NAME="applications"
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_MACHINETYPE="Standard_E2s_v5"

# === CALCULADOS ===
export TENANT_NAME="${TENANT_PRODUCT}-${TENANT_ENV}"
export TENANT_ACR_NAME="${TENANT_PRODUCT}${TENANT_ENV}acr$(date +%m%d)"
export TENANT_SUBNET_AKS_CIDR="$(echo $TENANT_VNET_CIDR | sed 's|0.0/16|0.0/22|')"
export TENANT_SUBNET_PE_CIDR="$(echo $TENANT_VNET_CIDR | sed 's|0.0/16|4.0/24|')"

echo "Tenant: $TENANT_NAME | ACR: $TENANT_ACR_NAME"

Por que calcular CIDRs automaticamente?

O /22 para AKS suporta ate 1000 IPs (suficiente para nodes + pods). O /24 para endpoints suporta 254 IPs. Essa divisao e uma boa pratica que evita desperdicio de IPs.

4.2 Verificar CIDRs Existentes

1
2
# Evitar conflito de rede
grep -r "vnetCidr:" tenants/*/tenant.yaml 2>/dev/null

4.3 Criar Estrutura de Diretorios

1
2
3
4
# Navegue ate a raiz do repositorio codesolve-multicloud
cd <CAMINHO_DO_REPOSITORIO>

mkdir -p tenants/${TENANT_NAME}/infra/azure/base

4.4 Criar tenant.yaml

Este arquivo e a “fonte da verdade” do tenant:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cat > tenants/${TENANT_NAME}/tenant.yaml << EOF
apiVersion: platform.codesolve.io/v1alpha1
kind: Tenant
metadata:
  name: ${TENANT_NAME}
spec:
  product: ${TENANT_PRODUCT}
  environment: ${TENANT_ENV}
  region:
    azure: ${TENANT_REGION}
  naming:
    prefix: ${TENANT_NAME}
    acrName: ${TENANT_ACR_NAME}
  network:
    vnetCidr: ${TENANT_VNET_CIDR}
    subnetAksCidr: ${TENANT_SUBNET_AKS_CIDR}
    subnetPrivateEndpointsCidr: ${TENANT_SUBNET_PE_CIDR}
  kubernetes:
    version: "${TENANT_KVERSION}"
    skuTier: Free
    nodePools:
      applications:
        name: "${TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_NAME}"
        machineType: "${TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_MACHINETYPE}"
        osDiskSizeGb: 30
        minNodes: 1
        maxNodes: 2
        maxPods: 30
  costCenter: "${TENANT_PRODUCT}-platform"
EOF

4.5 Criar Kustomizations

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Root
cat > tenants/${TENANT_NAME}/infra/azure/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - base
EOF

# Base
cat > tenants/${TENANT_NAME}/infra/azure/base/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../../../../platform/compositions/azure/resource-group.yaml
  - ../../../../../platform/compositions/azure/network.yaml
  - ../../../../../platform/compositions/azure/nsg-rules.yaml
  - ../../../../../platform/compositions/azure/identity.yaml
  - ../../../../../platform/compositions/azure/aks.yaml
  - ../../../../../platform/compositions/azure/acr.yaml
EOF

4.6 Criar Script de Variaveis

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cat > tenants/${TENANT_NAME}/export-vars.sh << 'SCRIPT'
#!/bin/bash
TENANT_FILE="tenant.yaml"

export TENANT_NAME=$(yq -r '.metadata.name' $TENANT_FILE)
export TENANT_PRODUCT=$(yq -r '.spec.product' $TENANT_FILE)
export TENANT_ENVIRONMENT=$(yq -r '.spec.environment' $TENANT_FILE)
export TENANT_REGION_AZURE=$(yq -r '.spec.region.azure' $TENANT_FILE)
export TENANT_NAMING_PREFIX=$(yq -r '.spec.naming.prefix' $TENANT_FILE)
export TENANT_NAMING_ACRNAME=$(yq -r '.spec.naming.acrName' $TENANT_FILE)
export TENANT_NETWORK_VNETCIDR=$(yq -r '.spec.network.vnetCidr' $TENANT_FILE)
export TENANT_NETWORK_SUBNETAKSCIDR=$(yq -r '.spec.network.subnetAksCidr' $TENANT_FILE)
export TENANT_NETWORK_SUBNETPRIVATEENDPOINTSCIDR=$(yq -r '.spec.network.subnetPrivateEndpointsCidr' $TENANT_FILE)
export TENANT_KUBERNETES_VERSION=$(yq -r '.spec.kubernetes.version' $TENANT_FILE)
export TENANT_KUBERNETES_SKUTIER=$(yq -r '.spec.kubernetes.skuTier' $TENANT_FILE)
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_NAME=$(yq -r '.spec.kubernetes.nodePools.applications.name' $TENANT_FILE)
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_MACHINETYPE=$(yq -r '.spec.kubernetes.nodePools.applications.machineType' $TENANT_FILE)
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_OSDISKSIZEGB=$(yq -r '.spec.kubernetes.nodePools.applications.osDiskSizeGb' $TENANT_FILE)
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_MINNODES=$(yq -r '.spec.kubernetes.nodePools.applications.minNodes' $TENANT_FILE)
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_MAXNODES=$(yq -r '.spec.kubernetes.nodePools.applications.maxNodes' $TENANT_FILE)
export TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_MAXPODS=$(yq -r '.spec.kubernetes.nodePools.applications.maxPods' $TENANT_FILE)
export TENANT_COSTCENTER=$(yq -r '.spec.costCenter' $TENANT_FILE)

echo "Variaveis exportadas: $TENANT_NAME"
SCRIPT

chmod +x tenants/${TENANT_NAME}/export-vars.sh

Parte 5 — Aplicando o Tenant

5.1 Carregar Variaveis

1
2
cd tenants/${TENANT_NAME}
source export-vars.sh

5.2 Preview (Opcional)

1
2
kustomize build --load-restrictor LoadRestrictionsNone infra/azure | envsubst > /tmp/preview.yaml
grep "^kind:" /tmp/preview.yaml | sort | uniq -c

Esperado: 11 recursos

      1 KubernetesCluster
      1 NetworkSecurityGroup
      1 Registry
      1 ResourceGroup
      2 SecurityRule
      1 SubnetNetworkSecurityGroupAssociation
      2 Subnet
      1 UserAssignedIdentity
      1 VirtualNetwork

5.3 Aplicar

1
kustomize build --load-restrictor LoadRestrictionsNone infra/azure | envsubst | kubectl --context minikube apply -f -

5.4 Acompanhar Criacao

1
watch kubectl --context minikube get managed
RecursoTempo Aproximado
ResourceGroup30s
VNet, Subnets, NSG1-2 min
SecurityRules1-2 min
Identity1 min
ACR2-3 min
AKS10-15 min
┌─────────────────────────────────────────────────────────────────────────────┐
│                         TIMELINE DE PROVISIONAMENTO                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  0min    2min    4min    6min    8min    10min   12min   14min   16min     │
│  ├───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┤         │
│  │                                                                         │
│  ├─ RG ──┤                                                                 │
│  │       ├─ VNet ─┤                                                        │
│  │       ├─ NSG ──┤                                                        │
│  │       │        ├─ Identity ─┤                                           │
│  │       │        ├─ ACR ──────┤                                           │
│  │       │        │            ├───────── AKS ──────────────────┤          │
│  │                                                                         │
│  ▼                                                              ▼          │
│  APPLY                                                    READY!           │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Parte 6 — Post-Deploy

IMPORTANTE: Algumas integracoes nao podem ser feitas 100% via Crossplane. Execute apos todos recursos estarem READY.

6.1 Verificar Node Pool Pronto

1
2
3
4
5
6
# Aguardar node pool estar Succeeded
az aks nodepool show \
  --resource-group ${TENANT_NAME}-rg \
  --cluster-name ${TENANT_NAME}-aks \
  --name ${TENANT_KUBERNETES_NODEPOOLS_APPLICATIONS_NAME} \
  --query "provisioningState" -o tsv

6.2 Anexar ACR ao AKS

1
2
3
4
az aks update \
  --resource-group ${TENANT_NAME}-rg \
  --name ${TENANT_NAME}-aks \
  --attach-acr ${TENANT_NAMING_ACRNAME}

Por que isso e Post-Deploy?

O Crossplane ainda nao suporta Role Assignments com selectors para principalId. Esse comando az aks update --attach-acr e a forma recomendada pela Microsoft e cria automaticamente o AcrPull role.


Parte 7 — Validacao

7.1 Verificar Crossplane

1
2
kubectl --context minikube get managed
# Todos devem estar READY=True, SYNCED=True

7.2 Acessar o AKS

1
2
3
4
5
6
az aks get-credentials \
  --resource-group ${TENANT_NAME}-rg \
  --name ${TENANT_NAME}-aks \
  --overwrite-existing

kubectl get nodes

7.3 Testar Pull do ACR

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Login no ACR
az acr login --name ${TENANT_NAMING_ACRNAME}

# Push imagem teste
docker pull nginx:alpine
docker tag nginx:alpine ${TENANT_NAMING_ACRNAME}.azurecr.io/nginx:test
docker push ${TENANT_NAMING_ACRNAME}.azurecr.io/nginx:test

# Testar no cluster
kubectl run nginx-test --image=${TENANT_NAMING_ACRNAME}.azurecr.io/nginx:test
kubectl get pod nginx-test -w

# Limpar
kubectl delete pod nginx-test

7.4 Checklist Final

  • 11 recursos READY=True no Crossplane
  • Resource Group visivel no Portal Azure
  • AKS acessivel via kubectl
  • Nodes em Ready
  • ACR criado
  • Push/Pull de imagens funciona

Parte 8 — Troubleshooting

Resource nao fica READY

1
2
kubectl --context minikube describe <tipo> <nome>
kubectl --context minikube logs -n crossplane-system deployment/crossplane

Erro de permissao

1
2
az account show
az role assignment list --assignee $(az account show --query user.name -o tsv)

CIDR em conflito

1
az network vnet list --query "[].{name:name, cidr:addressSpace.addressPrefixes[0]}" -o table

ACR nome duplicado

1
2
az acr check-name --name ${TENANT_NAMING_ACRNAME}
# Nome ACR e global, adicione sufixo unico

Quota insuficiente

1
az vm list-usage --location ${TENANT_REGION_AZURE} -o table | grep -i cores

Parte 9 — Agendamento Start/Stop (Economia de Custos)

Para ambientes nao-produtivos, configure start/stop automatico:

9.1 Criar Automation Account

1
2
3
4
5
6
7
8
az automation account create \
  --name "${TENANT_NAME}-automation" \
  --resource-group ${TENANT_NAME}-rg \
  --location ${TENANT_REGION_AZURE}

az automation account identity assign \
  --name "${TENANT_NAME}-automation" \
  --resource-group ${TENANT_NAME}-rg

9.2 Atribuir Permissao

1
2
3
4
5
6
7
8
9
AUTOMATION_IDENTITY=$(az automation account show \
  --name "${TENANT_NAME}-automation" \
  --resource-group ${TENANT_NAME}-rg \
  --query "identity.principalId" -o tsv)

az role assignment create \
  --assignee $AUTOMATION_IDENTITY \
  --role "Contributor" \
  --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/${TENANT_NAME}-rg"

9.3 Comandos Manuais

1
2
3
4
5
6
7
8
# Parar cluster
az aks stop --resource-group ${TENANT_NAME}-rg --name ${TENANT_NAME}-aks

# Iniciar cluster
az aks start --resource-group ${TENANT_NAME}-rg --name ${TENANT_NAME}-aks

# Verificar estado
az aks show --resource-group ${TENANT_NAME}-rg --name ${TENANT_NAME}-aks --query "powerState.code" -o tsv

Quanto economiza?

Um cluster AKS parado nao cobra pelas VMs. Em um ambiente de staging que roda 12h/dia, 5 dias/semana, voce economiza ~65% do custo de compute.


Parte 10 — Estimativa de Custos

10.1 Custos por Componente (Config Minima)

ComponenteSKU/TipoCusto Mensal (USD)
AKS NodeStandard_E2s_v5 (2 vCPU, 16GB) x 1~$67.40
Container RegistryACR Basic~$5.00
Managed Disk30GB Premium SSD (OS)~$1.20
Subtotal Visivel~$73.60

Nota: IP de egress e gerenciado pelo AKS (incluso no custo do Load Balancer).

10.2 Custos Ocultos (Estimados)

ItemEstimativa MensalObservacao
Trafego de saida (egress)$5-15Depende do volume
Logs/Diagnosticos$10-20Se habilitados
Load Balancer$15-25Criado automaticamente pelo AKS
Total Estimado$103-133

10.3 Otimizacao com Reserved Instances

CenarioEconomiaCusto Total
On-Demand (padrao)-$103-133/mes
Reserved 1 ano~15-20%$87-113/mes
Reserved 3 anos~30-40%$72-93/mes

10.4 Referencias de Preco

RecursoLink
AKS Pricinghttps://azure.microsoft.com/pricing/details/kubernetes-service/
VM Pricinghttps://azure.microsoft.com/pricing/details/virtual-machines/linux/
ACR Pricinghttps://azure.microsoft.com/pricing/details/container-registry/
Bandwidth Pricinghttps://azure.microsoft.com/pricing/details/bandwidth/
Reserved Instanceshttps://azure.microsoft.com/pricing/reserved-vm-instances/

Remover Tenant

1
2
3
4
5
6
7
8
# Desanexar ACR primeiro (opcional mas recomendado)
az aks update --resource-group ${TENANT_NAME}-rg --name ${TENANT_NAME}-aks --detach-acr ${TENANT_NAMING_ACRNAME}

# Deletar recursos Crossplane
kustomize build --load-restrictor LoadRestrictionsNone tenants/${TENANT_NAME}/infra/azure | envsubst | kubectl --context minikube delete -f -

# Verificar
kubectl --context minikube get managed

O Antes e Depois: Seu Resultado

┌─────────────────────────────────────────────────────────────────────────────┐
│                                                                             │
│   ANTES (Workflow Tradicional)         DEPOIS (Com Este Guia)               │
│   ────────────────────────────         ─────────────────────                │
│                                                                             │
│   Dia 1: Abre ticket                   $ git push                           │
│   Dia 2: Equipe de Infra trabalha      $ kubectl apply -f tenant.yaml       │
│   Dia 3: Equipe de Redes trabalha                                           │
│   Dia 4: DevOps configura              [Aguarde 15 minutos...]              │
│   Dia 5: Testes e ajustes                                                   │
│   Dia 6: Finalmente pronto             ✓ Resource Group criado              │
│                                        ✓ VNet e Subnets criados             │
│   Tempo total: 6 DIAS                  ✓ NSG com regras aplicadas           │
│   Erros humanos: ~70%                  ✓ AKS rodando com ACR anexado        │
│   Rastreabilidade: Tickets perdidos    ✓ Managed Identity configurada       │
│   Reproducibilidade: Depende           ✓ Tudo versionado no Git             │
│                                                                             │
│                                        Tempo total: 15 MINUTOS              │
│                                        Erros humanos: ~5%                   │
│                                        Rastreabilidade: Git history         │
│                                        Reproducibilidade: 100%              │
│                                                                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   GANHO REAL:                                                               │
│   • 96% mais rapido (6 dias → 15 minutos)                                   │
│   • 100% auditavel (Git logs = quem, quando, o que)                         │
│   • 100% reproduzivel (mesmo comando, mesmo resultado)                      │
│   • Self-healing (Crossplane recria recursos deletados automaticamente)     │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Conclusao

Se voce chegou ate aqui, seu tenant esta pronto de verdade:

  • Provisionamento declarativo (Crossplane + Kustomize)
  • GitOps-ready (tudo versionado no Git)
  • Infraestrutura completa (VNet, AKS, ACR, NSG, Identity)
  • Integracoes configuradas (ACR → AKS)
  • Custos controlados (Start/Stop, estimativas claras)
  • Fluxo reproduzivel (qualquer estagiario consegue executar)

Este guia forneceu um caminho completo e validado para criar um ambiente Azure robusto e funcional. Agora voce tem uma base solida para explorar, aprender e se aprofundar no ecossistema Crossplane + Azure. Parabens pela conquista!


Resumo Rapido

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 1. Preparar
az login && az account set --subscription "ID"
kubectl --context minikube apply -f platform/providers/azure-providers.yaml

# 2. Criar tenant
mkdir -p tenants/NOME-ENV/infra/azure/base
# Criar tenant.yaml, kustomizations, export-vars.sh

# 3. Aplicar
cd tenants/NOME-ENV
source export-vars.sh
kustomize build --load-restrictor LoadRestrictionsNone infra/azure | envsubst | kubectl --context minikube apply -f -

# 4. Post-deploy
az aks update --resource-group NOME-ENV-rg --name NOME-ENV-aks --attach-acr ACRNAME

# 5. Validar
az aks get-credentials --resource-group NOME-ENV-rg --name NOME-ENV-aks
kubectl get nodes

Proximos Passos — Escolha Seu Caminho

Se voce quer continuar aprendendo:

Proximos artigos da serie:

  • Compositions e XRDs: Criar abstracoes poderosas para sua plataforma
  • Multi-cloud: Provisionar na AWS, Azure e GCP com os mesmos YAMLs
  • ArgoCD + Crossplane: GitOps completo para infraestrutura (deploy automatico via Git)

Se voce quer implementar em producao e precisa de ajuda:

A CodeSolve oferece:

  • Audit de arquitetura Crossplane existente
  • Implementacao acelerada (2-4 semanas para producao)
  • Treinamento hands-on para sua equipe
  • Suporte pos-implementacao

Agende uma conversa: alexandre@codesolve.com.br


Perguntas Frequentes

PerguntaResposta
“E se meu cluster nao conseguir criar o AKS?”Ver Parte 8 (Troubleshooting)
“Quanto custa provisionar tudo isso?”Ver Parte 10 (~$100/mes config minima)
“Posso usar em producao?”Sim, a arquitetura e production-ready
“Minha empresa usa Terraform, vale migrar?”Se ja usa K8s, provavelmente sim
“E se der problema no meio?”Crossplane tem retry automatico

Duvidas nao listadas? Abra issue no repositorio ou entre em contato direto.

"crossplane" "azure" "aks" "gitops" "iac" "kubernetes" "control-plane"

Precisa de ajuda com Crossplane: O Plano de Controle Universal para Infraestrutura?

A CodeSolve pode ajudar sua equipe a implementar essa e outras solucoes.

Falar com a equipe