TL;DR:

  • GitOps uses Git as the single source of truth for device configuration — changes are PRs, not SSH sessions; every deployment is an audit trail.
  • Flux CD runs on each edge node (or cluster) and continuously reconciles the device’s actual state against what Git says it should be.
  • This scales better than push-based deployment tools for large, intermittently connected fleets, because nodes pull their own updates when connectivity is available.

Managing configuration drift across tens, hundreds, or thousands of edge devices is one of the harder operational problems in IoT. Traditional approaches — SSH into devices to push updates, run Ansible playbooks from a central server, or rely on custom update daemons — work at small scale but break down when devices are spread across sites, have unreliable connectivity, or need different configuration per location.

GitOps solves this by inverting the model: instead of a central controller pushing changes to devices, each device continuously pulls its desired state from Git and reconciles to match it.

The GitOps Model

GitOps has four principles as defined by the OpenGitOps specification:

  1. Declarative — desired state is described as configuration (Kubernetes manifests, Helm charts, Kustomize overlays), not imperative commands.
  2. Versioned and immutable — Git provides the history and the rollback mechanism. Every state is a commit.
  3. Pulled automatically — the agent on the device pulls from Git and applies changes without being told to.
  4. Continuously reconciled — if someone modifies a device directly (configuration drift), the GitOps agent detects the divergence and corrects it.

For edge IoT this means: your edge devices run a Kubernetes distribution (K3s is most common for resource-constrained hardware), the K3s cluster runs a Flux CD agent, and Flux watches a Git repository for changes. When you push a manifest update to Git, Flux picks it up and applies it — no manual steps, no SSH, no push from a central controller.

Flux CD for Edge

Flux CD is a CNCF-graduated GitOps toolkit for Kubernetes. Its architecture is particularly well-suited to edge deployments:

Pull-based model. Flux agents on edge nodes initiate connections outbound to your Git provider and container registry. You don’t need inbound firewall rules to reach edge devices — a significant operational advantage when devices are behind NAT or cellular connections.

Disconnected operation. If a device loses internet connectivity, it continues running its last-applied configuration. When connectivity resumes, Flux reconciles against the current Git state. This is the right behaviour for IoT devices in factories, vehicles, or remote sites.

Multi-tenancy and RBAC. Flux’s Kustomize controller supports namespace isolation, so different teams can own different configuration subtrees in the same repository without interfering with each other.

Repository Structure for Edge Fleets

A common pattern is a single Git repository with per-site or per-device-group overlays using Kustomize:

fleet-config/
  base/
    deployment.yaml       # base application config
    kustomization.yaml
  sites/
    factory-london/
      kustomization.yaml  # patches for London site (e.g., local API endpoints)
      config-patch.yaml
    factory-bristol/
      kustomization.yaml
      config-patch.yaml
  clusters/
    factory-london/
      flux-system/        # Flux bootstrap files
      apps.yaml           # points Flux to sites/factory-london
    factory-bristol/
      flux-system/
      apps.yaml

Each cluster’s apps.yaml tells Flux which path in the repository contains its configuration. When you change the London factory’s site config and push, Flux on the London nodes picks up the change within the configured sync interval (typically 1–5 minutes). The Bristol devices are unaffected.

Bootstrapping Flux on K3s Edge Nodes

Initial device setup installs K3s and bootstraps Flux:

# On the edge device, install K3s
curl -sfL https://get.k3s.io | sh -

# Bootstrap Flux with your Git repository
export GITHUB_TOKEN=<your-PAT>
flux bootstrap github \
  --owner=your-org \
  --repository=fleet-config \
  --path=clusters/factory-london \
  --personal

After bootstrap, Flux installs itself into the cluster and begins watching clusters/factory-london/ in the repository. Any manifests in that path (or referenced from it) are applied and kept in sync automatically.

For large fleets, bootstrap can be included in a golden image build process: the base OS image includes K3s, and first-boot cloud-init runs the Flux bootstrap for the device’s assigned site. New devices come online already connected to their Git configuration without any manual steps.

Handling Secrets

Secrets (API keys, certificates, credentials) can’t be stored in plaintext in Git. Flux has two main options:

SOPS with age or KMS encryption. SOPS encrypts secret values before they’re committed to Git, and Flux’s SOPS integration decrypts them at apply time using a key that lives on the device or is fetched from a secrets manager. The Git repository contains encrypted ciphertext; the device has the decryption key. This keeps secrets version-controlled and auditable.

External Secrets Operator. ESO runs on each edge node and fetches secrets from Vault, AWS Secrets Manager, Azure Key Vault, or other external stores, then creates Kubernetes Secrets from them. The Git repository contains ESO ExternalSecret objects (which are safe to commit) rather than actual secret values.

Observability and Drift Detection

Flux exposes Prometheus metrics for sync status, reconciliation errors, and last-applied revision per controller. A standard monitoring setup exports these metrics to a central Prometheus/Grafana instance:

  • flux_kustomize_reconcile_duration_seconds — how long reconciliation took
  • flux_kustomize_conditions — current sync status (Ready/NotReady) per Kustomization
  • gotk_suspend_status — whether sync is suspended for a device (useful for maintenance windows)

An alert on devices that haven’t synced in over N minutes catches connectivity issues and failed reconciliations before they become incidents. Devices that are in sync but diverging from Git (e.g., due to manual changes) are caught by the continuous reconciliation loop itself.

Comparing to Push-Based Alternatives

Push-based tools (Ansible, SaltStack, custom deployment scripts) work by a central controller reaching out to each device and applying changes. This requires:

  • Network reachability from the controller to every device
  • Credentials on the controller for every device
  • Active devices at the time of deployment

For small fleets with reliable connectivity and centrally-managed credentials, push-based tooling is simpler. GitOps becomes compelling when any of those assumptions break — devices behind NAT, devices on cellular with intermittent connectivity, fleets too large to manage credentials centrally, or environments where the audit trail and rollback story of Git is operationally required.

At 50+ devices in different network environments, the pull-based model of GitOps typically wins. At 10 devices on a single well-connected network, Ansible may be simpler. The right threshold depends on your operational context.

Getting Started

The Flux CD documentation (fluxcd.io) includes a complete edge computing guide. For the hardware layer, K3s on Raspberry Pi 4 or 5, Nvidia Jetson, or any ARM/x86 edge compute module is the standard starting point. The flux2-kustomize-helm-example repository provides a complete reference fleet structure to adapt.