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.
- 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.
- 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
ServiceoIngressgenera 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.
- 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
| Componente | Versión mínima | Notas |
|---|---|---|
| **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 |
- Repositorio Git: Acceso de escritura para FluxCD y GitHub Actions.
- Registry privado: Para almacenar imágenes Kairos (ej. Harbor, Harbor Enterprise, o Quay).
- Cluster de gestión: Debe tener permisos para instalar operadores (ClusterRole
cluster-admin). - Hypervisor (vSphere/KVM): Credenciales para VirtRigaud (aisladas en un
Secretde Kubernetes). - Infoblox (DNS): API key o credenciales para bindy (almacenadas en un
Secretcon 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/IngressGuí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.- Clonar el repositorio de Kairos:
git clone https://github.com/kairos-io/kairos-core.git
cd kairos-core
- Editar
.github/workflows/build.ymlpara 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)
- Resultado esperado:
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.- Crear un
Secretpara 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
- Definir el
VMImageCRD (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"
- 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
- Resultado esperado:
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.- Crear un
VirtualMachineCRD (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
- Aplicar con FluxCD:
flux create kustomization kairos-vms \
--source=platform-images \
--path=./clusters/base/nodes \
--prune=true
- 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.- Instalar dependencias (Cluster API):
kubectl apply -f https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.6.1/cluster-api-components.yaml
- Instalar k0rdent:
helm repo add k0rdent https://charts.k0rdent.io
helm install k0rdent k0rdent/k0rdent \
--namespace k0rdent-system \
--create-namespace \
--version 0.5.0
- 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
- 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
- Resultado esperado:
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 paraServices e Ingress.- Crear un
Secretpara 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
- Instalar bindy:
kubectl apply -f https://github.com/erickbourgeois/bindy/releases/download/v0.3.0/bindy.yaml
- 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
- Crear un
Servicecon 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
- Resultado esperado:
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
scratchodistrolesspara 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
| Componente | Alternativa | Trade-off |
|---|---|---|
| **Kairos** | Flatcar Linux | Menos integrado con Cloud Config |
| **k0s** | k3s | k3s tiene más dependencias de OS |
| **VirtRigaud** | Cluster API VM | Menos flexible para multi-hypervisor |
| **bindy** | CoreDNS + plugins | Menos features enterprise (ej. GSLB) |
Con esta arquitectura, logramos:
- Nodos inmutables con Kairos, gestionados como código y auditables.
- Clústeres declarativos con k0rdent/k0smotron, escalables a cientos de nodos.
- DNS integrado con Infoblox, eliminando cuellos de botella operativos.
- 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
- CNCF Blog: Building a cloud-native platform with Kairos, k0rdent, and bindy
- Kairos Documentation
- k0rdent GitHub
- bindy GitHub
- k0s Documentation
- VirtRigaud GitHub
