Problema
Los entornos homelab cada vez incorporan servidores basados en ARM, pero la mayoría de los manifiestos, operadores y pipelines siguen diseñados para x86. Cuando se sustituye el hardware tradicional por nodos Ampere Q80‑30 o similares, aparecen fallos de compatibilidad: imágenes sin soporte arm64, CRDs que asumen arquitectura x86, y políticas de scheduling que no distribuyen correctamente los pods. El síntoma típico es que el clúster arranca, pero varios componentes (por ejemplo, ClickHouse Operator o Harbor) no se despliegan, o los pods quedan en Pending con mensajes de “no matching node”.
Causa
- Imágenes Docker mono‑arch – Muchos charts usan imágenes construidas solo para amd64. En ARM los contenedores no arrancan y el scheduler los marca como incompatibles.
- Operadores sin binaries arm64 – Algunos operadores descargan binarios precompilados para x86 en tiempo de instalación (por ejemplo, ciertos plugins de Barman o el controlador de NATS).
- Node affinity rígida – Manifiestos que fijan
nodeSelector.kubernetes.io/arch: amd64o que usannodeAffinitycon valores hard‑coded impiden que los pods se programen en los nuevos nodos. - CNI/BGP configurado para interfaces específicas – En clusters mixtos, Cilium o Calico pueden estar atados a nombres de interfaces que solo existen en la placa base x86, provocando pérdida de conectividad.
- Herramientas de CI/CD que generan imágenes solo para la arquitectura del runner – Si el pipeline de BuildKit corre en un nodo x86,
docker buildproducirá imágenes amd64 por defecto, lo que rompe la cadena de despliegue en ARM.
Solución
1. Preparar la capa de imágenes multi‑arch
- Buildx: habilitar un builder con soporte para
linux/amd64,linux/arm64. - Publicar ambas variantes bajo la misma etiqueta; Kubernetes elegirá la adecuada según el nodo.
- Para charts que no ofrecen versiones multi‑arch, crear una fork mínima que reemplace la imagen con una construida localmente.
2. Auditar operadores y componentes críticos
- Revisar cada CRD que instala binarios externos.
- Si el proyecto no publica arm64, compilar desde fuente o buscar forks que lo hagan.
- Documentar los binarios en un
ConfigMapy montar comoemptyDirpara que el pod los encuentre.
3. Normalizar los selectors de arquitectura
- Reemplazar
nodeSelector.kubernetes.io/arch: amd64por una variable de plantilla que se resuelva en tiempo de renderizado. - Usar
nodeSelector.kubernetes.io/arch: {{ .Values.arch }}y definirarch: arm64envalues.yamlpara los nodos ARM. - Añadir
tolerationsgenéricas y dejar que el scheduler decida.
4. Ajustar la CNI
- En Cilium, habilitar
enable-ipv4=trueyenable-ipv6=false(o viceversa) sin referir nombres de interfaces. - Configurar BGP con
nodePortdinámico y evitar hard‑coding deeth0. - Verificar que el
daemonsetde Cilium se despliegue en ambos tipos de nodo; si no, añadirnodeSelector.kubernetes.io/arch: arm64al daemonset.
5. Re‑configurar la pipeline de CI/CD
- En los runners de GitHub Actions, GitLab CI o cualquier otro, instalar
docker buildxy crear un builder con--platform linux/arm64. - Modificar los
Dockerfilepara usarARG TARGETARCHy copiar binarios específicos según la arquitectura. - En los jobs de Flux, habilitar
--kustomize-build-options=--load-restrictor=LoadRestrictionsNonepara que los manifests se apliquen sin validar la arquitectura del contenedor.
6. Validar la migración con Flux y Talos
- Talos no depende de la arquitectura del kernel; sin embargo, los
machineconfigdeben apuntar a la versión de firmware adecuada para Ampere. - Flux Operator permite declarar
Kustomizationpor arquitectura; crear dosKustomizationdistintas (una para amd64, otra para arm64) y usardependsOnpara asegurar el orden correcto.
Cuándo aplicar esta solución
- Síntomas: pods en
Pendingcon mensaje “no nodes match pod’s node selector”, errores de descarga de binarios durante la instalación de operadores, o fallos dedocker pullpor “manifest unknown”. - Entorno: clústeres bare‑metal o on‑premise con nodos mixtos x86/arm64, usando Talos, Flux y Cilium.
- No aplica: clusters totalmente gestionados (EKS, GKE) donde la capa de infraestructura ya garantiza imágenes multi‑arch y los operadores están pre‑compilados para ambas arquitecturas.
Código
# Crear builder multi‑arch
docker buildx create --use --name multiarch-builder
# Habilitar plataformas
docker buildx inspect --bootstrap
# Construir y publicar ambas variantes
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myrepo/app:latest \
--push .
Verificación
- Ejecutar
kubectl get nodes -o widey confirmar que la columnaARCHmuestraarm64en los nuevos servidores. - Desplegar un pod de prueba con imagen oficial multi‑arch (por ejemplo,
nginx:alpine) y observar que el contenedor arranca sin errores. - Revisar los logs de Cilium (
kubectl -n kube-system logs ds/cilium) para asegurarse de que no haya mensajes de “interface not found”. - Ejecutar
flux get kustomizationsy validar que los objetos de cada arquitectura aparecen con estadoready. - En la pipeline de CI, observar que el artefacto Docker tiene ambas manifest entries (
docker manifest inspect myrepo/app:latest).
Notas adicionales
- Algunas imágenes de terceros (Harbor, Gitea) todavía no ofrecen builds oficiales para arm64. En esos casos, la alternativa más estable es usar la versión
scratchy compilar desde código fuente. - Cuando se usan GPUs (RTX 3090) en nodos x86 y se combinan con nodos ARM, los pods que requieren CUDA deben tener
nodeSelector.kubernetes.io/arch: amd64explícito; de lo contrario el scheduler los enviará a nodos sin GPU y fallarán. - Mantener una rama de
values.yamlpor arquitectura simplifica la gestión de Helm; usarhelmfilepara orquestar la aplicación simultánea de ambas versiones. - Si el clúster está conectado a un NAS con NVMe‑of, verifica que el driver CSI sea compatible con arm64; la mayoría de los plugins de Longhorn ya lo son, pero versiones muy antiguas pueden requerir recompilación.
Con estos pasos el clúster homelab pasa de depender exclusivamente de Intel/AMD a aprovechar la densidad y eficiencia energética de los procesadores Ampere, sin perder funcionalidad en los operadores críticos ni en los pipelines de CI/CD.