Cómo configuré ArgoCD para GitOps en Kubernetes: lo que nadie te cuenta
Source: Dev.to
Un viernes por la tarde, hace unos 14 meses…
Desplegué la versión incorrecta de nuestro servicio de pagos en producción. No fue un error de código — fue un error de proceso. Corrí:
kubectl apply -f .
desde mi laptop con cambios locales sin commitear, y durante 23 minutos el sistema respondió con errores 500. Cuatro personas en el equipo, silencio total en Slack, y yo mirando los logs sin saber exactamente qué había pasado.
La lección
Esa semana empecé a investigar GitOps de verdad. Revisé las dos opciones principales:
| Herramienta | Filosofía | Ventajas |
|---|---|---|
| Flux v2 | “Nativo de Kubernetes”: todo son CRDs y controladores pequeños. Ideal si te gusta componer piezas. | Muy ligero, fácil de integrar con pipelines. |
| Argo CD | UI bastante buena out‑of‑the‑box, modelo de Application más explícito, y más documentación de comunidad. | UI amigable, excelente para equipos pequeños que necesitan visibilidad sin usar la terminal. |
Para un equipo pequeño como el mío, la UI fue el factor decisivo. No porque sea indispensable, sino porque cuando alguien que no vive en la terminal necesita saber el estado de un despliegue, puede abrir un navegador en vez de pedirme que corra kubectl. Eso vale mucho.
(Hay una versión de este artículo donde termino eligiendo Flux. Depende mucho de si tu equipo ya tiene familiaridad con el modelo operacional de cada herramienta.)
Instalación rápida de Argo CD (ejemplo típico)
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Sí, funciona. Pero en mi setup (EKS en AWS, con un ALB Controller ya instalado) me encontré con problemas que hubiera gustado saber antes.
Problemas que encontré
-
Restricciones de red – En clústeres con egress limitado, el pod
argocd-serverno puede hacergit clonedesde dentro del clúster. Los logs no son descriptivos; la solución fue crear una regla de salida explícita en los security groups. -
Versión del manifiesto – La rama
stableno siempre apunta a la versión que esperas. Yo instalé Argo CD 2.9.3 creyendo que era más reciente. Verifica siempre la imagen que está corriendo:kubectl get pods -n argocd -o jsonpath='{range .items[*]}{.spec.containers[0].image}{"\n"}{end}'
Instalación con Helm (recomendado para producción)
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd \
--namespace argocd \
--create-namespace \
--version 6.7.3 \
--set server.service.type=ClusterIP \
--set configs.params."server\.insecure"=true
El flag server.insecure=true lo usé porque tenía terminación TLS en el ALB, no en Argo CD directamente. Si tu setup es diferente, probablemente no lo necesites.
Acceso inicial
# Obtén la contraseña inicial del admin
kubectl get secret argocd-initial-admin-secret \
-n argocd \
-o jsonpath="{.data.password}" | base64 -d
# Port‑forward para acceder localmente
kubectl port-forward svc/argocd-server -n argocd 8080:443
Dato curioso: la contraseña inicial está en el Secret
argocd-initial-admin-secret, que Argo CD borra automáticamente después de que la cambias por primera vez. Bien pensado, pero me agarró desprevenido cuando la busqué semanas después y ya no estaba.
Primeros pasos con GitOps en Argo CD
La idea: tienes un repositorio con tus manifiestos de Kubernetes (o charts de Helm, o Kustomize) y Argo CD observa ese repositorio y sincroniza el estado del clúster con él.
1. Registrar el repositorio
# Con SSH (mi preferencia)
argocd repo add git@github.com:tu-org/tu-repo-k8s.git \
--ssh-private-key-path ~/.ssh/id_rsa
# O con HTTPS y un token de GitHub
argocd repo add https://github.com/tu-org/tu-repo-k8s.git \
--username tu-usuario \
--password ghp_tu_token_aqui
2. Crear la primera Application
Puedes hacerlo desde la UI o con un manifiesto YAML — yo prefiero YAML porque vive en Git (GitOps hasta el final).
# argocd/apps/mi-servicio.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: mi-servicio
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/tu-org/tu-repo-k8s.git
targetRevision: main
path: manifests/mi-servicio
destination:
server: https://kubernetes.default.svc
namespace: mi-servicio
syncPolicy:
automated:
prune: true # Borra recursos que ya no están en Git
selfHeal: true # Revierte cambios manuales en el clúster
syncOptions:
- CreateNamespace=true
selfHeal: truehace que GitOps sea GitOps de verdad. Si alguien (yo, a las 11 pm, “solo para probar algo rápido”) hacekubectl editdirectamente en el clúster, Argo CD lo detecta y lo revierte. Al principio molesta; después lo agradeces.prune: truetambién merece atención. Con esta opción, si eliminas un manifiesto del repositorio, Argo CD elimina el recurso correspondiente del clúster. Sin ella, los recursos huérfanos se acumulan silenciosamente. Lo aprendí por las malas — teníaServices de versiones anteriores flotando sin utilidad.
Lección aprendida (y un poco vergonzosa)
Configuré Argo CD con sync automático habilitado y prune: true. Funcionó perfectamente durante semanas. Luego, durante una refactorización, moví varios manifiestos de directorio (reorganicé la estructura de carpetas del repositorio).
Argo CD detectó que los recursos en las rutas antiguas ya no existían en Git. Con prune: true, los borró.
Consejo: antes de mover o renombrar directorios, considera crear una temporada de pausa (
sync: off) o actualizar losApplicationcon los nuevos paths y aplicar unsyncmanual. De lo contrario, podrías perder recursos críticos si el proceso de migración no está bien coordinado.
Resumen rápido
- Elige la herramienta que mejor se adapte a tu equipo (Flux vs. Argo CD).
- Instala con Helm para mayor control y facilidad de upgrades.
- Configura egress y verifica la versión del manifiesto cuando trabajes en entornos con restricciones de red.
- Registra tu repositorio (SSH o HTTPS).
- Define
Applications en YAML y almacénalas en Git. - Habilita
selfHealyprunepara que el clúster siempre refleje el estado deseado. - Ten cuidado al reorganizar la estructura del repositorio; usa pausas o sincronizaciones manuales para evitar borrados inesperados.
Con estos pasos, tu clúster permanecerá alineado con la fuente de verdad y evitarás los temidos “errores 500” causados por despliegues manuales accidentales. 🚀
Lecciones de una migración de directorios con ArgoCD
Problema inicial
Los recursos en las rutas nuevas todavía no habían sido sincronizados. Durante cuatro minutos varios Deployments estuvieron en cero réplicas.
- El problema no fue ArgoCD — el comportamiento es exactamente el documentado.
- El problema fue que no había pensado en el orden de operaciones de una migración de estructura de directorios.
Qué debería haber hecho
- Deshabilitar el sync automático antes del PR.
- Hacer el merge de la reorganización.
- Sincronizar manualmente y verificar que todo esté correcto.
- Volver a habilitar el sync automático.
Tip: si vas a hacer cambios estructurales en tu repositorio de manifiestos, trata ese PR como si fuera una migración de base de datos: con cuidado, con un plan de rollback y, de preferencia, no un martes por la noche.
Sync windows
Desde entonces uso syncWindows para limitar cuándo ArgoCD puede sincronizar automáticamente en producción.
# Configurado en el Project de ArgoCD, no en la Application
spec:
syncWindows:
- kind: allow
schedule: '0 9-17 * * 1-5' # Solo horario laboral, lunes a viernes
duration: 8h
applications:
- 'produccion-*'
namespaces:
- produccion
Esto no es para todo el mundo. Si despliegas con mucha frecuencia fuera de horario, será un obstáculo. Pero para nuestro equipo, eliminar los syncs sorpresa a las 3 am valió la configuración extra.
Registro de clústeres externos
Tenemos tres clústeres: desarrollo, staging y producción.
ArgoCD corre en uno solo — producción, con acceso muy restringido — y gestiona los tres.
# Asegúrate de tener el contexto correcto en tu kubeconfig
kubectl config get-contexts
# Registra el clúster de staging
argocd cluster add arn:aws:eks:us-east-1:123456789:cluster/staging \
--name staging
Lo que la documentación no enfatiza suficientemente: el ServiceAccount que ArgoCD crea en el clúster remoto tiene permisos de cluster‑admin por defecto. Para empezar está bien, pero en producción querrás ajustar eso. Yo no lo hice hasta que alguien de seguridad me preguntó explícitamente — mejor enterarse antes de que te lo pregunten.
Gestión de secrets entre entornos
Una cosa que todavía no tengo completamente resuelta: la gestión de secrets entre entornos.
- Usamos AWS Secrets Manager con el External Secrets Operator.
- La integración con ArgoCD a veces produce sync states confusos cuando el external secret tarda en popularse.
No es exactamente un bug — es más una cuestión de timing y de cómo ArgoCD evalúa el health de los recursos. No estoy 100 % seguro de que nuestra solución actual escale bien más allá de los 12 servicios que tenemos ahora. Si alguien tiene una solución elegante para esto, genuinamente me interesa saberlo.
Lecciones aprendidas (más de un año en producción)
-
Empieza sin sync automático.
- Dos semanas manejando sincronización manual te enseñan más que cualquier tutorial: entiendes qué hace
prune, cómo leer el diff que ArgoCD muestra antes de aplicar, y por qué elselfHealeventualmente te salvará. - Habilita el sync automático solo cuando confíes en tus manifiestos y en tu proceso de revisión de PRs.
- Dos semanas manejando sincronización manual te enseñan más que cualquier tutorial: entiendes qué hace
-
Usa ApplicationSets si tienes más de tres o cuatro Applications con estructura similar.
- Te ahorras repetición y los cambios de configuración global son mucho más manejables.
-
Invierte tiempo en el control de acceso desde el principio — no después.
- ArgoCD tiene RBAC basado en proyectos con políticas de Casbin: flexible, pero bastante más difícil de retrofitear cuando ya tienes diez personas tocando el sistema y no quieres romper nada mientras ajustas permisos.
ArgoCD vs. Flux
| Característica | ArgoCD | Flux |
|---|---|---|
| UI amigable para operaciones diarias | ✅ | ❌ |
| Operaciones desde la terminal, controladores pequeños | ❌ | ✅ |
| Enfoque “declarativo” puro | ✅ | ✅ |
| Curva de aprendizaje | Media | Media‑alta |
No hay una respuesta universal, pero sí hay una respuesta correcta para tu contexto específico.
Conclusión para mi equipo
Para nuestro equipo, ArgoCD fue la decisión correcta.
- El viernes siguiente al incidente del servicio de pagos, hicimos un despliegue que tardó exactamente lo que tardó el merge del PR.
- Nadie corrió comandos locales.
- Nadie tuvo que confiar en que alguien había hecho checkout del branch correcto.
- El historial de despliegues estaba en Git, con el nombre del autor y el mensaje del commit.
Eso, más que cualquier feature específica, es lo que hace que GitOps valga la pena el esfuerzo inicial.