ArgoCD + Image Updater for GitOps
Date: 2026-03-23 Status: Accepted Context: Choosing a GitOps tool and deployment trigger mechanism for the platform
Decision
Use ArgoCD with ArgoCD Image Updater (polling-based) as the GitOps controller for all deployments.
How it works
graph LR
push["git push"] --> gha["GitHub Actions<br/>build image"]
gha --> harbor["Harbor<br/>stores image"]
harbor --> iu["Image Updater<br/>polls every 1 min"]
iu --> argocd["ArgoCD<br/>triggers sync"]
argocd --> k8s["Team namespace<br/>deploys"]
Image Updater watches Harbor for new image tags and automatically updates ArgoCD application annotations, triggering a sync. No webhooks, no per-team configuration.
Rationale
Why ArgoCD?
- UI for visibility — ArgoCD's web interface makes deployment state visible to admins and coaches without needing kubectl access. You can see at a glance which teams have deployed, what version is running, and whether syncs are healthy.
- Ecosystem maturity — widely adopted CNCF project with strong community support and documentation.
- ApplicationSet — enables templated multi-tenant deployments from a single definition.
Why Image Updater with polling?
- Zero per-team configuration — teams just push to Harbor and deployments happen automatically. No webhooks to set up per student repository.
- Decoupled from CI — the deployment trigger doesn't depend on GitHub Actions completing a specific step. If an image lands in Harbor (from any source), it gets deployed.
- Trade-off accepted: polling interval (1 min) means deployments take 1-3 minutes after image push. This is acceptable for an educational context.
Alternatives Considered
Flux
- ✅ Lightweight, GitOps-native
- ❌ No built-in UI — coaches would need kubectl or a third-party dashboard
- Rejected: Lack of UI is a significant gap for our use case
Webhook-based triggers (e.g., Harbor webhook → ArgoCD)
- ✅ Faster deployment (seconds vs minutes)
- ❌ Requires webhook configuration per team/project
- ❌ More fragile (webhook delivery failures, network issues)
- Rejected: Per-team config overhead doesn't scale with 15+ teams
Jenkins / manual CD
- ❌ Not GitOps (imperative, not declarative)
- ❌ Extra infrastructure to maintain
- Rejected: Counter to our IaC principles
Consequences
Positive
- Single ArgoCD instance serves all tenants (PRJ2 + SPoHF)
- Coaches can inspect deployments via UI without platform access
- Adding a new team requires only an ArgoCD Application manifest — no webhook setup
Negative
- 1-3 minute delay between image push and deployment (polling interval)
- Image Updater is an additional component to maintain
- ArgoCD UI exposes some cluster state (mitigated by RBAC: read-only default policy)