--- title: "Argo CD multi-clúster con ApplicationSets, RBAC y alertas" description: "Registra varios clústeres en Argo CD, despliega en todos con ApplicationSets, ordena recursos con sync waves y hooks, aplica RBAC y recibe avisos en Slack." category: "Ecosistema Kubernetes" language: es source: https://cubepath.com/es/docs/ecosistema-kubernetes/configuracion-avanzada-de-argocd-multi-cluster updated: 2026-09-25 --- # Argo CD multi-clúster con ApplicationSets, RBAC y alertas Argo CD es la herramienta GitOps de la CNCF que mantiene el estado de Kubernetes sincronizado con lo que hay en un repositorio Git. Una sola instancia puede gestionar muchos clústeres: el clúster donde está instalada actúa como plano de control y el resto se registran como destinos. En este tutorial registrarás dos clústeres remotos, desplegarás la misma aplicación en todos con un ApplicationSet, controlarás el orden de despliegue con sync waves y hooks, restringirás permisos con proyectos y RBAC, y configurarás avisos en Slack. ## Requisitos previos Para seguir esta guía necesitas: - Argo CD 2.8 o superior (los ejemplos se han escrito para Argo CD 3.x) instalado en un clúster de gestión, en el namespace `argocd`, y accesible desde tu equipo en `argocd.tu_dominio` o mediante port-forward. - Uno o más clústeres Kubernetes adicionales como destino, con sus contextos en tu `~/.kube/config`. En esta guía se llaman `staging` y `produccion-eu`. - `kubectl` configurado para el clúster de gestión, con permisos de administrador. - Un repositorio Git con manifiestos de Kubernetes o overlays de Kustomize. En los ejemplos se usa `https://github.com/tu_organizacion/k8s-manifests.git`. - Para el paso de notificaciones: un workspace de Slack donde puedas crear una app con un token de bot. ## Paso 1: Instalar el CLI de Argo CD e iniciar sesión Descarga el binario de la última versión estable e instálalo en `/usr/local/bin`: ```bash curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd rm argocd-linux-amd64 ``` Comprueba la versión del cliente: ```bash argocd version --client --short ``` Obtén la contraseña inicial del usuario `admin`, que Argo CD genera en la instalación: ```bash argocd admin initial-password -n argocd ``` Inicia sesión contra el servidor de Argo CD con esa contraseña: ```bash argocd login argocd.tu_dominio --username admin ``` ```output 'admin:login' logged in successfully Context 'argocd.tu_dominio' updated ``` Si no tienes Argo CD expuesto con un Ingress, abre un port-forward en otra terminal con `kubectl -n argocd port-forward svc/argocd-server 8080:443` y usa `argocd login localhost:8080 --insecure`. > Importante: cambia la contraseña con `argocd account update-password` y borra después el Secret `argocd-initial-admin-secret` del namespace `argocd`. ## Paso 2: Registrar los clústeres de destino `argocd cluster add` crea en el clúster remoto una ServiceAccount `argocd-manager` con permisos de administrador y guarda sus credenciales en un Secret del clúster de gestión. Las etiquetas que añadas al registrarlo son las que usarán después los ApplicationSets para decidir dónde desplegar. Lista los contextos disponibles en tu kubeconfig: ```bash kubectl config get-contexts -o name ``` Registra cada clúster con un nombre legible y etiquetas de entorno y región: ```bash argocd cluster add staging --name staging --label env=staging --label region=eu argocd cluster add produccion-eu --name produccion-eu --label env=produccion --label region=eu ``` Argo CD te pedirá confirmación antes de crear la ServiceAccount en cada clúster. Comprueba que están registrados: ```bash argocd cluster list ``` ```output SERVER NAME VERSION STATUS MESSAGE PROJECT https://10.0.10.10:6443 staging Unknown Cluster has no applications and is not being monitored. https://10.0.20.10:6443 produccion-eu Unknown Cluster has no applications and is not being monitored. https://kubernetes.default.svc in-cluster 1.33 Successful ``` El estado `Unknown` es normal hasta que haya alguna aplicación desplegada en ese clúster. Las etiquetas se guardan en el Secret del clúster; puedes verlas con: ```bash kubectl -n argocd get secrets -l argocd.argoproj.io/secret-type=cluster --show-labels ``` ## Paso 3: Crear un proyecto para limitar destinos Un `AppProject` define qué repositorios se pueden usar, en qué clústeres y namespaces se puede desplegar y qué tipos de recursos se permiten. Es la base del RBAC: los permisos se conceden por proyecto. ```bash nano proyecto-web.yaml ``` ```yaml apiVersion: argoproj.io/v1alpha1 kind: AppProject metadata: name: web namespace: argocd spec: description: Aplicaciones web desplegadas en staging y producción sourceRepos: - https://github.com/tu_organizacion/k8s-manifests.git destinations: - name: staging namespace: web-* - name: produccion-eu namespace: web-* clusterResourceWhitelist: - group: "" kind: Namespace ``` Con esta configuración, las aplicaciones del proyecto `web` solo pueden desplegar desde ese repositorio, en namespaces que empiecen por `web-` y en los dos clústeres registrados. El único recurso de ámbito de clúster permitido es `Namespace`. ```bash kubectl apply -f proyecto-web.yaml argocd proj get web ``` ## Paso 4: Desplegar en varios clústeres con un ApplicationSet Un `ApplicationSet` genera objetos `Application` a partir de una plantilla y un generador. El generador `clusters` produce una aplicación por cada clúster registrado que cumpla un selector de etiquetas, así que un clúster nuevo recibe la aplicación en cuanto lo registras con la etiqueta adecuada. Este ejemplo supone que el repositorio tiene overlays de Kustomize en `apps/frontend/overlays/staging` y `apps/frontend/overlays/produccion`: ```bash nano appset-frontend.yaml ``` ```yaml apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: frontend namespace: argocd spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: matchExpressions: - key: env operator: In values: ["staging", "produccion"] template: metadata: name: "frontend-{{.name}}" spec: project: web source: repoURL: https://github.com/tu_organizacion/k8s-manifests.git targetRevision: main path: "apps/frontend/overlays/{{index .metadata.labels \"env\"}}" destination: server: "{{.server}}" namespace: web-frontend syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true ``` Las variables disponibles con el generador `clusters` son, entre otras, `.name` y `.server` del clúster y `.metadata.labels` con sus etiquetas. `missingkey=error` hace que el ApplicationSet falle de forma visible si una plantilla usa una variable inexistente, en vez de generar una ruta vacía. ```bash kubectl apply -f appset-frontend.yaml ``` Comprueba que se ha generado una aplicación por clúster y que se sincronizan: ```bash argocd appset get frontend argocd app list ``` ```output NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY argocd/frontend-produccion-eu https://10.0.20.10:6443 web-frontend web Synced Healthy Auto-Prune argocd/frontend-staging https://10.0.10.10:6443 web-frontend web Synced Healthy Auto-Prune ``` ### Una aplicación por carpeta con el generador Git Si el repositorio tiene una carpeta por aplicación, el generador `git` con `directories` crea una `Application` por carpeta y se actualiza solo cuando añades o borras carpetas. Este ejemplo despliega todo lo que haya bajo `apps/` en el clúster de gestión, excepto `apps/experimental`: ```bash nano appset-carpetas.yaml ``` ```yaml apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: apps-por-carpeta namespace: argocd spec: goTemplate: true goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/tu_organizacion/k8s-manifests.git revision: main directories: - path: "apps/*" - path: "apps/experimental" exclude: true template: metadata: name: "{{.path.basename}}" spec: project: default source: repoURL: https://github.com/tu_organizacion/k8s-manifests.git targetRevision: main path: "{{.path.path}}" destination: name: in-cluster namespace: "{{.path.basename}}" syncPolicy: syncOptions: - CreateNamespace=true ``` ```bash kubectl apply -f appset-carpetas.yaml argocd appset get apps-por-carpeta ``` Los generadores se pueden combinar con `matrix` para desplegar cada carpeta en cada clúster, pero empieza con un solo generador hasta que el resultado sea el esperado. ## Paso 5: Ordenar el despliegue con sync waves y hooks Por defecto Argo CD aplica los recursos en un orden fijo por tipo (namespaces, luego ConfigMaps y Secrets, luego Deployments...). Cuando necesitas un orden propio, por ejemplo que una base de datos esté lista antes que la aplicación, usa la anotación `argocd.argoproj.io/sync-wave`. Argo CD aplica las olas de menor a mayor y espera a que los recursos de una ola estén sanos antes de pasar a la siguiente. Estas anotaciones van en los manifiestos del repositorio Git, no se aplican a mano con `kubectl`. Por ejemplo, en el StatefulSet de la base de datos: ```yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: postgresql annotations: argocd.argoproj.io/sync-wave: "0" ``` Y en el Deployment de la aplicación: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: frontend annotations: argocd.argoproj.io/sync-wave: "1" ``` Los recursos sin anotación pertenecen a la ola `0`. Puedes usar valores negativos para lo que debe ir antes de todo. Los **hooks** son recursos que Argo CD ejecuta en un momento concreto de la sincronización en lugar de mantenerlos desplegados. El caso típico es un `Job` que ejecuta las migraciones de la base de datos antes de actualizar la aplicación. Añade este archivo al mismo directorio del repositorio: ```yaml apiVersion: batch/v1 kind: Job metadata: name: migraciones annotations: argocd.argoproj.io/hook: PreSync argocd.argoproj.io/hook-delete-policy: BeforeHookCreation spec: backoffLimit: 1 template: spec: restartPolicy: Never containers: - name: migrate image: registry.tu_dominio/frontend:1.4.2 command: ["python", "manage.py", "migrate"] envFrom: - secretRef: name: frontend-db ``` Con `PreSync`, Argo CD crea el Job, espera a que termine y solo entonces aplica el resto de recursos. Si el Job falla, la sincronización se detiene y la versión anterior sigue en marcha. `BeforeHookCreation` borra el Job de la ejecución anterior justo antes de crear el nuevo, así que siempre puedes consultar los logs de la última migración. Tras hacer commit y push, comprueba el orden en la sincronización: ```bash argocd app sync frontend-staging argocd app get frontend-staging ``` En la salida verás el Job `migraciones` con fase `PreSync` completado antes que el resto de recursos. ## Paso 6: Configurar el RBAC Los permisos de Argo CD se definen en el ConfigMap `argocd-rbac-cm`. Cada línea `p` concede una acción sobre un recurso, y las líneas `g` asignan roles a usuarios o a grupos de tu proveedor SSO. Para aplicaciones, el objeto tiene la forma `/`. ```bash nano argocd-rbac-cm.yaml ``` ```yaml apiVersion: v1 kind: ConfigMap metadata: name: argocd-rbac-cm namespace: argocd labels: app.kubernetes.io/name: argocd-rbac-cm app.kubernetes.io/part-of: argocd data: policy.default: role:readonly policy.csv: | # Desarrolladores: ver todo, sincronizar y reiniciar solo en el proyecto web p, role:desarrollador, applications, get, web/*, allow p, role:desarrollador, applications, sync, web/*, allow p, role:desarrollador, applications, action/apps/Deployment/restart, web/*, allow p, role:desarrollador, logs, get, web/*, allow # SRE: control total de las aplicaciones y lectura de clústeres p, role:sre, applications, *, */*, allow p, role:sre, clusters, get, *, allow # Grupos del proveedor SSO g, tu_organizacion:developers, role:desarrollador g, tu_organizacion:sre, role:sre g, tu_organizacion:platform, role:admin ``` `policy.default: role:readonly` da acceso de solo lectura a cualquier usuario autenticado que no tenga otro rol. Si prefieres que no vean nada, deja ese campo vacío. Antes de aplicarlo, valida la sintaxis y comprueba un permiso concreto con el propio CLI: ```bash argocd admin settings rbac validate --policy-file argocd-rbac-cm.yaml argocd admin settings rbac can role:desarrollador sync applications 'web/frontend-staging' --policy-file argocd-rbac-cm.yaml ``` ```output Yes ``` ```bash kubectl apply -f argocd-rbac-cm.yaml ``` Los cambios se aplican sin reiniciar nada. Un usuario puede comprobar sus propios permisos con `argocd account can-i sync applications 'web/frontend-staging'`. ## Paso 7: Recibir avisos en Slack El controlador de notificaciones viene incluido en Argo CD desde la versión 2.3. Solo tienes que configurar el servicio y elegir qué eventos quieres recibir. Instala el catálogo oficial de triggers y plantillas (`on-sync-failed`, `on-deployed`, `on-health-degraded`...). Este comando sustituye el ConfigMap `argocd-notifications-cm`, así que hazlo antes de añadir configuración propia: ```bash kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/notifications_catalog/install.yaml ``` Crea una app en Slack con el permiso `chat:write`, instálala en el workspace, invita al bot a los canales y guarda su token en el Secret de notificaciones: ```bash kubectl -n argocd patch secret argocd-notifications-secret --type merge \ -p '{"stringData":{"slack-token":"xoxb-tu_token_de_slack"}}' ``` Añade el servicio Slack al ConfigMap. `$slack-token` hace referencia a la clave del Secret, no al token en claro: ```bash kubectl -n argocd patch configmap argocd-notifications-cm --type merge \ -p '{"data":{"service.slack":"token: $slack-token\n"}}' ``` Suscribe las aplicaciones a los eventos. Para las generadas por un ApplicationSet, añade la anotación en `template.metadata.annotations` del ApplicationSet; si la pones directamente sobre la `Application`, el controlador la eliminará en la siguiente reconciliación: ```yaml template: metadata: name: "frontend-{{.name}}" annotations: notifications.argoproj.io/subscribe.on-sync-failed.slack: alertas-despliegues notifications.argoproj.io/subscribe.on-health-degraded.slack: alertas-despliegues notifications.argoproj.io/subscribe.on-deployed.slack: despliegues ``` Aplica de nuevo el ApplicationSet y fuerza un despliegue para comprobar que llega el mensaje: ```bash kubectl apply -f appset-frontend.yaml argocd app sync frontend-staging ``` Si no llega nada, revisa los logs del controlador: ```bash kubectl -n argocd logs deploy/argocd-notifications-controller --tail=50 ``` ## Solución de problemas **El ApplicationSet no genera aplicaciones.** Revisa la sección `status.conditions` con `kubectl -n argocd describe applicationset frontend`. Con `missingkey=error`, un error de plantilla aparece ahí. Con el generador `clusters`, confirma que las etiquetas del Secret del clúster coinciden con el selector. **`argocd cluster add` falla con `context not found`.** El argumento es el nombre del contexto de kubeconfig, no el del clúster. Consúltalo con `kubectl config get-contexts -o name`. **Una aplicación se queda `OutOfSync` tras sincronizar.** Algún controlador del clúster está modificando campos después de aplicarlos (réplicas gestionadas por un HPA, anotaciones añadidas por un webhook). Consulta la diferencia con `argocd app diff ` y excluye esos campos con `ignoreDifferences` en la plantilla. **Error `application destination ... is not permitted in project`.** El destino no está en `spec.destinations` del `AppProject`, o el namespace no coincide con el patrón. Ajusta el proyecto en lugar de mover la aplicación a `default`. ## Conclusión Con esta configuración, una única instancia de Argo CD despliega la misma aplicación en todos los clústeres etiquetados, respeta el orden entre base de datos, migraciones y aplicación, limita qué puede hacer cada equipo y avisa en Slack cuando algo falla. Como siguientes pasos, conecta Argo CD a tu proveedor SSO para que los grupos del RBAC sean reales, guarda los Secrets en Git de forma segura con Sealed Secrets o External Secrets Operator, y valora Argo Rollouts si necesitas despliegues canary o blue-green.