Problema

Muchas instalaciones de Kubernetes usan GitHub Actions, GitLab CI o Jenkins para compilar imágenes y aplicar manifiestos. Cuando el número de microservicios crece, la coordinación entre compilación, publicación de imágenes y despliegue se vuelve frágil: los pipelines están dispersos, los permisos son inconsistentes y la trazabilidad entre código y versión de imagen se pierde. El patrón problemático es intentar orquestar tres fases distintas (build, push, deploy) con herramientas que no comparten un modelo de estado único, lo que genera “drift” y fallos inesperados en entornos homelab o producción.

Causa

  1. Separación de responsabilidades – Cada herramienta (CI, registry, CD) mantiene su propio historial. Un cambio en el repositorio puede quedar sin que la imagen se reconstruya o sin que el CD la detecte.
  2. RBAC fragmentado – Los service accounts creados para CI y CD suelen tener permisos mínimos, pero al estar en namespaces diferentes la política de red y de pod security puede bloquear la comunicación entre los componentes.
  3. Falta de sincronización automática – Sin un mecanismo que observe el registro de contenedores, el despliegue sigue usando versiones antiguas de la imagen aunque la pipeline haya publicado una nueva etiqueta.
  4. Gestión manual de manifiestos – Los archivos YAML se editan a mano o se generan con scripts externos, lo que aumenta la probabilidad de errores de sintaxis o de referencia a etiquetas inexistentes.

Solución

Unificar las tres fases bajo la suite Argo permite que un único estado declarativo controle compilación, publicación y despliegue. La arquitectura típica es:

  1. Argo CD – Observa un repositorio Git y mantiene los manifiestos en el clúster sincronizados.
  2. Argo Workflows – Ejecuta jobs de compilación y push de imágenes como pasos de un workflow definido en YAML.
  3. Argo Image Updater – Monitorea el registro de contenedores; cuando detecta una nueva etiqueta, actualiza automáticamente los manifiestos gestionados por Argo CD y dispara una nueva sincronización.

Paso a paso

1. Preparar el namespace y los service accounts

Crear un namespace dedicado (argo-stack) y tres service accounts: una para Argo CD, otra para Workflows y una tercera para Image Updater. Cada cuenta recibe un RoleBinding que le otorga permisos de get, list, watch, create, update y patch sobre los recursos que necesita (Applications, Workflows, ConfigMaps).

2. Instalar Argo CD

Desplegar Argo CD con el manifiesto oficial, pero añadiendo la referencia al service account creado. La configuración mínima incluye server, repo-server y application-controller. Habilitar --insecure solo en entornos de pruebas.

3. Definir una Application de Argo CD

El repositorio Git contiene los manifiestos de los microservicios. Cada microservicio tiene su propio directorio con deployment.yaml, service.yaml y opcionalmente kustomization.yaml. La Application apunta a la raíz del repo y usa directory como tipo de source.

4. Configurar Argo Workflows para la fase de build

Crear un WorkflowTemplate que reciba como parámetros el nombre del proyecto y la ruta del Dockerfile. El template usa un contenedor con Docker (o Kaniko) para construir la imagen, la etiqueta con el hash de commit y la publica en el registro privado. Al final, el workflow escribe la etiqueta en un ConfigMap que Argo Image Updater leerá.

5. Activar Argo Image Updater

Instalar el controlador y proporcionar un ImageUpdaterConfigMap con la lista de aplicaciones que deben ser observadas. Cada entrada indica el registry, repository, selector (etiqueta del Deployment) y la política de actualización (semver, latest). Cuando el registro recibe una nueva etiqueta, el updater modifica el image field del Deployment y solicita a Argo CD que sincronice.

6. Encadenar los componentes

  • Trigger: Un webhook de Git (push) llama a la API de Argo Workflows para lanzar el template.
  • Workflow: Compila y publica la imagen.
  • Image Updater: Detecta la nueva etiqueta y actualiza el Deployment.
  • Argo CD: Detecta el cambio en el ConfigMap y aplica la nueva versión.

Este flujo garantiza que la única fuente de verdad sea el repositorio Git; cualquier cambio en código genera automáticamente una nueva imagen y su despliegue sin intervención manual.

Cuándo aplicar esta solución

  • Entornos homelab o producción donde se gestionan varios microservicios y se desea evitar scripts ad‑hoc.
  • Equipos que ya usan GitOps y quieren añadir la capa de construcción de imágenes dentro del mismo clúster.
  • Políticas de seguridad estrictas que requieren RBAC granular y aislamiento de componentes.

No es la mejor opción si:

  • Solo se despliega una o dos aplicaciones y la complejidad adicional supera los beneficios.
  • El registro de contenedores está fuera de control (por ejemplo, un registro SaaS sin webhook).
  • No se dispone de recursos de CPU/Memory suficientes para ejecutar los pods de Workflows y Image Updater.

Código

# 1. Namespace y ServiceAccounts
kubectl create namespace argo-stack

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: argo-cd-sa
  namespace: argo-stack
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: argo-cd-rb
  namespace: argo-stack
subjects:
- kind: ServiceAccount
  name: argo-cd-sa
  namespace: argo-stack
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io
EOF

# 2. Instalar Argo CD (usando el manifiesto oficial)
kubectl apply -n argo-stack -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# 3. Aplicar Application que apunta al repo Git
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: microservices
  namespace: argo-stack
spec:
  project: default
  source:
    repoURL: https://github.com/usuario/mi-repo-gitops.git
    targetRevision: HEAD
    path: .
    directory:
      recurse: true
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
EOF

# 4. WorkflowTemplate para build de imágenes
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: docker-build
  namespace: argo-stack
spec:
  entrypoint: build
  arguments:
    parameters:
    - name: repo
    - name: image
    - name: dockerfile
  templates:
  - name: build
    container:
      image: docker:stable
      command: [sh, -c]
      args:
      - |
        docker build -f {{inputs.parameters.dockerfile}} -t {{inputs.parameters.image}} .
        docker push {{inputs.parameters.image}}
    inputs:
      parameters:
      - name: repo
      - name: image
      - name: dockerfile
EOF

# 5. ConfigMap para Image Updater
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: argo-image-updater-config
  namespace: argo-stack
data:
  config.yaml: |
    registries:
    - name: my-registry
      api_url: https://registry.example.com
      credentials:
        username: user
        password: pass
    images:
    - name: my-app
      selector:
        matchLabels:
          app: my-app
      updateStrategy: semver
      registry: my-registry
EOF

Verificación

  1. Push a Git – Realiza un commit en el repositorio configurado.
  2. Webhook – Confirma que el webhook dispara el endpoint /api/v1/workflows/argo-stack/docker-build.
  3. Workflow – En el UI de Argo Workflows verifica que el job termina con Succeeded.
  4. Registro – Comprueba que la nueva etiqueta aparece en el registro (docker pull registry.example.com/my-app:<tag>).
  5. Image Updater – Revisa el log del pod argo-image-updater; debe indicar “updated image my-app to ”.
  6. Argo CD – En la UI de Argo CD, el Application microservices muestra estado Synced y el Deployment tiene la nueva etiqueta.

Notas adicionales

  • Persistencia de credenciales: Usa Secret en vez de colocar usuario/contraseña en texto plano dentro del ConfigMap.
  • Política de versiones: semver funciona bien cuando las etiquetas siguen vMAJOR.MINOR.PATCH. Si usas git SHA, cambia updateStrategy a latest.
  • Escalado: En clústers con recursos limitados, reduce la concurrencia de Workflows mediante parallelism en el WorkflowTemplate.
  • Auditoría: Habilita audit-logging en Argo CD para rastrear quién aprobó cada sincronización.
  • Backup de configuraciones: Exporta los objetos Application, WorkflowTemplate y ConfigMap a un repo separado; así puedes restaurar el stack completo con un solo kubectl apply.