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.

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.
# ❌ 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?# ✅ 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: 10Cada 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.
# 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# environments/production/api/replica-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 5Configuració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.
# 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 HPALa 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.
# .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 pushHealth 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.
# 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# 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 nuevoEl 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.
# 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 degradedConclusiones 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.


