GitOps para infraestructura: patrones y trampas de ArgoCD
GitOps con ArgoCD para Kubernetes: patrón de aplicación de aplicaciones, gestión de secretos, detección de deriva, multiclúster y despliegues progresivos.

GitOps convierte a Git en la única fuente de verdad del estado de la infraestructura. En lugar de ejecutar kubectl apply o hacer clic en paneles, confirmas los manifiestos en un repositorio y un controlador de reconciliación—ArgoCD—garantiza que el clúster coincida con lo declarado en Git. Si alguien cambia algo manualmente en el clúster, ArgoCD detecta la desviación y la corrige.
Esto suena sencillo, pero el GitOps en producción tiene aristas afiladas. La gestión de secretos, la coordinación multiclúster, los despliegues progresivos y el orden de dependencias entre aplicaciones requieren patrones que van más allá de los tutoriales básicos.
Patrón de aplicación de aplicaciones
Gestionar decenas de Applications de ArgoCD individualmente no escala. El patrón App of Apps utiliza una Application padre que gestiona las Applications hijas de forma declarativa.
# ❌ Gestionar cada app manualmente mediante CLI
# argocd app create frontend --repo https://... --path frontend
# argocd app create backend --repo https://... --path backend
# argocd app create monitoring --repo https://... --path monitoring
# No escala, no deja auditoría, no hay gestión declarativa# ✅ Application padre que gestiona todas las apps hijas
# root-app/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: platform-root
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/platform-apps
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true# apps/frontend.yaml — Application hija
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
project: default
source:
repoURL: https://github.com/org/platform-apps
targetRevision: main
path: manifests/frontend
helm:
valueFiles:
- values.yaml
- values-production.yaml
destination:
server: https://kubernetes.default.svc
namespace: frontend
syncPolicy:
automated:
prune: true
selfHeal: trueLas sync waves controlan el orden: la infraestructura (wave: 0) se despliega antes que las bases de datos (wave: 1), que se despliegan antes que las aplicaciones (wave: 2). Esto evita fallos por dependencias faltantes.
Gestión de secretos sin almacenar secretos en Git
La tensión fundamental en GitOps: todo debería estar en Git, pero los secretos no pueden estar en Git. Varios patrones resuelven esto.
// Enfoque 1: Sealed Secrets — cifra secretos para almacenarlos en Git
interface SealedSecretWorkflow {
steps: string[];
}
const sealedSecretsApproach: SealedSecretWorkflow = {
steps: [
// 1. Crea un secreto normal de Kubernetes
"kubectl create secret generic db-creds --from-literal=password=s3cure --dry-run=client -o yaml > secret.yaml",
// 2. Lo cifra con la clave pública del clúster
"kubeseal --format yaml < secret.yaml > sealed-secret.yaml",
// 3. Confirma la versión cifrada en Git
"git add sealed-secret.yaml && git commit -m 'Add db credentials'",
// 4. ArgoCD lo aplica; el controlador descifra dentro del clúster
],
};
// Enfoque 2: External Secrets Operator — referencia desde un almacén
// external-secret.yaml
const externalSecretManifest = `
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: backend
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: production/database
property: username
- secretKey: password
remoteRef:
key: production/database
property: password
`;External Secrets Operator es el patrón a largo plazo más adecuado. Desacopla el ciclo de vida de los secretos del ciclo de vida del despliegue: los secretos rotan en el almacén sin necesidad de commits en Git.
Detección de desviaciones y autocorrección
ArgoCD compara continuamente el estado deseado (Git) con el estado real (clúster). Cuando divergen, puede alertar o corregir automáticamente.
interface DriftPolicy {
autoSync: boolean;
selfHeal: boolean;
prune: boolean;
allowedDrift: DriftException[];
}
interface DriftException {
group: string;
kind: string;
jsonPointers: string[];
}
// Configura qué campos están permitidos para desviarse
// (gestionados por controladores, no por humanos)
const driftPolicy: DriftPolicy = {
autoSync: true,
selfHeal: true,
prune: true,
allowedDrift: [
{
// HPA modifica el número de réplicas
group: "apps",
kind: "Deployment",
jsonPointers: ["/spec/replicas"],
},
{
// Cert-manager actualiza los secretos TLS
group: "",
kind: "Secret",
jsonPointers: ["/data"],
},
],
};
// Configuración correspondiente de la Application de ArgoCD
const ignoreDifferences = `
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
- group: ""
kind: Secret
jsonPointers:
- /data/tls.crt
- /data/tls.key
`;Sin ignoreDifferences, ArgoCD luchará constantemente contra el Horizontal Pod Autoscaler: ArgoCD establece las réplicas al valor de Git, HPA las cambia inmediatamente, ArgoCD detecta la desviación y las restablece. Este bucle es una de las trampas más comunes de ArgoCD.
Estrategia de sincronización multiclúster
El GitOps en producción suele implicar varios clústeres: staging, producción y, a veces, clústeres regionales. La estructura del repositorio Git debe soportar configuración específica por entorno.
interface MultiClusterConfig {
structure: "directory-per-env" | "branch-per-env" | "overlay";
}
// Recomendado: overlays de Kustomize
const repoStructure = {
"base/": {
"deployment.yaml": "Base deployment manifest",
"service.yaml": "Base service manifest",
"kustomization.yaml": "Base kustomization",
},
"overlays/staging/": {
"kustomization.yaml": `
bases:
- ../../base
patches:
- replica-count.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=debug
- API_URL=https://api.staging.example.com
`,
},
"overlays/production/": {
"kustomization.yaml": `
bases:
- ../../base
patches:
- replica-count.yaml
- resource-limits.yaml
configMapGenerator:
- name: app-config
literals:
- LOG_LEVEL=warn
- API_URL=https://api.example.com
`,
},
};
// ApplicationSet de ArgoCD para multiclúster
const applicationSet = `
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: backend-service
namespace: argocd
spec:
generators:
- list:
elements:
- cluster: staging
url: https://staging-k8s.internal
overlay: staging
- cluster: production
url: https://prod-k8s.internal
overlay: production
template:
metadata:
name: 'backend-{{cluster}}'
spec:
source:
repoURL: https://github.com/org/platform-apps
targetRevision: main
path: 'manifests/backend/overlays/{{overlay}}'
destination:
server: '{{url}}'
namespace: backend
`;Los ApplicationSets generan Applications a partir de plantillas, reduciendo la duplicación y garantizando la consistencia entre clústeres. Cada entorno recibe los mismos manifiestos base con overlays específicos del entorno.
Integración con despliegues progresivos
GitOps con ArgoCD combina bien con Argo Rollouts para la entrega progresiva. En lugar de reemplazar todos los pods de golpe, el tráfico se desplaza gradualmente con análisis automatizado.
# rollout.yaml — reemplaza el Deployment
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: backend-api
namespace: backend
spec:
replicas: 10
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 5m }
- analysis:
templates:
- templateName: success-rate-check
- setWeight: 25
- pause: { duration: 10m }
- analysis:
templates:
- templateName: success-rate-check
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
canaryService: backend-api-canary
stableService: backend-api-stable
selector:
matchLabels:
app: backend-api
template:
metadata:
labels:
app: backend-api
spec:
containers:
- name: api
image: registry.example.com/backend:v2.1.0# analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate-check
spec:
metrics:
- name: success-rate
interval: 60s
successCondition: result[0] > 0.99
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{
service="backend-api",
status=~"2.."
}[5m])) /
sum(rate(http_requests_total{
service="backend-api"
}[5m]))Un commit de Git actualiza la etiqueta de la imagen, ArgoCD sincroniza el Rollout y Argo Rollouts desplaza el tráfico progresivamente. Si la plantilla de análisis detecta tasas de éxito degradadas, revierte automáticamente sin intervención humana.
Conclusiones clave
GitOps con ArgoCD convierte a Git en la única fuente de verdad de la infraestructura, proporcionando trazas de auditoría, rollback mediante git revert y gestión declarativa del clúster. Usa el patrón App of Apps con sync waves para gestionar decenas de aplicaciones con el orden de dependencias correcto. Maneja los secretos mediante External Secrets Operator o Sealed Secrets: nunca almacenes credenciales en texto plano en Git. Configura ignoreDifferences para los campos gestionados por controladores del clúster como HPA y cert-manager, evitando bucles de reconciliación. Estructura las configuraciones multiclúster con overlays de Kustomize y ApplicationSets para generar aplicaciones específicas por entorno a partir de plantillas. Integra Argo Rollouts para la entrega progresiva, que analiza automáticamente las métricas del canario y revierte ante degradaciones. El objetivo es un sistema donde un git revert sea tu plan de recuperación ante desastres: si el estado actual está roto, revertir el commit restaura automáticamente el último estado bueno conocido.


