Skip to content

Latest commit

 

History

23 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FlowPipe

Pipeline de integración y despliegue continuo que corre íntegramente dentro de un cluster de Kubernetes, sin depender de GitHub Actions, Jenkins ni ninguna herramienta externa. Detecta commits nuevos en un repositorio Git, ejecuta los tests, construye la imagen de la aplicación y actualiza el despliegue — todo mediante recursos nativos de Kubernetes (Job, CronJob, RBAC) y Kaniko para el build de imágenes sin Docker daemon.

Arquitectura

CronJob (polling Git) → Job (tests) → Job (build con Kaniko) → Job (deploy) → Deployment
                                                                      │
                                                                      ▼
                                                    Controller (FastAPI + Redis)
                                                    — estado de cada run del pipeline

Estado actual

  • Fase 1 — Controller: API de estado del pipeline (FastAPI + Redis)
  • Fase 2 — CronJob de polling de Git
  • Fase 3 — Job de tests con initContainer
  • Fase 4 — Job de build con Kaniko
  • Fase 5 — Job de deploy
  • Fase 6 — RBAC del pipeline (ServiceAccounts, Role por etapa)

Las 6 fases están completas y verificadas de punta a punta.

Detalle de lo verificado hasta ahora:

  • Fase 2: git-poller (CronJob cada minuto, k8s/git-poller-cronjob.yaml) consulta el último commit del repo vigilado (flowpipe-config ConfigMap) con git ls-remote, pregunta al controller si ese SHA ya fue procesado y, si es nuevo, lanza un Job a partir de la plantilla del CronJob test-runner (kubectl create job ... --from=cronjob/test-runner). Corre bajo su propio ServiceAccount (flowpipe-poller-sa, ver Fase 6) con permisos mínimos definidos en k8s/flowpipe-rbac.yaml.
  • Fase 3: test-runner (CronJob suspendido, sólo se dispara vía el poller, k8s/test-runner-cronjob.yaml) clona el repo en un initContainer, instala dependencias y corre pytest real contra el código clonado, reportando success/failed al controller vía POST /runs/update.
  • Fase 4: si los tests pasan, ese mismo Job encadena kaniko-build (CronJob suspendido, k8s/kaniko-build-cronjob.yaml) vía kubectl create job ... --from=cronjob/kaniko-build. Kaniko clona el repo, construye la imagen a partir de su Dockerfile sin depender de un Docker daemon, y la publica en el registry local de minikube con el SHA del commit como tag — trazabilidad completa entre commit → imagen.
  • Fase 5: como Kaniko no tiene shell (no puede encadenar nada por sí mismo), test-runner actúa como orquestador del resto del pipeline: espera con kubectl wait --for=condition=complete a que termine el Job de build, reporta stage:"build" al controller, y si tuvo éxito encadena flowpipe-deploy (CronJob suspendido, k8s/flowpipe-sample-deploy-cronjob.yaml), que aplica de forma idempotente un Deployment para flowpipe-sample con la imagen recién construida — actualizándolo (rolling update) en cada commit nuevo.
  • Fase 6: se reemplazó la ServiceAccount única compartida por tres — una por etapa (flowpipe-poller-sa, flowpipe-test-sa, flowpipe-deploy-sa), cada una con su propio Role acotado solo a los verbos y recursos que esa etapa usa de verdad (p. ej. flowpipe-deploy-sa no puede crear Jobs, solo Deployments; el acceso a las plantillas de CronJob está además acotado por resourceNames a las que cada etapa realmente encadena). kaniko-build no tiene ServiceAccount propia — usa el default del namespace porque no llama a la API de Kubernetes en absoluto.

Quick start

Requiere Docker Desktop, minikube y kubectl.

minikube start
minikube addons enable registry
minikube docker-env | Invoke-Expression

docker build -t flowpipe-controller:latest ./controller

kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/flowpipe-config.yaml
kubectl apply -f k8s/flowpipe-rbac.yaml
kubectl apply -f k8s/redis-deployment.yaml
kubectl apply -f k8s/controller-deployment.yaml
kubectl apply -f k8s/git-poller-cronjob.yaml
kubectl apply -f k8s/test-runner-cronjob.yaml
kubectl apply -f k8s/kaniko-build-cronjob.yaml
kubectl apply -f k8s/flowpipe-sample-deploy-cronjob.yaml

kubectl get pods -n flowpipe

Probar el controller:

kubectl port-forward -n flowpipe svc/flowpipe-controller 8000:80

# en otra terminal
Invoke-RestMethod -Uri http://localhost:8000/runs/update -Method Post `
  -ContentType "application/json" `
  -Body '{"commit_sha":"abc123","stage":"test","status":"success"}'

Invoke-RestMethod -Uri http://localhost:8000/runs/abc123

Decisiones de seguridad

  • Kaniko en vez de Docker-in-Docker (Fase 4): construir imágenes dentro de un Pod normalmente requeriría montar /var/run/docker.sock o correr el contenedor en modo privileged, lo que da acceso efectivo al nodo. Kaniko construye la imagen en espacio de usuario, sin socket ni privilegios especiales — el enfoque recomendado para CI/CD nativo de Kubernetes.
  • Registry local sin TLS (Fase 4): el addon registry de minikube no trae certificado, por lo que Kaniko usa --insecure --skip-tls-verify para poder publicar en él. Válido únicamente para este entorno de aprendizaje/local — en un clúster real este sería un registry con TLS y imagePullSecrets, nunca una conexión sin cifrar.
  • Imagen del Deployment por IP del Service, no por su DNS interno (Fase 5): el perfil de minikube usado en este proyecto corre con --container-runtime=docker. Con ese runtime, el pull de imágenes lo hace el daemon de Docker del nodo directamente, fuera de la red/DNS del clúster — por eso no resuelve nombres *.svc.cluster.local, aunque Kaniko sí pudo publicar con ese mismo nombre (su push corre dentro de un Pod, donde el DNS del clúster sí aplica). La solución fue resolver la IP del Service registry en tiempo de ejecución (kubectl get svc ... -o jsonpath='{.spec.clusterIP}') en vez de hardcodearla, con un Role acotado por resourceNames para que flowpipe-deploy-sa solo pueda leer ese Service puntual en kube-system. En un clúster real, con containerd como runtime y un registry externo con DNS público, este problema no existiría.
  • RBAC de mínimo privilegio por etapa (Fase 6): antes de esta fase, las tres CronJob que usan kubectl compartían una única ServiceAccount con la unión de todos los permisos — cualquiera de ellas podía, en teoría, crear Jobs o modificar Deployments aunque nunca lo hiciera. Separar una ServiceAccount/Role por etapa acota el radio de daño si alguna llegara a verse comprometida: cada una solo puede hacer exactamente lo que su propio script necesita, nada más.

About

Un pipeline de integración y despliegue continuo que vive dentro de Kubernetes. Detecta cambios en Git con un CronJob, ejecuta tests en un Job efímero, construye la imagen con Kaniko sin necesitar Docker daemon, y actualiza el Deployment. CD real sin GitHub Actions.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages