Why the installation decides how GitOps goes
Most failed GitOps rollouts did not fail on the tool. They failed on the install: a controller deployed once with kubectl apply, left on default credentials, never upgraded, and managed by nobody. Within a year the cluster has drifted from git, an engineer has a shared admin password, and the team quietly goes back to running Helm from laptops.
This page covers how we install and configure ArgoCD or Flux on Kubernetes so that it stays boring and dependable. It is the first step of our wider GitOps, Helm, ArgoCD and Flux service. If you want the background first, read what GitOps means in practice.
What a good install looks like
- The controller is configured from git and can be rebuilt from scratch in minutes.
- Nobody uses a shared admin login. Humans sign in through your identity provider.
- The controller has only the cluster permissions it needs, and tenant teams cannot escalate through it.
- Upgrades are a pull request, tested on a non-production cluster first.
- Health of the controller itself is monitored, because a silent GitOps outage looks exactly like a quiet week.
ArgoCD or Flux: how we decide
Both tools implement the same idea: a controller inside the cluster pulls desired state from git and reconciles it. The differences are about operating style.
| Question | ArgoCD | Flux |
|---|---|---|
| Interface | Web UI and CLI, application-centric | CLI and Kubernetes resources, optional third-party UI |
| Architecture | Central server with application controller, repo server, API server | Independent controllers (source, kustomize, helm, notification, image) |
| Multi-cluster | One control plane can manage many clusters | Typically one Flux per cluster, driven from a shared repository |
| Helm | Renders charts itself and applies the output | Native HelmRelease with Helm’s own lifecycle and release history |
| Best fit | Developer-facing platforms, visibility for non-platform engineers | Platform teams who prefer composable, CLI-first tooling |
Neither is wrong. We have seen teams pick on a demo and regret it, so we ask who will use it daily. If application developers want to see their deployment status without asking, ArgoCD’s UI is a genuine advantage. If one platform team runs everything and values small, independent controllers, Flux is often a better fit. Our GitOps with ArgoCD on EKS tutorial walks through the ArgoCD route in detail, and the Flux glossary entry covers the other.
How it works in practice
Bootstrapping Flux
Flux installs itself into git. The bootstrap command creates or updates a repository, commits its own manifests, and then reconciles from that repository:
flux bootstrap github \
--owner=acme-platform \
--repository=fleet \
--branch=main \
--path=clusters/production \
--personal=false
After this, upgrading Flux means regenerating its manifests in git and merging a pull request. The cluster applies the new version itself. Authentication uses a deploy key or token scoped to that repository, which we keep least-privilege and rotate.
Installing ArgoCD
For ArgoCD we generally use the official Helm chart, pinned to a version, rather than the raw quick-start manifest. That gives us one values file to review:
helm repo add argo https://argoproj.github.io/argo-helm
helm upgrade --install argocd argo/argo-cd \
--namespace argocd --create-namespace \
--version <pinned-chart-version> \
--values argocd-values.yaml
Once running, we create an Application that points ArgoCD at its own configuration in git, so it becomes self-managing. The first-run admin secret is used once to configure SSO and then removed.
Hardening for production
Whichever tool you choose, we work through the same list:
- Identity. Single sign-on through your OIDC provider, with groups mapped to roles. See GitOps RBAC for the permission model.
- Scope. Decide whether the controller holds cluster-admin or is restricted per namespace and per project. Multi-tenant clusters should restrict it.
- Availability. ArgoCD supports HA with multiple replicas of the server and repo server and a sharded or replicated application controller. Flux controllers are leader-elected and restart cleanly. We size both from your application count, not from defaults.
- Network. The UI and API sit behind your ingress with TLS. Network policy limits what can talk to the controller namespace.
- Repository credentials. Read-only deploy keys or GitHub App credentials, one per repository, never a developer’s personal token.
- Observability. Both tools expose Prometheus metrics. We alert on sync failures, reconciliation lag and controller restarts, and feed them into your notification channels.
Decisions and trade-offs
One controller or one per cluster. A central ArgoCD managing many clusters is convenient, but it becomes a high-value target holding credentials for all of them. Per-cluster controllers limit blast radius at the cost of more things to upgrade. We pick based on your cluster count and security posture, and cover the multi-cluster case in ApplicationSets and Flux Kustomizations.
Managed add-on or self-installed. Some cloud providers offer managed Flux or ArgoCD add-ons. These reduce upgrade work but may lag behind upstream versions or limit configuration. We evaluate them honestly rather than defaulting to self-hosting.
When not to do this. If you run a single small cluster with two services and one engineer who deploys rarely, a well-written pipeline using Helm may be enough. GitOps pays off with multiple environments, multiple deployers, or an audit requirement.
Common failure modes
- Controller managed by hand. If upgrades are manual, they get skipped. We put the controller in git on day one.
- Admin password shared. Fixed by SSO and disabling the local admin account.
- Over-permissioned controller. One compromised repository then means cluster takeover. Scoped projects and namespaces reduce this.
- No alerting. The controller can be failing for days. We alert on reconciliation errors and staleness.
- Large repositories slowing sync. Poorly structured monorepos hit repo-server limits. Layout matters, which is why we design the repository structure alongside the install.
Delivery and handover
You get a repository containing the controller configuration, a short architecture note explaining why we chose what we chose, an upgrade runbook, and a recovery procedure we have actually tested by rebuilding a non-production cluster from git. Your engineers do the first upgrade with us watching, not the other way round.
How to tell it is working
A new cluster reaches your intended state from one bootstrap command. Nobody runs kubectl apply against production. Controller upgrades are routine pull requests. Sync failures reach a human within minutes. If that is where you want to be, book a consultation and we will start with your current clusters.