ArgoCD is a better option for pull-based GitOps
Those who kube all come to realize the value of GitOps. Then the question of best practice comes up. Do we go with ArgoCD or FluxCD v2? Do other options exist? If these questions sound familiar, you're in the right place.
In this article, I will explain why Flux should be avoided and why ArgoCD is best if you want to do pull-based GitOps. Another option worth considering is push-based GitOps using a CICD pipeline.
What were we hoping to get out of GitOps?
For starters, it's a good solution to a problem introduced by an earlier solution: Infrastructure as Code (IaC) is a solution that helps you achieve reproducible deployments, and a source of truth ensures that large teams remain in sync, with minimal comms overhead. Unfortunately, these benefits of IaC depend on the live state of your infrastructure matching the desired state defined in Git. GitOps solves this new problem of config drift – where reality needs to be kept in sync with git.
Using GitOps to solve the config drift problem also makes it easy to follow the principle of least privilege and simplify role-based access control (RBAC). You can skip giving humans read-only kubectl access in favor of read-only git repo access. Direct kubectl access can be minimized, in favor of applying RBAC to GitOps service accounts and git repos.
GitOps is also able to inherit the security controls built into git. Requiring peer-reviewed merges translates to requiring peer-reviewed deployments. Git History can become an audit trail of who changed what, when a change occurred and who approved the change.
Why I promote ArgoCD over FluxCD for pull-based GitOps
The short answer: ArgoCD is a far more mature product with a superior user experience compared with Flux v2.
First, if you push a bad config with Argo, you SSO login to a GUI, get visual feedback that an error exists and where to find it and you also get a useful error message. However, with Flux, it’s difficult to figure out an error exists. To make the error message appear, you have to run the right command against the right object in the right namespace using the right CLI tool. Some errors show up with kubectl, others show up with fluxctl.
Second, only ArgoCD can do true pull-based GitOps to deliver the benefits listed above. With Argo, you can solve problems without kubectl access. You push a change to git. Argo infinitely reconciles a live cluster based on git and gives feedback in the GUI.
With Flux, you can't solve problems without kubectl access. Let's pretend you spent the time needed to create perfect logging pipelines with alerts to surface errors. Flux doesn't use a KISS infinite reconciliation loop like Argo. Flux uses a fragile event-based reconciliation loop that frequently gets stuck in a bad state (more common with helm).
At a previous job, I trained hundreds of people on how to do GitOps using Flux. During those training sessions, Flux would become "stuck" for at least 5 of 20 attendees. Reconciliation stops until the confused state is fixed. Git repo changes are temporarily ignored, so manual intervention is required.
The only way to fix it is with several fluxctl commands. Also, fluxctl has a dependency on kubectl, and because we need to fix state, RO access is insufficient. A common example is "install retries exhausted" errors. If you have fixed the issue in git, it’s too bad because Flux gave up after becoming "exhausted." Several fluxctl commands are needed to force a redeploy. You can update the default config to retries = -1 (infinite), but, this doesn't fix the problem, it just makes it get stuck less often. Flux tries to only run deployment logic when it detects changes. There are edge cases where it fails to reconcile because it didn't detect a helm-related change.
Are there edge cases where Flux is better than Argo?
ArgoCD purposefully avoids some of helm's rarely used advanced functionality. Instead, it focuses on rock-solid stability for the most common use cases. If you're using a very advanced helm chart that does stuff like helm hooks, ArgoCD might not support it. Flux has better support for helm's functionality.
What other options exist?
I’ve often seen the following pattern implemented on teams deciding how to implement GitOps:
ArgoCD vs FluxCD vs an over-representation of other tools that followed the operator pattern. I suspect those tools are what shows up in search engines for "GitOps."
An alternative option you might overlook is to point a generic CICD pipeline at IaC and scripting logic stored in a git repo. I call this approach push-based GitOps. I'm a fan of it because it allows you to easily mix both imperative and declarative deployment logic, which is great for dealing with problems like updates involving breaking changes. These are hard to solve using a purely pull-base declarative GitOps solution.
First-time adopters of GitOps should cross Flux off their list of options to consider. ArgoCD or a CICD pipeline are much better options when it comes to implementing GitOps.