Your Cluster Should Read Git: A Lean Reconciliation Pattern for k3s

A small k3s cluster does not need a miniature enterprise platform. It needs a dependable way to answer one question:

What should be running here right now?

GitOps turns that question into a file lookup rather than a memory test. Instead of SSH sessions, copied manifests, and half-remembered Helm commands, the cluster continuously compares its live state with a declared state in Git. When those states differ, a controller works to close the gap.

That reconciliation loop is the important idea. Argo CD and Flux are implementation choices around it.

For a homelab, a side project, or a small production estate on k3s, GitOps is valuable not because it makes the setup look sophisticated. It is valuable because it makes the system legible after three weeks away from it.

Start with the constraints of a small cluster

k3s is already optimized for a lighter Kubernetes experience, but its clusters still have finite memory, CPU, storage, and operational attention. A three-node cluster built from small virtual machines or low-power hardware should not casually absorb every dashboard, policy engine, observability suite, and automation controller available in the ecosystem.

A useful GitOps design begins with a resource budget.

Before selecting Argo CD or Flux, identify what the cluster must manage:

  • Application deployments and Helm releases
  • Shared infrastructure such as Traefik middleware, cert-manager, or external DNS
  • Namespaces, resource quotas, and network policies
  • Secrets or encrypted secret references
  • Cluster-specific configuration such as storage classes and ingress settings

Then decide what does not belong in the first version. Multi-cluster fleet management, elaborate promotion pipelines, custom admission controls, and a heavily customized UI can wait until there is a concrete need.

The goal is not to install GitOps. The goal is to establish a small, recoverable reconciliation system.

Treat Git as the desired-state contract

The repository should describe the cluster in a way that a new machine and a future version of you can understand. A practical structure separates cluster wiring from application ownership:

text

The bootstrap directory contains the minimum manifests needed to give a cluster permission to begin reading the rest of the repository. Everything after bootstrap should be managed by the GitOps controller itself.

This distinction matters during recovery. If a node fails, a disk is replaced, or the cluster is rebuilt, the procedure should be short:

  1. Install k3s.
  2. Restore only essential cluster data if required.
  3. Apply the bootstrap manifests.
  4. Let the controller reconstruct declared infrastructure and workloads from Git.

That is a much stronger recovery story than rebuilding from a collection of terminal history and undocumented Helm values.

Argo CD: a visual command center

Argo CD is often the easiest GitOps tool to explain because its user interface makes reconciliation visible. It presents applications as trees of Kubernetes resources, highlights drift, exposes sync status, and gives operators a quick path from a deployment to the manifests that describe it.

For a small k3s environment, Argo CD works especially well when the operator values visual feedback and occasional hands-on inspection. The Application and ApplicationSet abstractions also provide a clean way to define deployment boundaries.

An Argo CD application can point to a path in Git, select a Helm chart or Kustomize overlay, and target a namespace. Its sync policy determines whether drift is merely reported or automatically corrected.

For example, automatic synchronization is compelling for stateless services:

yaml

With selfHeal, an accidental manual change is reversed. With prune, resources removed from Git are removed from the cluster. Both are powerful, and both require discipline. A manifest deletion is no longer just cleanup in a repository; it can become a deletion in a running environment.

The trade-off is footprint and operational surface. Argo CD includes several components, and its UI, API server, Redis dependency, and controllers are more than a minimal reconciler. That is usually acceptable on a comfortably sized k3s node, but it should be measured rather than assumed. Set resource requests and limits, disable features you will not use, and avoid exposing the Argo CD UI publicly without strong authentication.

Flux: reconciliation as a quiet background service

Flux takes a more Kubernetes-native and composable approach. Its core model uses custom resources such as GitRepository, Kustomization, and HelmRelease. Rather than presenting a central application dashboard as its primary interface, Flux makes the Kubernetes API the control surface.

A Flux Kustomization can express a concise desired-state pipeline:

yaml

Flux is a strong fit when you prefer declarative primitives, command-line workflows, and a smaller control-plane profile. It also handles dependency ordering cleanly: an infrastructure Kustomization can complete before an application Kustomization begins.

The absence of a built-in, full-featured UI is not necessarily a disadvantage. On a small cluster, fewer externally exposed components can mean less maintenance. Status is available through kubectl, Flux CLI commands, events, and metrics. If a visual layer becomes necessary later, tools in the Flux ecosystem can provide one without making it the center of the architecture.

Do not run both without a reason

Argo CD and Flux solve the same fundamental problem. Installing both to manage the same resources introduces competing reconciliation loops, ambiguous ownership, and confusing incident response.

Choose one as the author of cluster state.

Argo CD is often the better choice when a UI improves day-to-day operations, multiple people need an approachable deployment view, or application-centric grouping is the natural mental model.

Flux is often the better choice when the cluster should remain lean, Git and Kubernetes manifests are the primary interfaces, and composable controllers fit the operational style.

The choice is less consequential than consistency. A well-maintained Flux installation is better than a partially understood Argo CD installation, and the reverse is equally true.

Secrets are the boundary where GitOps gets real

Plain Kubernetes Secrets are only base64-encoded, not encrypted. They should not be committed directly to a normal repository.

For small clusters, two common patterns are practical:

  • SOPS with age keys, where encrypted YAML is committed and decrypted by the GitOps controller.
  • Sealed Secrets, where encrypted secret manifests can be committed and are decrypted only by a controller in the target cluster.

SOPS is flexible and works well when secret material may be consumed outside Kubernetes. Sealed Secrets is straightforward when Kubernetes is the main destination. Either way, document key backup and rotation. An encrypted repository without recoverable decryption keys is not a backup strategy; it is a future outage.

Also separate secret changes from ordinary application changes when possible. A pull request that updates an image tag should not need to expose or rewrite unrelated credential material.

Design for controlled drift, not blind automation

GitOps should reduce surprises, not create faster ones. Automatic reconciliation is safest when manifests are deterministic and workloads are designed for replacement.

Be more cautious around:

  • Stateful workloads with persistent volumes
  • Database schema migrations
  • CRD upgrades
  • Ingress or DNS changes
  • Namespace deletion
  • Helm charts that generate or mutate resources unexpectedly

For these changes, use pull requests, reviews where appropriate, and explicit rollout steps. A database deployment may be GitOps-managed, while its migration job is triggered through a carefully versioned release process. GitOps is not a reason to eliminate judgment; it is a way to make judgment visible in version control.

The small-cluster operating rhythm

The healthiest GitOps workflow is almost boring:

  1. A change is proposed in Git.
  2. CI validates YAML, Kustomize builds, Helm templates, and policy checks.
  3. The change is merged.
  4. Argo CD or Flux detects the revision.
  5. The cluster converges on the declared state.
  6. Status and logs confirm the outcome.

That rhythm creates an audit trail without demanding a large platform team. Git holds intent. The controller enforces intent. Kubernetes reports reality.

On a small k3s cluster, this is enough. The system does not need to imitate a cloud provider's internal platform. It needs to be understandable, reversible, and calm under failure.

Choose one reconciler, keep the repository structure obvious, protect secret keys, and make bootstrap repeatable. When the cluster eventually needs rebuilding, GitOps changes the experience from archaeological recovery into a controlled restoration.

Comments (0)

No comments yet. Be the first to share your thoughts!