Introducción

Gestionar más de 50 clústeres de Kubernetes en entornos híbridos (on-prem VMware, múltiples clouds) no es solo un desafío operativo: en instituciones financieras reguladas como RBC Capital Markets, implica cumplir con normativas estrictas como SOX, PCI-DSS y Basilea III. Estas normativas exigen auditoría completa, prevención de drift de configuración y segmentación de red, pero las herramientas tradicionales suelen abordar estos requisitos de forma aislada.

En este artículo, te mostramos cómo construimos una plataforma cloud-native desde cero usando:

  • Kairos: para nodos inmutables y reproducible.
  • k0rdent + k0smotron: para gestionar el ciclo de vida de los clústeres de Kubernetes de forma declarativa.
  • bindy: un operador en Rust para integrar Kubernetes con DNS enterprise (Infoblox) sin depender de tickets manuales.

El resultado es una plataforma donde cada componente (nodos, clústeres, DNS) se gestiona con GitOps, con auditoría completa en Git y tiempos de aprovisionamiento reducidos de horas a segundos.

Qué es y para qué sirve

1. Nodos inmutables con Kairos

Kairos es una distribución Linux diseñada para ser inmutable, declarativa y reproducible, basada en imágenes OCI. Cada nodo en tu flota:

  • Boot desde una imagen OCI (derivada de RHEL, Ubuntu, etc.).
  • Configuración definida como YAML (cloud-config) que se versiona en tu repositorio Git.
  • Integración con FluxCD para reconciliación continua.
¿Por qué es útil?
  • Elimina el «drift» de configuración: los nodos siempre arrancan desde una imagen conocida.
  • Simplifica el cumplimiento normativo: cada cambio en la imagen pasa por un pipeline de CI (GitHub Actions) con tests integrados.
  • Reduce la superficie de ataque: los nodos no pueden modificarse en runtime.

2. Gestión declarativa de clústeres con k0rdent y k0smotron

k0rdent es un control plane nativo de Kubernetes para gestionar clústeres (basado en Cluster API). Con él, puedes:

  • Definir clústeres como CRDs (Custom Resource Definitions).
  • Automatizar provisionamiento, actualizaciones y decomisionamiento usando GitOps (FluxCD).
  • Usar k0s como distribución Kubernetes: un binario único que no depende de gestores de paquetes ni systemd.
¿Por qué es útil?
  • Consistencia cross-cloud: el mismo modelo CRD funciona en VMware, AWS, GCP, etc.
  • Auditoría por diseño: todo el estado del clúster (incluido el control plane) se gestiona en Git.
  • Flexibilidad para casos especiales: como absorber capacidad spot de servidores físicos donados.

3. Integración con DNS enterprise usando bindy

En entornos financieros, el DNS no es un commodity: está integrado con infraestructura legacy (ej. Infoblox). bindy resuelve el cuello de botella:

  • DNS como un recurso Kubernetes: cada Service o Ingress genera automáticamente registros DNS.
  • Provisionamiento en segundos (vs. horas/días con tickets).
  • Auditoría en Git: todos los cambios quedan registrados en el historial del repositorio.
¿Por qué es útil?
  • Elimina la dependencia de equipos externos para cambios de DNS.
  • Integra Kubernetes con sistemas legacy sin romper flujos de trabajo existentes.

Prerequisitos

Requisitos técnicos

ComponenteVersión mínimaNotas
**Kubernetes**1.28+Cluster de gestión (management cluster)
**FluxCD**2.3.0+Para reconciliación GitOps
**Kairos**3.0.0+Usaremos la imagen base BLOCK24
**k0rdent**0.5.0+Incluye dependencias como Cluster API
**k0smotron**0.4.0+Para control planes in-cluster
**bindy**0.3.0+Operador en Rust (compilado para Linux)
**GitHub Actions**Para pipelines de CI de imágenes Kairos
**VirtRigaud**0.2.0+Operador para VMs declarativas
### Permisos y accesos
  1. Repositorio Git: Acceso de escritura para FluxCD y GitHub Actions.
  2. Registry privado: Para almacenar imágenes Kairos (ej. Harbor, Harbor Enterprise, o Quay).
  3. Cluster de gestión: Debe tener permisos para instalar operadores (ClusterRole cluster-admin).
  4. Hypervisor (vSphere/KVM): Credenciales para VirtRigaud (aisladas en un Secret de Kubernetes).
  5. Infoblox (DNS): API key o credenciales para bindy (almacenadas en un Secret con permisos mínimos).

Arquitectura de referencia

[GitHub] → [GitHub Actions] → [OCI Image (Kairos)] → [Registry]
       ↓
[FluxCD] → [Kairos Nodes (VMs)] → [k0s] → [k0rdent/k0smotron] → Clústeres
       ↓
[bindy] → [Infoblox DNS] → Registros automáticos para Services/Ingress

Guía paso a paso

Paso 1: Configurar el pipeline de construcción de imágenes Kairos

Objetivo: Automatizar la construcción de imágenes OCI para nodos, con tests integrados y publicación en tu registry.
  1. Clonar el repositorio de Kairos:
   git clone https://github.com/kairos-io/kairos-core.git
   cd kairos-core
   
  1. Editar .github/workflows/build.yml para usar tu base RHEL y tu registry:
   name: Build Kairos Image
   on:
     push:
       branches: [ main ]
     schedule:
       - cron: '0 0 * * *'  # Nightly build

   jobs:
     build:
       runs-on: ubuntu-latest
       steps:
         - uses: actions/checkout@v4
         - name: Build Kairos image
           run: |
             docker build \
               --build-arg BASE_IMAGE=registry.access.redhat.com/ubi9/ubi \
               -t ghcr.io/tu-org/kairos-node:ubi9-$(date +%Y%m%d) \
               -f Dockerfile .
         - name: Run integration tests
           run: |
             # Ejecutar tests en una VM efímera (usar QEMU)
             qemu-system-x86_64 -m 2G -kernel ./vmlinuz -initrd ./initrd.img \
               -append "console=ttyS0" -nographic -drive file=./disk.qcow2,format=qcow2
             # Validar que el nodo se registre en el cluster de gestión
             kubectl get nodes | grep -q kairos-node
         - name: Publish image
           run: |
             echo "${{ secrets.REGISTRY_TOKEN }}" | docker login ghcr.io -u USERNAME --password-stdin
             docker push ghcr.io/tu-org/kairos-node:ubi9-$(date +%Y%m%d)
   
  1. Resultado esperado:
– Una imagen OCI publicada en ghcr.io/tu-org/kairos-node:ubi9-YYYYMMDD.

– Tests integrados que validan:

– Boot correcto.

– Registro automático en el clúster de gestión (usando k3s o k0s).

– Configuración de red y autenticación (SSSD/AD).

Error común: Si los tests fallan, verifica que el kernel y los módulos necesarios (ej. virtio_net) estén incluidos en la imagen. Usa dracut para regenerar el initramfs:
   dracut --force --add-drivers "virtio_net" /boot/initramfs-$(uname -r).img $(uname -r)
   

Paso 2: Registrar la imagen Kairos como un VMImage en VirtRigaud

Objetivo: Hacer que la imagen OCI sea consumible por VirtRigaud para provisionar VMs.
  1. Crear un Secret para credenciales de vSphere (si usas VMware):
   kubectl create secret generic vsphere-creds \
     [email protected] \
     --from-literal=password='TU_PASSWORD' \
     --from-literal=server=vcsa.tudominio.com
   
  1. Definir el VMImage CRD (ejemplo para vSphere):
   # kairos-vmimage.yaml
   apiVersion: virt.iguazio.com/v1alpha1
   kind: VMImage
   metadata:
     name: kairos-ubi9
     namespace: platform
   spec:
     provider: vsphere
     url: https://github.com/tu-org/kairos-node/releases/download/ubi9-20240513/kairos-node-ubi9.qcow2
     checksum: sha256:abc123...  # Obtener con `sha256sum kairos-node-ubi9.qcow2`
     format: qcow2
     storagePolicy: "Thin Provision"
   
  1. Aplicar con FluxCD:
   flux create source git platform-images \
     --url=https://github.com/tu-org/platform-manifests.git \
     --branch=main
   flux create kustomization kairos-images \
     --source=platform-images \
     --path=./clusters/base/vmimages \
     --prune=true
   
  1. Resultado esperado:
– La imagen aparece en el catálogo de VirtRigaud:
     kubectl get vmimages -n platform
     NAME            PROVIDER   STATUS
     kairos-ubi9     vsphere     Ready
     

Paso 3: Definir nodos Kairos como VirtualMachine CRDs

Objetivo: Provisionar VMs con Kairos usando VirtRigaud.
  1. Crear un VirtualMachine CRD (ejemplo para un nodo worker):
   # kairos-worker-01.yaml
   apiVersion: virt.iguazio.com/v1alpha1
   kind: VirtualMachine
   metadata:
     name: kairos-worker-01
     namespace: platform
     labels:
       cluster: prod-01
   spec:
     image: kairos-ubi9  # Referencia al VMImage anterior
     flavor:
       cpu: 4
       memory: 8Gi
     network:
       - name: "VM Network"
         mac: "00:00:00:00:00:01"
     cloudInit: |
       #cloud-config
       hostname: kairos-worker-01
       users:
         - name: admin
           ssh-authorized-keys:
             - ssh-rsa AAAAB3NzaC1yc2E...
       write_files:
         - path: /etc/systemd/system/kubelet.service.d/10-kubelet.conf
           content: |
             [Service]
             Environment="KUBELET_EXTRA_ARGS=--node-labels=node-role.kubernetes.io/worker=true"
       runcmd:
         - systemctl enable --now kubelet
   
  1. Aplicar con FluxCD:
   flux create kustomization kairos-vms \
     --source=platform-images \
     --path=./clusters/base/nodes \
     --prune=true
   
  1. Verificar el nodo en Kubernetes:
   kubectl get nodes -w
   # Esperar a que aparezca: NAME                STATUS   ROLES    AGE
   #                     kairos-worker-01     Ready    <none>   2m
   
Error común: Si el nodo no se registra, verifica:

– Que el cloud-config incluya el comando para unirse al clúster (ej. k3s-agent --server https://<IP_MASTER>).

– Que el firewall (firewalld) permita tráfico en el puerto 6443 (Kubernetes API).

Paso 4: Instalar k0rdent y k0smotron para gestión de clústeres

Objetivo: Automatizar el provisionamiento de clústeres de Kubernetes.
  1. Instalar dependencias (Cluster API):
   kubectl apply -f https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.6.1/cluster-api-components.yaml
   
  1. Instalar k0rdent:
   helm repo add k0rdent https://charts.k0rdent.io
   helm install k0rdent k0rdent/k0rdent \
     --namespace k0rdent-system \
     --create-namespace \
     --version 0.5.0
   
  1. Definir un ClusterTemplate (ejemplo para clústeres en VMware):
   # cluster-template.yaml
   apiVersion: k0rdent.mirantis.com/v1alpha1
   kind: ClusterTemplate
   metadata:
     name: k0s-vmware
     namespace: platform
   spec:
     kubernetesVersion: "v1.28.0+k0s"
     controlPlane:
       replicas: 1
       machineTemplate:
         infrastructureTemplate:
           apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
           kind: VSphereMachineTemplate
           name: k0s-controlplane-vmware
     workers:
       - replicas: 3
         machineTemplate:
           infrastructureTemplate:
             apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
             kind: VSphereMachineTemplate
             name: k0s-worker-vmware
   
  1. Crear un clúster con FluxCD:
   flux create source git cluster-manifests \
     --url=https://github.com/tu-org/platform-manifests.git \
     --branch=main
   flux create kustomization prod-cluster-01 \
     --source=cluster-manifests \
     --path=./clusters/prod/cluster-01 \
     --prune=true
   
  1. Resultado esperado:
– Un clúster prod-01 con 1 control plane y 3 workers, usando k0s.

– Verificar con:

     k0s kubectl get nodes
     kubectl get clusters -A
     
Consideración: Si usas k0smotron para control planes in-cluster, instala:
   kubectl apply -f https://github.com/k0sproject/k0smotron/releases/download/v0.4.0/k0smotron.yaml
   

Paso 5: Implementar bindy para integración con Infoblox

Objetivo: Automatizar la creación de registros DNS para Services e Ingress.
  1. Crear un Secret para Infoblox (con permisos mínimos):
   kubectl create secret generic infoblox-creds \
     --from-literal=username=api-user \
     --from-literal=password='API_PASSWORD' \
     --from-literal=wapi-version=2.11 \
     --from-literal=host=infoblox.tudominio.com
   
  1. Instalar bindy:
   kubectl apply -f https://github.com/erickbourgeois/bindy/releases/download/v0.3.0/bindy.yaml
   
  1. Definir un DNSPolicy (para un clúster específico):
   # dns-policy.yaml
   apiVersion: bindy.io/v1alpha1
   kind: DNSPolicy
   metadata:
     name: prod-01-dns
     namespace: prod-01
   spec:
     zone: "prod.tudominio.com"
     provider: infoblox
     ttl: 300
   
  1. Crear un Service con anotaciones para bindy:
   # ingress-example.yaml
   apiVersion: v1
   kind: Service
   metadata:
     name: nginx
     namespace: prod-01
     annotations:
       bindy.io/dns-record: "nginx.prod"
       bindy.io/ttl: "300"
   spec:
     ports:
       - port: 80
     selector:
       app: nginx
   
  1. Resultado esperado:
– Un registro DNS nginx.prod.tudominio.com creado en Infoblox en segundos.

– Verificar con:

     kubectl get dnsrecords -A
     dig nginx.prod.tudominio.com
     
Error común: Si los registros no se crean, verifica:

– Que el DNSPolicy esté aplicado al namespace correcto.

– Que bindy tenga permisos para leer Services e Ingress (RBAC).

Consideraciones y buenas prácticas

1. Seguridad en entornos regulados

  • Imágenes minimalistas: Usa scratch o distroless para componentes críticos (ej. bindy).
  • Firma de imágenes: Implementa cosign o Notary para validar imágenes antes de desplegar.
  • Network Policies: Aplica políticas estrictas en los clústeres para segmentar tráfico entre namespaces.

2. Manejo de secretos

  • Evita hardcodear credenciales: Usa Sealed Secrets o Vault CSI Driver para encriptar secretos en Git.
  • Rotación automática: Configura renovación de tokens de Infoblox y credenciales de vSphere con cert-manager.

3. Escalabilidad y rendimiento

  • k0rdent + k0smotron: Para clústeres con >50 nodos, considera usar Cluster API con CAPV (vSphere) para optimizar provisionamiento.
  • bindy: Para entornos con miles de registros DNS, usa etcd como backend en lugar de Infoblox (consulta la documentación de bindy).

4. Alternativas y trade-offs

ComponenteAlternativaTrade-off
**Kairos**Flatcar LinuxMenos integrado con Cloud Config
**k0s**k3sk3s tiene más dependencias de OS
**VirtRigaud**Cluster API VMMenos flexible para multi-hypervisor
**bindy**CoreDNS + pluginsMenos features enterprise (ej. GSLB)
## Conclusión

Con esta arquitectura, logramos:

  1. Nodos inmutables con Kairos, gestionados como código y auditables.
  2. Clústeres declarativos con k0rdent/k0smotron, escalables a cientos de nodos.
  3. DNS integrado con Infoblox, eliminando cuellos de botella operativos.
Próximos pasos:
  • Automatizar rollouts de imágenes Kairos con canary deployments.
  • Implementar policy enforcement con OPA/Gatekeeper para cumplir con PCI-DSS.
  • Extender bindy para soportar DNSSEC en entornos críticos.

Esta solución es reproducible en cualquier institución financiera o regulada, donde la auditoría y la seguridad son prioritarias.

Fuentes

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *