Saltar al contenido

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.

5 min de lectura
Diagrama de flujo de trabajo GitOps que muestra a ArgoCD reconciliando el estado deseado de los repositorios Git con el estado real del clúster de Kubernetes

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.

ymlyaml
# ❌ 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
ymlyaml
# ✅ 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
ymlyaml
# 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: true

Las 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.

tstypescript
// 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.

tstypescript
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.

tstypescript
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.

ymlyaml
# 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
ymlyaml
# 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.

Wilfredo Rujel

Wilfredo Rujel

Ingeniero de Software Full Stack

Compartir esta publicaciónX