Skip to main content

Lesson: Pull-Based Deployment with Argo CD

What you'll learn

  • The GitOps principle: Git as the single source of truth for what runs in your cluster.
  • What an Argo CD Application is, what sync means, and how drift detection works.
  • How pull-based deployment contrasts with the push-based CI you've seen so far.
  • How to deploy an app to the lab's live Kubernetes cluster with Argo CD.

By the end you can explain GitOps to a teammate and define an Argo CD Application that deploys to the lab cluster.

The lesson

In the concepts chapter you met pull deployment: instead of the CI pipeline pushing changes into production, a tool inside the environment watches Git and pulls changes in. GitOps is that idea made into a discipline, and Argo CD is the most popular tool for doing it on Kubernetes. This chapter shows how it works and has you deploy to the lab's real cluster (master 10.100.100.7).

1. The GitOps principle

GitOps rests on one rule: the desired state of your system is described declaratively in Git, and an automated agent continuously makes the cluster match Git.

"Declaratively" means you describe what you want (e.g. "3 replicas of myapp version abc123"), not how to get there. Kubernetes manifests (YAML) are already declarative, which is why GitOps and Kubernetes fit so well.

The four GitOps principles, in plain words:

  1. Declarative — the whole system is described as data, not scripts.
  2. Versioned in Git — that description lives in Git, so it has history, review, and rollback.
  3. Pulled automatically — an agent applies the Git state; no human runs kubectl apply.
  4. Continuously reconciled — the agent constantly checks that reality matches Git and corrects any difference.

The practical payoff: Git is the single source of truth. Want to know what's running? Read the repo. Want to roll back? git revert. Want an audit trail? It's the commit history.

2. Push CI vs pull GitOps

Compare the two models for the deploy step:

  PUSH (classic CI deploy):
  +-----------+   builds image   +-----------+   kubectl apply   +-----------+
  | CI runner |----------------> | registry  |                   |  cluster  |
  | (Gitea,   |                  |10.100.100.6|<-- CI also reaches|10.100.100.7|
  |  .11)     |---- has cluster credentials --- and pushes ----->|           |
  +-----------+                  +-----------+                   +-----------+
       The CI runner needs production credentials. It initiates the change.

  PULL (GitOps with Argo CD):
  +-----------+   builds image   +-----------+
  | CI runner |----------------> | registry  |
  | (.11)     |                  |10.100.100.6|
  +-----+-----+                  +-----------+
        | updates a manifest in Git (image tag = new sha)
        v
  +-----------+    Argo CD watches & pulls    +-----------+
  | Git repo  |<------------------------------|  Argo CD   |
  | (manifests)|                              | (in cluster|
  +-----------+                               |  .7)       |
                                              +-----------+
       CI only touches Git. Argo CD, inside the cluster, pulls and applies.

The crucial difference: in the pull model, production credentials never leave the cluster. Your CI runner only needs write access to a Git repo and the image registry — not to the cluster. That shrinks the blast radius if your CI is ever compromised, and it means every change to production is a Git commit you can see and revert.

3. The Argo CD Application

Argo CD runs inside your Kubernetes cluster. You tell it what to manage by creating an Application — itself a Kubernetes resource. An Application answers three questions: where is the desired state (source)?, where should it go (destination)?, and how should it sync?

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://gitea.example.com/intern/myapp-deploy.git
    targetRevision: main        # which branch/tag to track
    path: k8s                   # folder of manifests within the repo
  destination:
    server: https://kubernetes.default.svc   # the cluster Argo CD lives in
    namespace: myapp
  syncPolicy:
    automated:
      prune: true               # delete resources removed from Git
      selfHeal: true            # undo manual changes that drift from Git

Read it as a sentence: "Watch the k8s/ folder on the main branch of this repo; keep namespace myapp in this cluster matching it; do it automatically."

4. Sync, drift, and self-heal

Two concepts make Argo CD powerful:

  • Sync = the act of making the cluster match Git. Argo CD compares the manifests in Git (desired) with what's actually running (live). If they differ, the Application is OutOfSync; running a sync applies the Git version. With syncPolicy.automated, this happens on its own whenever Git changes.

  • Drift detection = Argo CD continuously notices when the live cluster diverges from Git — for example if someone manually runs kubectl edit and bumps the replica count. The Application goes OutOfSync and Argo CD shows you exactly what differs. With selfHeal: true, it automatically reverts the cluster back to what Git says. Git wins — always.

  Git says: replicas=3        Live cluster: replicas=5  (someone edited it)
                |                          |
                +-----> Argo CD compares <-+
                            |
                  status = OutOfSync, diff shown
                            |
                 selfHeal -> sets replicas back to 3

prune: true extends this to deletions: if you remove a resource from Git, Argo CD removes it from the cluster too. This is what "Git is the source of truth" really means in practice — the cluster has no state that isn't in Git.

5. How a deploy actually flows in the lab

Putting the whole module together, here's the end-to-end flow you'll build across the assignments:

  1. You push app code to Gitea. The Actions runner on 10.100.100.11 builds a container image tagged with the commit SHA and pushes it to the registry at 10.100.100.6 (Module chapter 2).
  2. The image tag in your deployment manifest (in a Git repo Argo CD watches) is updated to the new SHA — either by hand at first, or automated later.
  3. Argo CD, running in the cluster (10.100.100.7), sees the manifest changed, marks the Application OutOfSync, and syncs — pulling the new image and rolling out the update.
  4. If anyone manually messes with the running app, drift detection flags it and selfHeal puts it back.

You never run kubectl apply against production yourself. You commit to Git; Argo CD does the rest.

6. When push is still fine

GitOps isn't mandatory for everything. For a tiny project, a push-based kubectl apply step in your CI is simpler and perfectly acceptable. GitOps shines when you have multiple environments or clusters, want strong audit/rollback, and want to keep cluster credentials out of CI. As the number of things you deploy grows, pull-based GitOps scales better and is safer.

Dig deeper

Search terms

  • what is gitops explained simply
  • argo cd application crd tutorial
  • argo cd sync drift self heal
  • push vs pull deployment kubernetes argo cd
  • argo cd automated sync prune selfheal
  • gitops single source of truth git

Check yourself

  1. State the one rule that GitOps rests on.
  2. In the pull model, why don't your CI runner need credentials to the cluster?
  3. What three questions does an Argo CD Application answer?
  4. What does it mean for an Application to be OutOfSync, and what does selfHeal: true do about it?
  5. Walk through, in order, what happens in the lab from "you push app code" to "the new version is running" without you ever typing kubectl apply.