{"schemaVersion":1,"id":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes","title":"Crossplane: Composición de Infraestructura en Kubernetes, Reemplazando Terraform con IaC GitOps-Native","description":"Guía de practicante sobre Crossplane, composición de infraestructura en Kubernetes usando XRDs, compositions y provider-aws. Cómo reemplazamos Terraform con un approach de IaC GitOps-native y qué aprendimos en el proceso.","language":"es","datePublished":"2025-11-17","dateModified":null,"contentFormat":"text/markdown","content":"DevOps\n\n# Crossplane: Composición de Infraestructura en Kubernetes, Reemplazando Terraform con IaC GitOps-Native\n\n2025-11-175 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/crossplane-infrastructure-composition-kubernetes>)\n\n## Qué Es Realmente Crossplane\n\n[Crossplane](<https://www.crossplane.io/>) es un operador de [Kubernetes](<https://kubernetes.io/>) que te permite manejar infraestructura cloud usando custom resources de Kubernetes. En vez de escribir archivos HCL y correr ` terraform apply `, escribirs manifests YAML y hacés ` kubectl apply `. Los controllers de Crossplane reconcilian el estado deseado contra el estado real del cloud provider, continuamente.\n\nLas abstracciones clave:\n\n1. **Managed Resources (MRs)**, Mapeos directos 1:1 a recurse es cloud. Un MR ` RDSInstance ` provisiona una instancia AWS RDS.\n2. **Composite Resources (XRs)**, Tu API de plataforma custom. Definís el schema (via XRDs) y la implementación (via Compositions).\n3. **Claims**, Requests con scope a namespace para composite resources. Los equipos de aplicación crean claims; los equipos de plataforma definen qué provisionan los claims.\n\n## Armando una API de Plataforma con XRDs y Compositions\n\nLos equipos de aplicación necesitan bases de datos. No deberían necesitar saber sobre VPC subnets, security groups, parameter groups, ni IAM roles. Necesitan: un nombre de base de datos, un engine, un tamaño, y una región.\n\n### El XRD (Definición de API)\n\n```yaml\napiVersion: apiextensions.crossplane.io/v1\nkind: CompositeResourceDefinition\nmetadata:\n name: xdatabases.platform.example.com\nspec:\n group: platform.example.com\n names:\n kind: XDatabase\n plural: xdatabases\n claimNames:\n kind: Database\n plural: databases\n versions:\n - name: v1alpha1\n served: true\n referenceable: true\n schema:\n openAPIV3Schema:\n type: object\n properties:\n spec:\n type: object\n properties:\n engine:\n  type: string\n  enum: [\"postgres\", \"mysql\"]\n engineVersion:\n  type: string\n size:\n  type: string\n  enum: [\"small\", \"medium\", \"large\"]\n region:\n  type: string\n  default: \"us-east-1\"\n backupRetentionDays:\n  type: integer\n  default: 7\n  minimum: 1\n  maximum: 35\n required: [\"engine\", \"engineVersion\", \"size\"]\n```\n\nEsa es nuestra API de plataforma. Cinco campos para el equipo de app. Sin VPC IDs, sin reglas de security groups, sin políticas IAM.\n\n### El Claim (Lo Que Escriben los Equipos de App)\n\n```yaml\napiVersion: platform.example.com/v1alpha1\nkind: Database\nmetadata:\n name: orders-db\n namespace: orders-service\nspec:\n engine: postgres\n engineVersion: \"15.4\"\n size: medium\n backupRetentionDays: 14\n```\n\nEso es todo. Cinco líneas de configuración significativa. El equipo de plataforma controla todo lo demás.\n\n### La Composition (Implementación)\n\nLa Composition define qué recurse es cloud se crean: una instancia RDS con nuestra configuración de seguridad estándar, un parameter group con nuestros settings, y un Kubernetes secret con los detalles de conexión. Incluye mapeos de t-shirt sizes a instance classes reales (` small ` → ` db.t4g.micro `, ` medium ` → ` db.t4g.medium `, ` large ` → ` db.r6g.large `) y patches para propagar campos del XR a los recurse es hijos.\n\n## La Migración desde Terraform\n\nNo arrancamos Terraform de un tirón. La migración llevó cuatro meses:\n\n**Mes 1: Importar recurse es existentes.** Para cada recurso manejado por Terraform, creamos un MR de Crossplane correspondiente con el ID del recurso cloud y ` deletionPolicy: Orphan `. Crossplane observaba pero no modificaba ni borraba los recursos.\n\n**Mes 2: Buildear XRDs y Compositions.** Diseñamos la API de plataforma con nuestros equipos de app, enfocándonos en lo que realmente necesitaban configurar.\n\n**Mes 3: Migrar app por app.** Cada equipo reemplazó sus referencias de Terraform con claims de Crossplane. Porque ambos apuntaban a los mismos recursos, era seguro.\n\n**Mes 4: Decomisionar Terraform.** Cambiamos ` deletionPolicy ` a ` Delete `, borramos el state de Terraform, y archivamos los repos.\n\n## Qué Salió Mal\n\n**1. Madurez del provider.** El provider [AWS](<https://aws.com/>) cubre ~85% de los servicios. Pegamos contra gaps en CloudFront y Cognito. Para esos, usamos el Terraform provider de Crossplane (` provider-terraform `) como puente, corre Terraform real dentro de un controller de Crossplane. Feo pero funcional.\n\n**2. Tormentas de reconciliación.** Crossplane reconcilia cada recurso cada 60 segundos por default. Con 2,400 managed resources, son 2,400 llamadas API a AWS por minuto. Pegamos contra rate limits de AWS en la primera semana. El fix: incrementar ` --poll-interval ` a 5 minutos para recurse es estables.\n\n**3. Secret management.** Crossplane escribe connection secrets como Kubernetes Secrets en base64, no encriptados. Tuvimos que agregar External Secrets Operator para sincronizar secrets generados por Crossplane a AWS Secrets Manager.\n\n**4. Debugging es más difícil.** Cuando un apply de Terraform falla, teners un mensaje de error y un plan diff. Cuando una reconciliación de Crossplane falla, el error está en un evento de Kubernetes en un managed resource anidado dentro de un composite resource que fue creado por un claim. Necesitás ` crossplane beta trace ` y ` kubectl describe ` a través de tres capas de recurse es para encontrar el error real.\n\n## Comparación de Performance\n\n| Métrica | Terraform | Crossplane |\n| --- | --- | --- |\n| Tiempo para provisionar RDS | 12-15 min | 12-15 min (igual, es AWS) |\n| Tiempo para que el dev solicite | 45 min (PR + plan + apply) | 3 min (PR + Argo CD sync) |\n| Detección de drift | Manual (terraform plan) | Continua (cada poll interval) |\n| Storage de estado | S3 + DynamoDB lock | etcd (Kubernetes) |\n| Rollback | terraform apply con state viejo | git revert + Argo CD sync |\n\n## ¿Lo Haría de Nuevo?\n\nSí, pero con advertencias:\n\n1. **Solo si ya se está en Kubernetes.** Crossplane sin Kubernetes no tiene sentido.\n2. **Solo si se desea una API de plataforma.** Si se es un equipo chico donde todos manejan su propia infra, las capas de abstracción de Crossplane son overhead.\n3. **Presupuestar la curva de aprendizaje.** Los conceptos de Crossplane tardan unas dos semanas para un ingeniero de Kubernetes experimentado.\n4. **Mantener Terraform como fallback.** Utilizar ` provider-terraform ` para cualquier recurso que el provider nativo de Crossplane no soporte bien. El purismo no vale outages de producción.\n\nEl ecosistema Kubernetes se está moviendo hacia tratar la infraestructura igual que las aplicaciones, manifests declarativos, reconciliación GitOps, y provisioning API-driven. Crossplane es la herramienta más madura en este espacio, y para organizaciones ya invertidas en Kubernetes, es el siguiente paso natural. Entrá nomás con plena conciencia de la complejidad operacional que se está asumiendo.\n\n## Preguntas frecuentes\n\n### ¿Debería reemplazar Terraform con Crossplane?\n\nSolo si ya se está corriendo Kubernetes y se desea que tu infraestructura se maneje con el mismo workflow GitOps que tus aplicaciones. Crossplane agrega complejidad operacional (otro controller para correr, CRDs para manejar) pero provee reconciliación continua, detección de drift, y una experiencia developer Kubernetes-native. Si no se está en Kubernetes, quedate con Terraform.\n\n### ¿Cómo maneja Crossplane el estado comparado con Terraform?\n\nCrossplane guarda el estado como recurse es Kubernetes (custom resources en etcd), no en un archivo de estado separado. Esto significa que el estado lo maneja el storage etcd built-in de Kubernetes, replicado entre nodos del control plane, y respaldado por tu estrategia de backup existente de Kubernetes. No hay problema de state locking porque Kubernetes maneja el acceso concurrente a recursos.\n\n### ¿Qué son los XRDs y Compositions en Crossplane?\n\nLos XRDs (Composite Resource Definitions) definen una API custom, como un schema CRD para tu plataforma. Las Compositions definen cómo se implementa esa API, qué recurse es cloud crear cuando alguien crea una instancia de tu XRD. Juntos, te permiten buildear una API de plataforma que abstrae la complejidad del cloud mientras le da a los ingenieros de plataforma control total sobre lo que se provisiona.\n\n## Tips\n\n1. **LuchoTip:** Se recomienda establecer siempre ` deletionPolicy: Orphan ` en tus managed resources durante la migración inicial desde Terraform. Esto evita que Crossplane borre tus recurse es cloud reales si accidentalmente borrás el objeto Kubernetes. Cambiá a ` Delete ` solo después de validar el import.\n2. **LuchoTip:** Se recomienda utilizar el recurso ` Usage ` de Crossplane (alpha) para declarar dependencias entre recursos. Sin esto, borrar un claim de VPC va a intentar borrar el VPC antes que sus subnets, causando que el delete se cuelgue. Usage enforcea el orden como el ` depends_on ` de Terraform.\n3. **LuchoTip:** Tus schemas de XRD deberían ser opinados y estrechos. No expongas cada parámetro de AWS, exponer solo lo que tus equipos de plataforma necesitan. Un buen XRD para una instancia RDS tiene 5-8 campos, no 50. Estás armando una API de plataforma, no wrapeando la API del cloud.\n4. **LuchoTip:** Se recomienda ejecutar ` crossplane beta trace ` en tus composite resources cuando debuggees. Muestra todo el árbol de recurse es, qué managed resources pertenecen a qué composition, cuál es su estado, y dónde en el loop de reconciliación están trabados.\n\n- crossplane\n- kubernetes\n- infrastructure-as-code\n- gitops\n- terraform\n- xrd\n- compositions\n- provider-aws\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)","headings":[{"level":1,"text":"Crossplane: Composición de Infraestructura en Kubernetes, Reemplazando Terraform con IaC GitOps-Native","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#title"},{"level":2,"text":"Qué Es Realmente Crossplane","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#qu-es-realmente-crossplane"},{"level":2,"text":"Armando una API de Plataforma con XRDs y Compositions","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#armando-una-api-de-plataforma-con-xrds-y-compositions"},{"level":3,"text":"El XRD (Definición de API)","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#el-xrd-definicin-de-api"},{"level":3,"text":"El Claim (Lo Que Escriben los Equipos de App)","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#el-claim-lo-que-escriben-los-equipos-de-app"},{"level":3,"text":"La Composition (Implementación)","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#la-composition-implementacin"},{"level":2,"text":"La Migración desde Terraform","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#la-migracin-desde-terraform"},{"level":2,"text":"Qué Salió Mal","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#qu-sali-mal"},{"level":2,"text":"Comparación de Performance","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#comparacin-de-performance"},{"level":2,"text":"¿Lo Haría de Nuevo?","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#lo-hara-de-nuevo"},{"level":2,"text":"Preguntas frecuentes","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#questions"},{"level":3,"text":"¿Debería reemplazar Terraform con Crossplane?","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#question-1"},{"level":3,"text":"¿Cómo maneja Crossplane el estado comparado con Terraform?","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#question-2"},{"level":3,"text":"¿Qué son los XRDs y Compositions en Crossplane?","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#question-3"},{"level":2,"text":"Tips","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#article-tips"}],"sections":[{"heading":"Crossplane: Composición de Infraestructura en Kubernetes, Reemplazando Terraform con IaC GitOps-Native","level":1,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes","content":"DevOps"},{"heading":"Crossplane: Composición de Infraestructura en Kubernetes, Reemplazando Terraform con IaC GitOps-Native","level":1,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#title","content":"2025-11-175 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/crossplane-infrastructure-composition-kubernetes>)"},{"heading":"Qué Es Realmente Crossplane","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#qu-es-realmente-crossplane","content":"[Crossplane](<https://www.crossplane.io/>) es un operador de [Kubernetes](<https://kubernetes.io/>) que te permite manejar infraestructura cloud usando custom resources de Kubernetes. En vez de escribir archivos HCL y correr ` terraform apply `, escribirs manifests YAML y hacés ` kubectl apply `. Los controllers de Crossplane reconcilian el estado deseado contra el estado real del cloud provider, continuamente.\n\nLas abstracciones clave:\n\n1. **Managed Resources (MRs)**, Mapeos directos 1:1 a recurse es cloud. Un MR ` RDSInstance ` provisiona una instancia AWS RDS.\n2. **Composite Resources (XRs)**, Tu API de plataforma custom. Definís el schema (via XRDs) y la implementación (via Compositions).\n3. **Claims**, Requests con scope a namespace para composite resources. Los equipos de aplicación crean claims; los equipos de plataforma definen qué provisionan los claims."},{"heading":"Armando una API de Plataforma con XRDs y Compositions","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#armando-una-api-de-plataforma-con-xrds-y-compositions","content":"Los equipos de aplicación necesitan bases de datos. No deberían necesitar saber sobre VPC subnets, security groups, parameter groups, ni IAM roles. Necesitan: un nombre de base de datos, un engine, un tamaño, y una región."},{"heading":"El XRD (Definición de API)","level":3,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#el-xrd-definicin-de-api","content":"```yaml\napiVersion: apiextensions.crossplane.io/v1\nkind: CompositeResourceDefinition\nmetadata:\n name: xdatabases.platform.example.com\nspec:\n group: platform.example.com\n names:\n kind: XDatabase\n plural: xdatabases\n claimNames:\n kind: Database\n plural: databases\n versions:\n - name: v1alpha1\n served: true\n referenceable: true\n schema:\n openAPIV3Schema:\n type: object\n properties:\n spec:\n type: object\n properties:\n engine:\n  type: string\n  enum: [\"postgres\", \"mysql\"]\n engineVersion:\n  type: string\n size:\n  type: string\n  enum: [\"small\", \"medium\", \"large\"]\n region:\n  type: string\n  default: \"us-east-1\"\n backupRetentionDays:\n  type: integer\n  default: 7\n  minimum: 1\n  maximum: 35\n required: [\"engine\", \"engineVersion\", \"size\"]\n```\n\nEsa es nuestra API de plataforma. Cinco campos para el equipo de app. Sin VPC IDs, sin reglas de security groups, sin políticas IAM."},{"heading":"El Claim (Lo Que Escriben los Equipos de App)","level":3,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#el-claim-lo-que-escriben-los-equipos-de-app","content":"```yaml\napiVersion: platform.example.com/v1alpha1\nkind: Database\nmetadata:\n name: orders-db\n namespace: orders-service\nspec:\n engine: postgres\n engineVersion: \"15.4\"\n size: medium\n backupRetentionDays: 14\n```\n\nEso es todo. Cinco líneas de configuración significativa. El equipo de plataforma controla todo lo demás."},{"heading":"La Composition (Implementación)","level":3,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#la-composition-implementacin","content":"La Composition define qué recurse es cloud se crean: una instancia RDS con nuestra configuración de seguridad estándar, un parameter group con nuestros settings, y un Kubernetes secret con los detalles de conexión. Incluye mapeos de t-shirt sizes a instance classes reales (` small ` → ` db.t4g.micro `, ` medium ` → ` db.t4g.medium `, ` large ` → ` db.r6g.large `) y patches para propagar campos del XR a los recurse es hijos."},{"heading":"La Migración desde Terraform","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#la-migracin-desde-terraform","content":"No arrancamos Terraform de un tirón. La migración llevó cuatro meses:\n\n**Mes 1: Importar recurse es existentes.** Para cada recurso manejado por Terraform, creamos un MR de Crossplane correspondiente con el ID del recurso cloud y ` deletionPolicy: Orphan `. Crossplane observaba pero no modificaba ni borraba los recursos.\n\n**Mes 2: Buildear XRDs y Compositions.** Diseñamos la API de plataforma con nuestros equipos de app, enfocándonos en lo que realmente necesitaban configurar.\n\n**Mes 3: Migrar app por app.** Cada equipo reemplazó sus referencias de Terraform con claims de Crossplane. Porque ambos apuntaban a los mismos recursos, era seguro.\n\n**Mes 4: Decomisionar Terraform.** Cambiamos ` deletionPolicy ` a ` Delete `, borramos el state de Terraform, y archivamos los repos."},{"heading":"Qué Salió Mal","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#qu-sali-mal","content":"**1. Madurez del provider.** El provider [AWS](<https://aws.com/>) cubre ~85% de los servicios. Pegamos contra gaps en CloudFront y Cognito. Para esos, usamos el Terraform provider de Crossplane (` provider-terraform `) como puente, corre Terraform real dentro de un controller de Crossplane. Feo pero funcional.\n\n**2. Tormentas de reconciliación.** Crossplane reconcilia cada recurso cada 60 segundos por default. Con 2,400 managed resources, son 2,400 llamadas API a AWS por minuto. Pegamos contra rate limits de AWS en la primera semana. El fix: incrementar ` --poll-interval ` a 5 minutos para recurse es estables.\n\n**3. Secret management.** Crossplane escribe connection secrets como Kubernetes Secrets en base64, no encriptados. Tuvimos que agregar External Secrets Operator para sincronizar secrets generados por Crossplane a AWS Secrets Manager.\n\n**4. Debugging es más difícil.** Cuando un apply de Terraform falla, teners un mensaje de error y un plan diff. Cuando una reconciliación de Crossplane falla, el error está en un evento de Kubernetes en un managed resource anidado dentro de un composite resource que fue creado por un claim. Necesitás ` crossplane beta trace ` y ` kubectl describe ` a través de tres capas de recurse es para encontrar el error real."},{"heading":"Comparación de Performance","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#comparacin-de-performance","content":"| Métrica | Terraform | Crossplane |\n| --- | --- | --- |\n| Tiempo para provisionar RDS | 12-15 min | 12-15 min (igual, es AWS) |\n| Tiempo para que el dev solicite | 45 min (PR + plan + apply) | 3 min (PR + Argo CD sync) |\n| Detección de drift | Manual (terraform plan) | Continua (cada poll interval) |\n| Storage de estado | S3 + DynamoDB lock | etcd (Kubernetes) |\n| Rollback | terraform apply con state viejo | git revert + Argo CD sync |"},{"heading":"¿Lo Haría de Nuevo?","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#lo-hara-de-nuevo","content":"Sí, pero con advertencias:\n\n1. **Solo si ya se está en Kubernetes.** Crossplane sin Kubernetes no tiene sentido.\n2. **Solo si se desea una API de plataforma.** Si se es un equipo chico donde todos manejan su propia infra, las capas de abstracción de Crossplane son overhead.\n3. **Presupuestar la curva de aprendizaje.** Los conceptos de Crossplane tardan unas dos semanas para un ingeniero de Kubernetes experimentado.\n4. **Mantener Terraform como fallback.** Utilizar ` provider-terraform ` para cualquier recurso que el provider nativo de Crossplane no soporte bien. El purismo no vale outages de producción.\n\nEl ecosistema Kubernetes se está moviendo hacia tratar la infraestructura igual que las aplicaciones, manifests declarativos, reconciliación GitOps, y provisioning API-driven. Crossplane es la herramienta más madura en este espacio, y para organizaciones ya invertidas en Kubernetes, es el siguiente paso natural. Entrá nomás con plena conciencia de la complejidad operacional que se está asumiendo."},{"heading":"Preguntas frecuentes","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#questions","content":""},{"heading":"¿Debería reemplazar Terraform con Crossplane?","level":3,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#question-1","content":"Solo si ya se está corriendo Kubernetes y se desea que tu infraestructura se maneje con el mismo workflow GitOps que tus aplicaciones. Crossplane agrega complejidad operacional (otro controller para correr, CRDs para manejar) pero provee reconciliación continua, detección de drift, y una experiencia developer Kubernetes-native. Si no se está en Kubernetes, quedate con Terraform."},{"heading":"¿Cómo maneja Crossplane el estado comparado con Terraform?","level":3,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#question-2","content":"Crossplane guarda el estado como recurse es Kubernetes (custom resources en etcd), no en un archivo de estado separado. Esto significa que el estado lo maneja el storage etcd built-in de Kubernetes, replicado entre nodos del control plane, y respaldado por tu estrategia de backup existente de Kubernetes. No hay problema de state locking porque Kubernetes maneja el acceso concurrente a recursos."},{"heading":"¿Qué son los XRDs y Compositions en Crossplane?","level":3,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#question-3","content":"Los XRDs (Composite Resource Definitions) definen una API custom, como un schema CRD para tu plataforma. Las Compositions definen cómo se implementa esa API, qué recurse es cloud crear cuando alguien crea una instancia de tu XRD. Juntos, te permiten buildear una API de plataforma que abstrae la complejidad del cloud mientras le da a los ingenieros de plataforma control total sobre lo que se provisiona."},{"heading":"Tips","level":2,"url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#article-tips","content":"1. **LuchoTip:** Se recomienda establecer siempre ` deletionPolicy: Orphan ` en tus managed resources durante la migración inicial desde Terraform. Esto evita que Crossplane borre tus recurse es cloud reales si accidentalmente borrás el objeto Kubernetes. Cambiá a ` Delete ` solo después de validar el import.\n2. **LuchoTip:** Se recomienda utilizar el recurso ` Usage ` de Crossplane (alpha) para declarar dependencias entre recursos. Sin esto, borrar un claim de VPC va a intentar borrar el VPC antes que sus subnets, causando que el delete se cuelgue. Usage enforcea el orden como el ` depends_on ` de Terraform.\n3. **LuchoTip:** Tus schemas de XRD deberían ser opinados y estrechos. No expongas cada parámetro de AWS, exponer solo lo que tus equipos de plataforma necesitan. Un buen XRD para una instancia RDS tiene 5-8 campos, no 50. Estás armando una API de plataforma, no wrapeando la API del cloud.\n4. **LuchoTip:** Se recomienda ejecutar ` crossplane beta trace ` en tus composite resources cuando debuggees. Muestra todo el árbol de recurse es, qué managed resources pertenecen a qué composition, cuál es su estado, y dónde en el loop de reconciliación están trabados.\n\n- crossplane\n- kubernetes\n- infrastructure-as-code\n- gitops\n- terraform\n- xrd\n- compositions\n- provider-aws\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)"}],"links":[{"text":"English","url":"https://lucioduran.com/blog/crossplane-infrastructure-composition-kubernetes"},{"text":"Crossplane","url":"https://www.crossplane.io/"},{"text":"Kubernetes","url":"https://kubernetes.io/"},{"text":"AWS","url":"https://aws.com/"},{"text":"Volver al Blog","url":"https://lucioduran.com/es/blog"}],"structuredData":[{"@context":"https://schema.org","@graph":[{"@type":"BlogPosting","@id":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes#article","mainEntityOfPage":{"@type":"WebPage","@id":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes"},"headline":"Crossplane: Composición de Infraestructura en Kubernetes, Reemplazando Terraform con IaC GitOps-Native","description":"Guía de practicante sobre Crossplane, composición de infraestructura en Kubernetes usando XRDs, compositions y provider-aws. Cómo reemplazamos Terraform con un approach de IaC GitOps-native y qué aprendimos en el proceso.","datePublished":"2025-11-17","author":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"publisher":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"image":"https://lucioduran.com/favicons/og-default.png","url":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes","inLanguage":"es","isPartOf":{"@id":"https://lucioduran.com/blog#blog"},"articleSection":"DevOps","keywords":"crossplane, kubernetes, infrastructure-as-code, gitops, terraform, xrd, compositions, provider-aws","wordCount":896,"timeRequired":"PT5M","workTranslation":[{"@type":"BlogPosting","inLanguage":"en","url":"https://lucioduran.com/blog/crossplane-infrastructure-composition-kubernetes"}]},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https://lucioduran.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://lucioduran.com/es/blog"},{"@type":"ListItem","position":3,"name":"Crossplane: Composición de Infraestructura en Kubernetes, Reemplazando Terraform con IaC GitOps-Native","item":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes"}]},{"@type":"FAQPage","mainEntity":[{"@type":"Question","name":"¿Debería reemplazar Terraform con Crossplane?","acceptedAnswer":{"@type":"Answer","text":"Solo si ya se está corriendo Kubernetes y se desea que tu infraestructura se maneje con el mismo workflow GitOps que tus aplicaciones. Crossplane agrega complejidad operacional (otro controller para correr, CRDs para manejar) pero provee reconciliación continua, detección de drift, y una experiencia developer Kubernetes-native. Si no se está en Kubernetes, quedate con Terraform."}},{"@type":"Question","name":"¿Cómo maneja Crossplane el estado comparado con Terraform?","acceptedAnswer":{"@type":"Answer","text":"Crossplane guarda el estado como recurse es Kubernetes (custom resources en etcd), no en un archivo de estado separado. Esto significa que el estado lo maneja el storage etcd built-in de Kubernetes, replicado entre nodos del control plane, y respaldado por tu estrategia de backup existente de Kubernetes. No hay problema de state locking porque Kubernetes maneja el acceso concurrente a recursos."}},{"@type":"Question","name":"¿Qué son los XRDs y Compositions en Crossplane?","acceptedAnswer":{"@type":"Answer","text":"Los XRDs (Composite Resource Definitions) definen una API custom, como un schema CRD para tu plataforma. Las Compositions definen cómo se implementa esa API, qué recurse es cloud crear cuando alguien crea una instancia de tu XRD. Juntos, te permiten buildear una API de plataforma que abstrae la complejidad del cloud mientras le da a los ingenieros de plataforma control total sobre lo que se provisiona."}}]}]}],"contentHash":"9efb19bf951e480019be27c1dcae634304a18ff8655d5b1c35063992292b28b2","provenance":{"method":"Deterministic serialization of the server-rendered main element","source":"https://lucioduran.com/es/blog/crossplane-infrastructure-composition-kubernetes","hashAlgorithm":"sha256","hashScope":"JSON document fields before contentHash and provenance","sourceHTMLBytes":58250,"contentBytes":9674}}
