Learn Calico - GitOps & Policy as Code
Series/Learn Calico/Episode 18
Episode 18 of 23

Learn Calico - GitOps & Policy as Code

This episode covers GitOps and policy as code: managing Installation, IPPool, BGPPeer, and policy as code with Argo CD or Flux, complete with versioning, a review flow, and phased rollout.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

So far we've applied policy with calicoctl apply directly to the cluster. In production, that pattern is risky: no trace, no review, and no easy rollback. Episode 18 changes your workflow into policy as code — all Calico configuration lives in a repository, and clusters reconcile themselves to that repository.

GitOps is not just "store YAML in git". It's about making git the single source of truth, making policy rollouts reviewable like code, and building a complete audit trail.

Why Policy Must Become Code

The Problem with Manual Application

With calicoctl apply, policy changes have no history. Who changed the policy last night? What changes rode along with it? Hard to answer. Worse, there is no easy way to see the difference between the desired policy and what's installed.

The GitOps Solution

With GitOps, every policy change is a commit with a clear message and a reviewed pull request. Clusters automatically reconcile their actual state with the repository contents. Unwanted changes are easy to detect because the cluster reports "out of sync".

The Calico Repository Structure

Organize Calico resources in a folder separate from application manifests:

Policy repository structure
calico/
  installation.yaml
  ippools/
    default-ipv4-ippool.yaml
  bgp/
    bgpconfiguration.yaml
    bgppeers.yaml
  policies/
    tiers/
    global/
    namespace/

This structure separates infrastructure configuration (Installation, IPPool) from security policy, so review authority can be split: the platform team for the former, the application teams for the latter.

One Example Resource

Installation as code
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  calicoNetwork:
    ipPools:
      - name: default-ipv4-ippool
        cidr: 192.168.0.0/16
        blockSize: 26
        encapsulation: IPIP

This resource is identical to what you'd write by hand — only now it's managed by git.

Rolling Out with Argo CD or Flux

Argo CD: An Application for Calico

With Argo CD, create an Application pointing at the calico/ folder:

Argo CD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: calico-policy
  namespace: argocd
spec:
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  project: platform
  source:
    repoURL: https://git.example.com/infra.git
    path: calico
    targetRevision: main
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

automated.prune and automated.selfHeal make Argo CD remove resources that disappeared from git and revert manual changes back to the git state.

Flux: Kustomization

With Flux, create a Kustomization pointing at the same source:

Flux Kustomization
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: calico-policy
  namespace: flux-system
spec:
  interval: 5m
  path: ./clusters/prod/calico
  prune: true
  sourceRef:
    kind: GitRepository
    name: infra

Both approaches are equally valid; pick the one you already use for other workloads so operations stay uniform.

Rollout Practices

Verify synchronization
kubectl get application calico-policy -n argocd
kubectl get application calico-policy -n argocd -o jsonpath='{.status.sync.status}'
calicoctl get globalnetworkpolicy -o wide

calicoctl get globalnetworkpolicy -o wide compares the installed policy with what's in git — the foundation of review and audit.

Versioning, Review, and Phased Rollout

Policy Versioning

Store policy in a sensible order: a folder per environment (staging/, prod/), and use release tags for major changes. Breaking changes — like a new global default deny — deserve their own major version.

The Review Flow

Every policy change goes through: branch → pull request → review → merge to main. Put a mandatory label on PRs that touch tier: security, because that part has the biggest impact:

Review before merge
git checkout -b add-payments-deny
git add calico/policies/namespace/
git commit -m "feat(calico): default deny untuk namespace payments"
git push origin add-payments-deny

Phased Rollout

Don't let a merge go live in production all at once. Apply to staging first, watch the metrics, then promote to production:

Environment progression
staging (not production) -> one production namespace -> full production

Combine this with automated smoke tests: after sync, run a kubectl exec to confirm core applications can still communicate.

Calico GitOps Pitfalls

Resources That Should Not Be Pruned Carelessly

Installation and FelixConfiguration are high-impact resources. Be careful with prune: true if the policy folder is incomplete — Argo CD could delete an IPPool that's still in use. Always keep complete resources in git.

Conflict with Out-of-Band Tools

If multiple tools write the same resource (for example a manual script and Argo CD), the result is a state war. Establish one source of truth: git, and keep other tools read-only with respect to Calico resources.

Wrap-Up

Episode 18 turns Calico configuration from ad-hoc commands into managed code: a structured repository, Argo CD or Flux as the applier, a review flow per change, and a safe phased rollout.

Key takeaways:

  • Policy as code makes every change recorded and reviewable.
  • Separate infrastructure and policy folders in one repository.
  • Both Argo CD and Flux can enforce the git state.
  • selfHeal and prune keep the cluster always matching git.
  • Roll out in phases: staging first, then production per namespace.
  • Be careful pruning high-impact resources like Installation and IPPool.

Next, in episode 19, we cover performance and troubleshooting — diagnosing with calicoctl, Felix and typha logs, common cases like pods that can't communicate, policy rejecting traffic, BGP not coming up, IPAM problems, and version upgrades.