Skip to main content
  1. Projects/

Implementing GitOps Delivery with Flux

Author
Richard Lintern
Building Kubernetes, GitOps and local-first AI systems.

Project date: 2026-08-09 Role: Architecture, implementation, validation and operation

A declarative delivery system using Flux, Kustomize, Helm, image automation and encrypted Git-managed secrets.

Environment and operating context
#

The Kubernetes platform grew from manually managed resources into a service environment with databases, media applications, networking, monitoring, security and internal tools. Early deployments relied on locally held YAML and manual Kubernetes or Helm operations. That approach was useful for experimentation but made it difficult to prove that source control and the live cluster represented the same system.

Business and technical objective
#

The objective was to make Git the authoritative desired state, preserve reviewable history and allow the cluster to converge automatically. A successful design also needed to support Helm-based applications, direct Kubernetes resources, encrypted secrets and automated image updates without making a mutable image tag the only production reference.

Operational value and risk reduction
#

Before: Deployments were performed from locally held manifests and Helm commands, leaving more operational knowledge outside the cluster definition.

After: Git records application, infrastructure, image and encrypted Secret state, while Flux continuously reconciles the cluster.

Risk reduced: Configuration drift and undocumented rebuild steps are reduced because the deployed state has a versioned source and rollback coordinate.

Architectural decisions and alternatives
#

Continue manual kubectl and Helm
Fast for isolated changes, but weak for drift control, reviewability and disaster reconstruction.
CI pipeline pushes directly to the cluster
Automates deployment, but grants the pipeline write access and does not provide continuous reconciliation.
Argo CD
A credible alternative with a strong UI, but Flux aligned well with the repository-driven, controller-based and image-automation requirements.
Selected design
Flux with Kustomize, HelmRelease, SOPS and image automation provided a compact Git-native operating model.

Technical challenges
#

The hard part was migrating stateful, already-running applications without losing configuration or replacing resources unexpectedly. Dependencies between namespaces, storage, Secrets, Helm releases and monitoring had to be represented explicitly. Image delivery also crossed two repositories: application source produced the image, while the GitOps repository recorded the immutable digest.

Proposed solution
#

The repository was divided into application, infrastructure and cluster-composition layers. Kustomize manages direct resources and composition, while HelmRelease objects manage upstream charts. Flux ImageRepository and ImagePolicy resources discover and select images; ImageUpdateAutomation writes the selected digest into Git. SOPS decrypts eligible Secret manifests only during reconciliation.

Source commit -> CI build -> GHCR image
                 |
                 v
ImageRepository -> ImagePolicy -> Git digest update
                                      |
                                      v
                              Flux reconciliation

Implementation
#

Applications were migrated incrementally. Each migration identified the namespace, service account, configuration, storage, network exposure, Secret references and dependency order. Existing resources were rendered and compared before Flux assumed ownership.

The current repository contains Kustomizations for applications such as databases, Grafana, Headlamp, LIP, Mealie, media services, n8n, NetBox, networking, Ombi, Vaultwarden and WordPress, plus infrastructure layers for CrowdSec, logging, MISP, monitoring and Traefik.

Validation and measurable outcomes
#

GitRepository1 of 1 ready
Kustomizations19 of 19 ready
ImageRepositories17 of 17 ready
ImagePolicies17 of 17 ready
ImageUpdateAutomations1 of 1 ready
Suspended Flux resources0
Observed applied revisionmain@sha1:227ff0ae

Readiness was collected directly from Flux custom resources. Image policies resolved to immutable SHA-256 digests, including the ARM64-compatible LIP image. The evidence demonstrates the whole delivery chain rather than only a successful kubectl apply.

Operational controls
#

  • Small reviewable commits
  • Kustomization dependency ordering
  • Render and server-side validation
  • SOPS decryption during reconciliation
  • Immutable digest recording
  • Rollout and API checks after deployment
  • Git history as the rollback coordinate

Outcome
#

The cluster can now be reconstructed and maintained from source-controlled desired state. Image changes are attributable, reconciliation health is measurable, and emergency changes cannot remain an undocumented alternative state.

Skills demonstrated
#

  • Flux controllers and custom resources
  • Kustomize and HelmRelease design
  • Container image automation
  • Git-based release management
  • Stateful workload migration
  • Dependency and rollback planning

Lessons learned
#

Installing Flux is straightforward; adopting GitOps is an operating-model change. Repository structure, dependency ownership, Secret handling and post-deployment validation determine whether reconciliation is genuinely reliable.

Current status and next steps
#

Operational, with all observed Flux resources ready. The existing direct-to-main workflow is effective for a single operator; pull-request policy can be added when collaboration or stronger approval requirements justify it.

Explore the implementation
#

See how secrets were brought into GitOps safely.

How it was done
#

  1. Assessed the existing deployment model. Applications previously managed through locally held YAML, manual Kubernetes commands and Helm operations were identified, together with their storage, configuration, Secret and networking dependencies.
  2. Designed the repository layout. Workloads were separated into apps, shared platform services into infrastructure, and cluster composition into clusters. This made ownership and reconciliation order easier to understand.
  3. Bootstrapped Flux. Flux controllers were installed and connected to the Git repository through a GitRepository source. The initial cluster Kustomization established continuous reconciliation.
  4. Created platform Kustomizations. Separate Kustomizations were introduced for databases, monitoring, logging, networking, security and individual applications. Dependencies were used where one layer required another.
  5. Converted chart-based services. Applications best maintained through upstream Helm charts were represented as HelmRelease resources, while direct Kubernetes resources remained under Kustomize.
  6. Migrated applications in small batches. Existing resources were rendered and compared before Flux took ownership. Each migration was followed by rollout, storage, ingress and application checks.
  7. Integrated encrypted Secrets. SOPS and age were introduced so Secret manifests could be committed alongside workloads without placing usable credentials in Git.
  8. Added image automation. ImageRepository resources scan registries, ImagePolicies select acceptable images, and ImageUpdateAutomation records selected immutable digests in the GitOps repository.
  9. Defined the release workflow. Application source changes trigger CI builds, multi-architecture images are published to GHCR, Flux discovers the new image and Kubernetes reconciles the digest recorded in Git.
  10. Validated the complete chain. The final snapshot showed one ready Git source, nineteen ready Kustomizations, seventeen ready image repositories, seventeen ready policies, one ready automation and no suspended resources.

Evidence methodology
#

The figures in this case study were derived from reproducible source and runtime checks rather than estimates.

  1. Counts were taken directly from Flux GitRepository, Kustomization, ImageRepository, ImagePolicy and ImageUpdateAutomation custom resources.
  2. A resource counted as ready only when its Ready condition was True. Suspended state was checked separately.
  3. Delivery validation combined Flux readiness with image-digest selection, Kubernetes rollout checks and application/API verification.

Limitations and residual risks
#

  • Direct commits to main are appropriate for the current single-operator model but provide less separation than pull-request approval.
  • GitOps can reproduce declared state, but cannot recover application data without the storage and backup design.
  • A valid manifest can still contain a poor operational decision, so review and post-deployment testing remain necessary.

Plain-English glossary
#

Reconciliation
A controller repeatedly compares desired Git state with live cluster state and corrects differences.
Kustomization
A Flux resource that builds and applies a defined set of Kubernetes manifests.
ImagePolicy
A Flux resource that selects an acceptable image version or digest from a scanned repository.

Independent validation
#

This was a self-directed engineering project rather than a client engagement. Credibility is established through deployed configuration, source history, successful builds, operational measurements, restoration tests and repeatable validation rather than a client testimonial.