O Dilema do IaC em Plataformas
Ao construir uma Internal Developer Platform, surge a pergunta: como desenvolvedores devem provisionar infraestrutura? Terraform é o padrão de mercado, mas Crossplane oferece uma abordagem Kubernetes-native que pode ser mais adequada para plataformas.
Terraform
Ferramenta declarativa com estado centralizado e vasto ecossistema de providers
Crossplane
Control plane Kubernetes que trata infraestrutura como CRDs nativos
Terraform: O Padrão da Indústria
Arquitetura do Terraform
Módulos para Abstração
# modules/platform-database/main.tf
variable "name" {
description = "Database name"
type = string
}
variable "size" {
description = "Database size (small, medium, large)"
type = string
default = "small"
}
variable "engine" {
description = "Database engine"
type = string
default = "postgresql"
}
locals {
sizes = {
small = { instance_class = "db.t3.small", storage = 20 }
medium = { instance_class = "db.t3.medium", storage = 100 }
large = { instance_class = "db.r5.large", storage = 500 }
}
}
resource "aws_db_instance" "this" {
identifier = var.name
engine = var.engine
engine_version = "15.4"
instance_class = local.sizes[var.size].instance_class
allocated_storage = local.sizes[var.size].storage
db_name = replace(var.name, "-", "_")
username = "admin"
password = random_password.db.result
vpc_security_group_ids = [aws_security_group.db.id]
db_subnet_group_name = aws_db_subnet_group.this.name
backup_retention_period = 7
skip_final_snapshot = false
deletion_protection = true
tags = {
Name = var.name
ManagedBy = "terraform"
Platform = "true"
}
}
# Output para uso pela aplicação
output "connection_string" {
value = "postgresql://${aws_db_instance.this.username}:${random_password.db.result}@${aws_db_instance.this.endpoint}/${aws_db_instance.this.db_name}"
sensitive = true
}
Terraform com Atlantis para GitOps
# atlantis.yaml
version: 3
projects:
- name: platform-infra
dir: infrastructure/platform
workspace: production
autoplan:
when_modified: ["*.tf", "modules/**/*.tf"]
enabled: true
apply_requirements: [approved, mergeable]
- name: team-a-database
dir: teams/team-a/database
workspace: production
autoplan:
enabled: true
apply_requirements: [approved]
workflows:
default:
plan:
steps:
- init
- plan:
extra_args: ["-lock=false"]
apply:
steps:
- apply
Crossplane: IaC Kubernetes-Native
Arquitetura do Crossplane
Managed Resources
# RDS Instance como CRD
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: my-database
spec:
forProvider:
region: us-east-1
dbInstanceClass: db.t3.small
engine: postgres
engineVersion: "15.4"
masterUsername: admin
allocatedStorage: 20
skipFinalSnapshot: false
writeConnectionSecretToRef:
name: my-database-creds
namespace: team-a
providerConfigRef:
name: aws-provider
Compositions para Abstração
O poder do Crossplane está nas Compositions - abstrações que expõem interfaces simplificadas:
# CompositeResourceDefinition (XRD) - Define a interface
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.platform.myorg.io
spec:
group: platform.myorg.io
names:
kind: XDatabase
plural: xdatabases
versions:
- name: v1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required:
- size
properties:
size:
type: string
enum: [small, medium, large]
description: "Database size"
engine:
type: string
enum: [postgresql, mysql]
default: postgresql
---
# Composition - Implementa a interface
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: database-aws
labels:
provider: aws
spec:
compositeTypeRef:
apiVersion: platform.myorg.io/v1
kind: XDatabase
resources:
- name: rds-instance
base:
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
spec:
forProvider:
region: us-east-1
engine: postgres
engineVersion: "15.4"
publiclyAccessible: false
skipFinalSnapshot: false
patches:
# Map size para instance class
- type: FromCompositeFieldPath
fromFieldPath: spec.size
toFieldPath: spec.forProvider.dbInstanceClass
transforms:
- type: map
map:
small: db.t3.small
medium: db.t3.medium
large: db.r5.large
- type: FromCompositeFieldPath
fromFieldPath: spec.size
toFieldPath: spec.forProvider.allocatedStorage
transforms:
- type: map
map:
small: 20
medium: 100
large: 500
- name: security-group
base:
apiVersion: ec2.aws.crossplane.io/v1beta1
kind: SecurityGroup
spec:
forProvider:
region: us-east-1
description: "Database security group"
ingress:
- fromPort: 5432
toPort: 5432
protocol: tcp
cidrBlocks:
- 10.0.0.0/8
Uso pelo Desenvolvedor
# Isso é tudo que o dev precisa criar!
apiVersion: platform.myorg.io/v1
kind: XDatabase
metadata:
name: orders-db
namespace: team-orders
spec:
size: medium
engine: postgresql
Comparativo
| Aspecto | Terraform | Crossplane |
|---|---|---|
| Modelo | Pull (CLI) | Push (Controller) |
| Estado | Remote backend | Kubernetes etcd |
| Linguagem | HCL | YAML (CRDs) |
| Drift Detection | Manual (plan) | Contínuo (reconciliation) |
| Self-Healing | Não | Sim |
| Multi-Cloud | Sim | Sim |
| GitOps Native | Via Atlantis | Nativo |
| Curva Aprendizado | Menor | Requer K8s knowledge |
| Ecossistema | Muito maduro | Crescendo |
Terraform para times que não usam Kubernetes como plataforma central ou precisam de features avançadas. Crossplane para plataformas Kubernetes-first que querem self-service verdadeiro via kubectl/GitOps.
Hybrid Approach
Muitas organizações usam ambos:
Quer construir a estratégia de IaC para sua plataforma? Fale com nossos especialistas em Platform Engineering.