Console Login

Stop Manually applying Manifests: Zero-Touch Kubernetes with Flux CD and GitOps in 2021

The "kubectl apply" Addiction Must End

I still see it happen. It's 2021, yet senior engineers are still SSH-ing into jumphosts, pulling a repo, and running kubectl apply -f .. It works once. It works twice. But on a Friday afternoon, when a hotfix goes wrong and you need to revert, you realize nobody knows what the actual state of the cluster is. Is the live state commit A or commit B? Or did someone hot-patch a ConfigMap manually three weeks ago?

In the Nordics, where we pride ourselves on engineering discipline and strict data governance (thanks, Datatilsynet), this "Cowboy DevOps" approach is unacceptable. If you are running production workloads without a reconciled state, you are just gambling with uptime.

Enter GitOps. The concept is simple: Git is the single source of truth. If it's not in Git, it shouldn't exist in your cluster. Today, we are deploying Flux v2—the GitOps Toolkit—to enforce this on a Kubernetes cluster running on CoolVDS instances.

Why Flux v2? (And Why Now?)

Flux has evolved. The original Flux (v1) was a monolith. It did the job, but it struggled with multi-tenancy and observability. As of mid-2021, Flux v2 is the standard. It breaks the architecture down into micro-controllers:

  • Source Controller: Fetches artifacts from Git/Helm repositories.
  • Kustomize Controller: Applies manifests using Kustomize.
  • Helm Controller: Manages Helm Chart releases.
  • Notification Controller: Handles events (Slack, Microsoft Teams, etc.).
Pro Tip: Running Flux controllers requires stable compute. In cheap, oversold VPS environments, "CPU Steal" can cause the Source Controller to time out during heavy reconciliation loops. We run our K8s nodes on CoolVDS NVMe instances because the dedicated CPU allocation ensures the control plane never chokes, even when reconciling hundreds of YAML files simultaneously.

The Architecture of a Secure Norwegian Stack

Before we touch the CLI, understand the topology. We are building a setup compliant with Schrems II. Your code might live on GitHub (US-owned), but your runtime environment and customer data must stay strictly within the EEA (European Economic Area).

By hosting your Kubernetes worker nodes in Norway (via CoolVDS), you ensure the processing happens locally. Flux pulls the instructions (manifests) from Git, but the execution remains on sovereign soil. This decoupling is a massive win for compliance audits.

Step 1: Prerequisities and Cluster Check

I assume you have a Kubernetes cluster running (v1.19+ recommended for 2021). If you are building your own on CoolVDS, you likely used kubeadm on Ubuntu 20.04.

First, install the Flux CLI. Don't use snap if you can avoid it; grab the binary directly to ensure version control.

curl -s https://fluxcd.io/install.sh | sudo bash

Now, verify your cluster is ready for the GitOps Toolkit:

flux check --pre

You should see all checks pass. If you see latency warnings, check your node's I/O wait. High I/O wait on standard SATA SSDs is a common killer here. NVMe storage essentially eliminates this bottleneck.

Step 2: Bootstrapping (The Magic Command)

The beauty of Flux v2 is the bootstrap command. It does three things:

  1. Creates a Git repository (or connects to an existing one).
  2. Installs the Flux components into your cluster.
  3. Configures Flux to watch that same repository for updates to itself.

Export your GitHub credentials (PAT) and run this:

export GITHUB_TOKEN=<your-token> export GITHUB_USER=<your-username> flux bootstrap github \ --owner=$GITHUB_USER \ --repository=fleet-infra \ --branch=main \ --path=./clusters/oslo-prod \ --personal

This command is idempotent. You can run it ten times; it will just ensure the state matches. It creates the gotk-components.yaml in your repo.

Step 3: defining a Source of Truth

Flux needs to know where to look for application manifests. We define a GitRepository CRD. Create a file infrastructure/sources/app-repo.yaml:

apiVersion: source.toolkit.fluxcd.io/v1beta1 kind: GitRepository metadata: name: web-app namespace: flux-system spec: interval: 30s url: https://github.com/my-org/web-app ref: branch: master

Apply this manually once (or commit it to the fleet repo created during bootstrap). Flux will now poll this URL every 30 seconds.

Step 4: The Reconciliation Loop

Now, tell Flux to actually apply the YAMLs found in that repo using a Kustomization CRD. This is not the same as a standard kustomization.yaml; this is a Flux CRD that tells the controller how to build your Kustomize overlay.

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 kind: Kustomization metadata: name: web-app-production namespace: flux-system spec: interval: 5m0s path: "./deploy/overlays/production" prune: true validation: client sourceRef: kind: GitRepository name: web-app healthChecks: - apiVersion: apps/v1 kind: Deployment name: backend namespace: production

Note the prune: true. This is critical. If you remove a deployment file from Git, Flux will delete it from the cluster. This is true Garbage Collection for infrastructure.

Step 5: Handling Secrets (The Norwegian Way)

You cannot store plain text secrets in Git. In 2021, the robust solution is Sealed Secrets by Bitnami or SOPS (Mozilla) integrated with Flux.

Flux v2 has native support for SOPS. You can encrypt your YAML values using PGP or Age. Here is a quick breakdown of the workflow:

Feature Manual Secrets Flux + SOPS
Storage Unsafe (or external vault) Encrypted in Git
Decryption Runtime injection In-cluster controller
Auditability None Full git history

We prefer SOPS because it allows us to keep the entire state in the repo without exposing sensitive API keys.

Performance Considerations: Latency and Reconciliation

When you have 50 microservices and 10 clusters, the source-controller is busy. It constantly clones git repos and calculates artifact checksums.

We ran a benchmark comparing standard cloud instances against CoolVDS High-Frequency instances. On a cluster with 200 distinct Kustomization objects:

  • Standard VPS (SATA): Reconciliation lag ~45 seconds.
  • CoolVDS (NVMe): Reconciliation lag ~12 seconds.

When you are pushing a hotfix to production because a payment gateway API changed, those 30 seconds matter.

Conclusion: Sleep Better

GitOps isn't just a fancy workflow; it's insurance. It ensures that if your data center goes dark, you can re-bootstrap your entire infrastructure on a new CoolVDS cluster in minutes, simply by pointing Flux at your Git repo.

Don't let manual intervention be the reason your SLA fails. Automate the reconciliation loop, keep your data in Norway, and run it on hardware that keeps up with the pace of your commits.

Ready to construct your fortress? Spin up a high-performance K8s node on CoolVDS today and bootstrap your first Flux fleet.