Skip to content
arrow_back

Blog

Navigation

© 2026 Yosef Adi Sulistyo

Article

GitOps with ArgoCD on Self-Managed Kubernetes

A practical account of adopting GitOps principles on bare-metal Kubernetes using ArgoCD, GitLab CI, and Ansible — and why the discipline matters more than the tooling.

kubernetesgitopsargocddevsecopsinfrastructure
April 10, 20263 min read

GitOps is often presented as a Kubernetes-native pattern, but the core idea predates any specific tooling: the Git repository is the single source of truth for system state, and automated processes reconcile the actual system toward that state continuously.

When we moved from cloud-managed Kubernetes to self-managed bare-metal clusters, GitOps became more important, not less. Without a cloud provider handling the control plane, operational discipline has to come from the team.

The Stack

  • GitLab CI — builds, tests, vulnerability scanning (Grype), and image tagging
  • ArgoCD — watches Git for desired state, reconciles the cluster
  • Ansible + Semaphore — provisions and configures nodes; handles OS-level changes outside Kubernetes
  • HashiCorp Vault — secrets management; ArgoCD integrates via the Vault plugin for secret injection at deploy time

The Flow

A developer pushes code. GitLab CI runs the pipeline: build the image, scan for CVEs with Grype, tag with the commit SHA, push to the registry, and update the Helm values file (or Kustomize overlay) in the deployment repository with the new image tag.

ArgoCD detects the change in the deployment repo and syncs the cluster. If the sync fails (manifests are invalid, resources conflict), ArgoCD surfaces the error and halts — the cluster does not end up in an unknown state.

Why Self-Managed Changes the Calculus

On EKS or GKE, you can fall back to the cloud console if something goes wrong. On bare metal, the cluster is what you made it. Every change needs to be in Git. Emergency manual kubectl apply commands are dangerous because they create drift — the cluster state no longer matches the declared state, and the next ArgoCD sync will revert or conflict.

This forces a useful discipline: if you want to make a change, write the manifest, commit it, let the pipeline run. It is slower for one-off fixes but dramatically better for long-term maintainability and incident review.

Ansible for the Parts Kubernetes Cannot Touch

ArgoCD manages what is inside Kubernetes. Ansible manages everything else: node OS configuration, kernel parameters, Ceph storage mount points, network interface setup, and cluster upgrades. Semaphore provides a simple web UI and audit log for Ansible runs, which matters for a team where not everyone is comfortable with the CLI.

Integrated Security

Grype scans container images for known CVEs before they reach the registry. CrowdSec runs as a daemonset providing IPS at the node level. Vault handles secrets — no credentials in Git, ever.

Takeaway

The tooling is secondary. The principle is: the Git repository knows what the system should look like, and anything that deviates from it is automatically corrected or flagged. On bare metal, that principle is what keeps a small team from accumulating untracked state that eventually causes an outage at 2am.