Saltar al contenido

GitOps: gestionar la infraestructura con pull requests

Flujos GitOps que gestionan Kubernetes mediante pull requests con ArgoCD y Flux: estructura del repositorio, sincronización, health checks y rollback.

5 min de lectura
Diagrama de flujo de trabajo GitOps que muestra cómo un pull request dispara la sincronización automatizada desde un repositorio Git hacia un clúster de Kubernetes a través de ArgoCD

Los pipelines de despliegue tradicionales empujan cambios a producción: un servidor de CI construye artefactos y los despliega en los destinos. GitOps invierte esto: el estado deseado vive en Git, y un controlador ejecutándose dentro del clúster reconcilia continuamente la realidad con el estado declarado. Sin comandos kubectl manuales, sin scripts imperativos, sin diferencia entre lo que crees que está desplegado y lo que realmente se ejecuta.

El pull request se convierte en el mecanismo de despliegue. Revisa un cambio de manifiesto, haz merge, y el clúster converge. Deshaz un despliegue revertiendo un commit.

El modelo GitOps

GitOps tiene cuatro principios: configuración declarativa, estado deseado bajo control de versiones, aplicación automatizada y reconciliación continua.

ymlyaml
# ❌ Despliegue imperativo — frágil, sin trazabilidad
# kubectl set image deployment/api api=myapp:v2.3.1
# kubectl scale deployment/api --replicas=5
# kubectl apply -f hotfix-configmap.yaml
# ¿Quién ejecutó esto? ¿Cuándo? ¿Fue revisado?
# ¿Qué pasa cuando el clúster se desvía?
ymlyaml
# ✅ GitOps declarativo — Git ES la fuente de la verdad
# environments/production/api/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: production
  labels:
    app: api
    version: v2.3.1
spec:
  replicas: 5
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
        version: v2.3.1
    spec:
      containers:
        - name: api
          image: registry.example.com/api:v2.3.1
          ports:
            - containerPort: 3000
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              cpu: 500m
              memory: 512Mi
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 15
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 10

Cada cambio es un commit. Cada despliegue es un merge. Cada rollback es un revert.

Estructura del repositorio

Separa el código de la aplicación de la configuración de despliegue. Los repositorios de aplicación contienen código fuente y pipelines de CI. Los repositorios de configuración contienen manifiestos de Kubernetes organizados por entorno.

# infrastructure-config/ (repositorio de configuración GitOps)
├── base/                    # Manifiestos compartidos
│   ├── api/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   ├── hpa.yaml
│   │   └── kustomization.yaml
│   └── worker/
│       ├── deployment.yaml
│       ├── service.yaml
│       └── kustomization.yaml
├── environments/
│   ├── staging/
│   │   ├── api/
│   │   │   ├── kustomization.yaml    # Parches para staging
│   │   │   └── replica-patch.yaml
│   │   └── kustomization.yaml
│   └── production/
│       ├── api/
│       │   ├── kustomization.yaml    # Parches para prod
│       │   ├── replica-patch.yaml
│       │   └── resource-patch.yaml
│       └── kustomization.yaml
└── argocd/                  # Definiciones de aplicaciones de ArgoCD
    ├── staging.yaml
    └── production.yaml

Con Kustomize, los manifiestos base definen la configuración común. Los overlays de entorno aplican parches solo en lo que difiere —número de réplicas, límites de recursos, variables de entorno.

ymlyaml
# environments/production/api/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
 
resources:
  - ../../../base/api
 
namespace: production
 
patches:
  - path: replica-patch.yaml
  - path: resource-patch.yaml
 
images:
  - name: registry.example.com/api
    newTag: v2.3.1
ymlyaml
# environments/production/api/replica-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 5

Configuración de aplicaciones en ArgoCD

ArgoCD observa el repositorio Git y sincroniza el estado del clúster para que coincida. El recurso Application define qué observar y cómo sincronizar.

ymlyaml
# argocd/production.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: production-api
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: production
  source:
    repoURL: https://github.com/myorg/infrastructure-config
    targetRevision: main
    path: environments/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true          # Elimina recursos borrados de Git
      selfHeal: true       # Revierte cambios manuales en el clúster
      allowEmpty: false    # Evita el borrado accidental de todos los recursos
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
      - PruneLast=true
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 1m
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas   # Ignora réplicas gestionadas por HPA

La configuración selfHeal: true es crítica: significa que los cambios manuales con kubectl se revierten automáticamente. La fuente de la verdad es Git, y el clúster converge continuamente hacia ella.

Actualización automatizada de imágenes

Cuando un pipeline de CI construye una nueva imagen, debe actualizar el repositorio de configuración de GitOps. Esto crea un commit que ArgoCD detecta.

ymlyaml
# .github/workflows/build-and-update.yml
name: Build and Update Config
 
on:
  push:
    branches: [main]
 
jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      image-tag: ${{ steps.meta.outputs.version }}
    steps:
      - uses: actions/checkout@v4
 
      - name: Build and push image
        id: meta
        run: |
          TAG="v$(date +%Y%m%d)-${GITHUB_SHA::8}"
          echo "version=$TAG" >> $GITHUB_OUTPUT
          docker build -t registry.example.com/api:$TAG .
          docker push registry.example.com/api:$TAG
 
  update-config:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout config repo
        uses: actions/checkout@v4
        with:
          repository: myorg/infrastructure-config
          token: ${{ secrets.CONFIG_REPO_TOKEN }}
 
      - name: Update image tag
        run: |
          cd environments/staging/api
          kustomize edit set image \
            registry.example.com/api:${{ needs.build.outputs.image-tag }}
 
      - name: Commit and push
        run: |
          git config user.name "CI Bot"
          git config user.email "ci@example.com"
          git add .
          git commit -m "chore: update api image to ${{ needs.build.outputs.image-tag }}"
          git push

Health checks y rollback

ArgoCD monitorea la salud de los recursos después de la sincronización. Si un despliegue falla los health checks, puedes configurar el rollback automático o detectarlo en el estado de sincronización.

ymlyaml
# Health check personalizado para la API
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: production-api
spec:
  # ... configuración de source y destination
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
  # Evaluación de salud del recurso
  info:
    - name: deployment-strategy
      value: rolling-update
shbash
# Verificar estado de sincronización
argocd app get production-api
 
# Ver historial de sincronización
argocd app history production-api
 
# Rollback a una sincronización anterior
argocd app rollback production-api 2
 
# O simplemente revertir en Git (preferido — mantiene a Git como fuente de la verdad)
git revert HEAD
git push origin main
# ArgoCD detecta el cambio y sincroniza de nuevo

El rollback basado en Git es el enfoque GitOps correcto. En lugar de usar el comando rollback de ArgoCD, revierte el commit en Git. Esto mantiene el repositorio Git como la única fuente de la verdad y genera una trazabilidad clara con el mensaje del revert que explica por qué ocurrió el rollback.

Detección de drift y alertas

Incluso con selfHeal habilitado, debes monitorear los intentos de drift: a menudo indican problemas operacionales o miembros del equipo evadiendo el flujo de trabajo GitOps.

ymlyaml
# Alerta de Prometheus para fallos de sincronización de ArgoCD
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: argocd-alerts
  namespace: monitoring
spec:
  groups:
    - name: argocd
      rules:
        - alert: ArgoCDSyncFailed
          expr: |
            argocd_app_info{sync_status="OutOfSync"}
            * on(name) group_left()
            (time() - argocd_app_info{sync_status="OutOfSync"})
            > 300
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: >-
              Application {{ $labels.name }}
              has been out of sync for more than 5 minutes
            description: >-
              Check ArgoCD for sync errors.
              Run: argocd app get {{ $labels.name }}
 
        - alert: ArgoCDAppDegraded
          expr: |
            argocd_app_info{health_status="Degraded"} == 1
          for: 3m
          labels:
            severity: critical
          annotations:
            summary: >-
              Application {{ $labels.name }}
              health is degraded

Conclusiones clave

GitOps hace de Git la única fuente de la verdad para el estado de la infraestructura: cada despliegue es un merge, cada rollback es un revert, y el clúster reconcilia continuamente hacia el estado declarado sin necesidad de comandos imperativos. Separa los repositorios de código de aplicación de los repositorios de configuración de infraestructura para que las builds de imagen activen actualizaciones de configuración mediante commits automatizados, manteniendo una frontera clara entre lo que es la aplicación y cómo se ejecuta. Habilita selfHeal y prune en las políticas de sincronización de ArgoCD para asegurar que los cambios manuales en el clúster se reviertan automáticamente y los recursos eliminados se limpien, evitando que se acumule configuración drift cuando los equipos evaden el flujo de trabajo GitOps. Monitorea estados fuera de sincronización y salud degradada con alertas, porque los intentos de drift suelen indicar brechas de proceso o problemas operacionales: detectarlos rápidamente preserva la integridad que hace valioso a GitOps.

Wilfredo Rujel

Wilfredo Rujel

Ingeniero de Software Full Stack

Compartir esta publicaciónX