Console Login

GitOps is Non-Negotiable: Building Bulletproof Pipelines in 2024

GitOps is Non-Negotiable: Building Bulletproof Pipelines in 2024

If you are still SSH-ing into servers to pull code, or worse, running kubectl apply -f from your laptop, you are a walking liability. I’ve seen production clusters implode because a senior engineer had a slightly different ~/.kube/config context than the rest of the team. It’s messy, it’s auditable only by digging through bash history, and quite frankly, it’s amateur hour.

In the high-stakes environment of Nordic tech infrastructure, where the Norwegian Data Protection Authority (Datatilsynet) watches data sovereignty like a hawk and latency to NIX (Norwegian Internet Exchange) defines your user experience, you cannot afford drift. GitOps isn't just a buzzword; it is the strict discipline of using Git as the single source of truth for your entire infrastructure.

Here is how we build a GitOps workflow that actually survives production, utilizing ArgoCD, Kubernetes, and the raw I/O power of CoolVDS NVMe instances.

The Core Philosophy: Pull, Don't Push

Traditional CI/CD pushes changes. The CI runner builds a container, then runs a script to deploy it. This is flawed. If the cluster changes (someone manually edits a resource), the CI pipeline has no idea. The state has drifted.

GitOps reverses this. An agent inside your infrastructure watches the Git repository. When the repo changes, the agent pulls the change. If the cluster changes without a Git commit, the agent detects the drift and heals it. Hard.

Pro Tip: Never let your CI system have direct access to your Kubernetes API server. It’s a massive security vector. Your CI should only be able to push to the Container Registry and update the Git manifest repo. The cluster pulls from there.

Tooling Selection: The Battle for the Controller

By mid-2024, the war is mostly between ArgoCD and Flux v2. Both are CNCF graduated projects. Here is the pragmatic breakdown:

FeatureArgoCDFlux v2
UI/VisibilityExcellent visual dashboard. easy for devs to debug.Minimal/None (CLI focused).
Multi-tenancyStrong RBAC, project isolation.Native, uses k8s RBAC heavily.
ComplexityHigher resource footprint.Lightweight, modular controllers.
Best ForTeams needing visibility & application management.Platform engineers building hidden plumbing.

For this guide, we focus on ArgoCD because the visual feedback loop is critical when diagnosing sync issues during a DDoS attack or a bad rollout.

The Infrastructure Layer: Why Hardware Matters

GitOps controllers are chatty. They constantly poll your Git repositories and verify the state of every resource in your cluster. If you run this on a budget VPS with noisy neighbors and spinning rust (HDD), your reconciliation loops will lag. I have seen ArgoCD application controllers crash because etcd latency spiked over 50ms.

This is where CoolVDS becomes the reference implementation. We use KVM virtualization to ensure strict resource isolation. When you run a Kubernetes control plane on our NVMe-backed instances, you get the IOPS required to handle hundreds of concurrent reconciliations without choking.

Step 1: The Repository Structure

Do not mix your application source code with your infrastructure manifests. Keep them separate. If you don't, your build pipeline loops infinitely.

Bad Structure:

/my-app
/src
/k8s-manifests (Don't do this)

Good Structure:

/my-app-source (Developers work here)
/my-infra-manifests (ArgoCD watches here)

Step 2: The CI Pipeline (The Builder)

Your CI (e.g., GitLab CI) has one job: Build the image, push to registry, and update the manifest repo. It does not touch the server.

Here is a battle-tested GitLab CI snippet that updates the image tag in the manifest repository using kustomize:

deploy_manifest:
stage: deploy
image: line/kubectl-kustomize:latest
script:
- git config --global user.email "ci-bot@coolvds.com"
- git config --global user.name "CI Bot"
- git clone https://oauth2:${ACCESS_TOKEN}@gitlab.com/org/infra-manifests.git
- cd infra-manifests/overlays/production
- kustomize edit set image my-app=registry.gitlab.com/org/my-app:${CI_COMMIT_SHORT_SHA}
- git commit -am "Bump image to ${CI_COMMIT_SHORT_SHA}"
- git push origin main

This is clean. It creates an audit trail in Git. You know exactly what version ran at 3:00 AM on a Tuesday.

Step 3: The CD Configuration (The Reconciler)

Now, we configure ArgoCD to watch that repo. Deploying ArgoCD on CoolVDS is straightforward given our optimized networking to major helm registries.

First, install ArgoCD (assuming you have a K8s cluster running):

kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Now, define the Application. This is the heart of GitOps. This manifest tells the controller what to sync and where.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: nordic-payment-gateway
namespace: argocd
spec:
project: default
source:
repoURL: 'https://gitlab.com/org/infra-manifests.git'
targetRevision: HEAD
path: overlays/production
destination:
server: 'https://kubernetes.default.svc'
namespace: payments
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

Notice the selfHeal: true. This is the magic flag. If a rogue admin changes a Service port manually, ArgoCD reverts it instantly.

Handling Secrets: The Elephant in the Room

You cannot store raw secrets in Git. If you do, you are already hacked. In 2024, the standard is either Sealed Secrets or External Secrets Operator.

For strict GDPR compliance, often required when hosting on VPS Norway, I prefer External Secrets integrated with a secure vault. However, for simplicity and effectiveness in smaller teams, Bitnami's Sealed Secrets works wonders.

Install the controller:

helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets -n kube-system --set-string fullnameOverride=sealed-secrets-controller sealed-secrets/sealed-secrets

You encrypt the secret locally using the public key from the controller. The result is a text string safe to commit to Git.

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-credentials
namespace: payments
spec:
encryptedData:
password: AgBy3... (safe to commit)
template:
metadata:
name: db-credentials
type: Opaque

Performance Tuning for High-Scale GitOps

When you have 500+ applications syncing, the default settings won't cut it. You will hit API rate limits on your Git provider, or your controller memory will spike.

1. Tune the Repo Server:

Increase the number of concurrent repo server requests in your argocd-cmd-params-cm:

reposerver.parallelism.limit: "50"

2. Resource Limits:

Don't let the application controller get OOMKilled. On a standard CoolVDS 8GB RAM instance, allocate at least:

resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"

Why CoolVDS for GitOps?

We built CoolVDS because we were tired of "cloud-native" often meaning "shared-resource". When your entire deployment pipeline depends on the speed at which a controller can pull, diff, and apply manifests, disk I/O and network latency are the bottlenecks.

Our data center in Oslo ensures that your compliance requirements are met (data stays in Norway), but our NVMe storage backend ensures that your `etcd` database—the brain of Kubernetes—never lags. A lagging `etcd` means failed syncs, phantom drifts, and developer frustration.

Final Thoughts

GitOps requires discipline. It forces you to define everything. But the payoff is sleep. You sleep better knowing that your infrastructure matches your repository, byte for byte. No hidden manual changes, no "snowflake" servers.

Don't let slow I/O kill your reconciliation loops. Deploy a test instance on CoolVDS in 55 seconds and see what raw performance does for your pipeline stability.