DevOps & CI/CD18 min read·By Liyabona Saki·

GitOps with ArgoCD — The Modern Kubernetes Deployment Strategy

A complete, production-grade guide to GitOps with ArgoCD on Kubernetes — workflow, architecture, multi-environment promotion, auto-sync, rollbacks and Spring Boot deployments.

Advertisement

Introduction

GitOps is the practice of using Git as the single source of truth for both application and infrastructure state. Instead of running kubectl apply from a CI runner, you commit a desired-state manifest to a repository — and a controller running inside the cluster continuously reconciles the live state to match it.

ArgoCD is the most widely adopted GitOps controller for Kubernetes. It watches one or more Git repositories, detects drift, and re-applies the declared state automatically. The result is deployments that are auditable (every change is a commit), reversible (every rollback is a git revert), and consistent across every environment.

This tutorial walks through the full GitOps lifecycle with ArgoCD: the conceptual workflow, the underlying architecture, multi-environment promotion, automatic sync, rollbacks, and a complete worked example deploying a Spring Boot service. By the end you will be able to set up a production-ready GitOps pipeline on any Kubernetes cluster.

Why GitOps matters

Three forces are pushing teams away from imperative kubectl-driven deployments:

  • Auditability and compliance. Every change to production must be traceable to a person, a time, and a reason. A Git commit gives you all three for free.
  • Cluster sprawl. Teams now run dev, QA, staging and multiple production clusters. Configuring each one manually does not scale and inevitably drifts.
  • Disaster recovery. When a cluster is lost, you need to rebuild from a known good state in minutes. GitOps reduces that to "point ArgoCD at the repo and wait."

GitOps also unlocks several engineering wins that are hard to achieve otherwise: declarative diff between environments, pull-request-based change review for infrastructure, and a single mental model for both code and operations.

Architecture

GitOps Workflow with ArgoCD

DEVELOPERSOURCE OF TRUTHGITOPS CONTROLLERCLUSTERWORKLOADcommitwatch / pullapply manifestsdeployDevelopergit pushGit RepositoryManifests · Helm · KustomizeArgoCDAuto-Sync · RollbackKubernetes ClusterReconciled StateRunning ApplicationPods · Services
Developers push manifests to Git, ArgoCD continuously reconciles the desired state into the Kubernetes cluster, and the live application reflects every commit.

Real-world use cases

GitOps with ArgoCD is the default deployment pattern in modern Kubernetes shops. Common scenarios include:

  • Microservices platforms where dozens of services share one infrastructure pipeline.
  • Regulated industries (banking, healthcare, telco) that need a complete audit trail of every production change.
  • Edge and multi-cluster fleets where a single source of truth must be reconciled to many distant clusters.
  • Platform engineering teams that ship internal developer platforms — developers commit, the platform deploys.

Architecture overview

ArgoCD is not magic. It is a set of pods running inside your cluster that watches a Git repo and reconciles state against the Kubernetes API server.

The three core components are:

  • Repo Server — clones the Git repository and renders manifests (Helm, Kustomize, plain YAML, Jsonnet).
  • Application Controller — diffs the rendered manifests against live state and applies changes.
  • ArgoCD Server (API + UI) — serves the dashboard, gRPC API and SSO integration.

Architecture

ArgoCD Architecture

DEVELOPERGITARGOCDKUBERNETES APIWORKLOADSgit pushpoll / webhookreconcileDeveloperGitHub Repositoryapp + infra manifestsArgoCD ServerRepo Server · App ControllerKubernetes API Serverkubectl apply -fConfigMapsSecretsDeploymentsPodsServicesClusterIP / LB
ArgoCD Server tracks the GitHub repository and applies ConfigMaps, Secrets, Deployments and Services to the Kubernetes API server, which schedules the application pods.

The Application Controller calls the Kubernetes API server using a service account, so RBAC works exactly the same way as for any other in-cluster operator. ConfigMaps, Secrets, Deployments and Services are reconciled in dependency order.

Step 1 — Install ArgoCD

Create a dedicated namespace and install the upstream manifests:

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

Wait for the controllers to become ready:

bash
kubectl -n argocd rollout status deploy/argocd-server
kubectl -n argocd rollout status deploy/argocd-repo-server
kubectl -n argocd rollout status statefulset/argocd-application-controller

Step 2 — Access the UI

Forward the API server port locally:

bash
kubectl -n argocd port-forward svc/argocd-server 8080:443

The initial admin password is stored in a secret:

bash
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d ; echo

Log in at https://localhost:8080. In production you would expose the server via an Ingress with TLS and disable the bootstrap admin account in favour of SSO (OIDC, GitHub, Okta, Azure AD).

Step 3 — Connect a Git repository

Create a private deploy key in your Git provider and register it with ArgoCD:

bash
argocd repo add git@github.com:your-org/k8s-manifests.git \
  --ssh-private-key-path ~/.ssh/argocd_deploy

For HTTPS with a personal access token:

bash
argocd repo add https://github.com/your-org/k8s-manifests.git \
  --username git --password "$GITHUB_TOKEN"

Step 4 — Create an Application

An ArgoCD Application is a CRD that points at a path in a repo and a destination on a cluster.

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: orders-service
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/k8s-manifests.git
    targetRevision: main
    path: apps/orders-service/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: orders
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        maxDuration: 3m
        factor: 2

Apply it:

bash
kubectl apply -f orders-service-app.yaml

Within seconds, ArgoCD pulls the manifests and applies them to the orders namespace.

Step 5 — Auto-sync, prune and self-heal

The three flags above are the heart of production GitOps:

  • automated: {} — apply new commits without manual intervention.
  • prune: true — delete resources that no longer exist in Git.
  • selfHeal: true — revert manual kubectl changes back to the Git-declared state.

Together they enforce that Git is the only way to change the cluster. Engineers who run ad-hoc kubectl edit will see their changes reverted within seconds — a feature, not a bug.

Step 6 — Rollbacks

Because every state is a commit, rollback is a Git operation:

bash
git revert <bad-commit-sha>
git push origin main

ArgoCD detects the new commit and reconciles the cluster back to the previous state. From the UI, you can also click History → Rollback to pin a previous revision without touching Git, which is useful during an incident before the postmortem commit lands.

Step 7 — Deploying a Spring Boot application

A typical layout for a Spring Boot service:

text
apps/orders-service/
  base/
    deployment.yaml
    service.yaml
    configmap.yaml
  overlays/
    dev/      kustomization.yaml
    qa/       kustomization.yaml
    staging/  kustomization.yaml
    production/ kustomization.yaml

A minimal base/deployment.yaml:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders
spec:
  replicas: 3
  selector:
    matchLabels: { app: orders }
  template:
    metadata:
      labels: { app: orders }
    spec:
      containers:
        - name: orders
          image: ghcr.io/your-org/orders:1.4.2
          ports: [{ containerPort: 8080 }]
          readinessProbe:
            httpGet: { path: /actuator/health/readiness, port: 8080 }
            initialDelaySeconds: 10
          livenessProbe:
            httpGet: { path: /actuator/health/liveness, port: 8080 }
            initialDelaySeconds: 30
          resources:
            requests: { cpu: "200m", memory: "512Mi" }
            limits:   { cpu: "1",    memory: "1Gi" }

The production overlay bumps replicas and patches the image tag:

yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
patches:
  - target: { kind: Deployment, name: orders }
    patch: |-
      - op: replace
        path: /spec/replicas
        value: 6
images:
  - name: ghcr.io/your-org/orders
    newTag: 1.4.2

When CI builds image 1.4.3, it opens a PR that bumps the newTag field. Merge the PR — ArgoCD does the rest.

Multi-environment GitOps

For more than one cluster, define an environment per branch or per directory and let ArgoCD's App-of-Apps pattern manage them centrally.

Architecture

Multi-Environment GitOps

GIT REPOSITORYENVIRONMENTSGITOPSCLUSTERSsyncpromoteGit Repositoryconfig-repoenvs/devenvs/qaenvs/stagingenvs/productionArgoCDApp-of-AppsDev ClusterEKS devQA ClusterEKS qaStaging ClusterEKS stagingProduction ClusterEKS prod
A single Git repository branches per environment. ArgoCD reads each path and deploys it to an isolated Kubernetes cluster — Dev, QA, Staging and Production share one pipeline with different targets.

A root Application points at a directory of child Applications, one per environment:

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: platform-root
  namespace: argocd
spec:
  source:
    repoURL: https://github.com/your-org/k8s-manifests.git
    path: envs
    targetRevision: main
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated: { prune: true, selfHeal: true }

Each child Application targets a different cluster via its destination.server and a different overlay via its source.path. Promotion from staging to production becomes a pull request that copies one image tag from envs/staging to envs/production.

Configuration examples

Restrict which projects a team can deploy with an AppProject:

yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: orders-team
  namespace: argocd
spec:
  sourceRepos:
    - https://github.com/your-org/k8s-manifests.git
  destinations:
    - server: https://kubernetes.default.svc
      namespace: orders
    - server: https://kubernetes.default.svc
      namespace: orders-staging
  clusterResourceWhitelist: []
  namespaceResourceBlacklist:
    - group: ""
      kind: ResourceQuota

Configure notifications to Slack on sync failures:

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.slack: |
    token: $slack-token
  trigger.on-sync-failed: |
    - when: app.status.operationState.phase in ['Error', 'Failed']
      send: [app-sync-failed]
  template.app-sync-failed: |
    message: "🚨 {{.app.metadata.name}} sync failed: {{.app.status.operationState.message}}"

Security considerations

GitOps changes the security model — the cluster pulls from Git instead of CI pushing to the cluster. Tighten the following:

  • Repository access. Use a dedicated deploy key or short-lived OIDC token. Never share a personal access token.
  • Signed commits. Require GPG-signed commits on the deployment branch and verify with ArgoCD's gpg-keys config.
  • Secrets management. Never commit raw secrets. Use Sealed Secrets, External Secrets Operator, SOPS or HashiCorp Vault.
  • RBAC. Scope the ArgoCD service account to the namespaces it actually manages. Use AppProject whitelists per team.
  • SSO and audit logs. Disable the bootstrap admin once SSO is wired. Ship the ArgoCD audit log to your SIEM.
  • Network. Restrict the ArgoCD server to internal users via Ingress + private DNS, or front it with a zero-trust proxy.

Production best practices

  • Use Kustomize or Helm overlays per environment — never copy-paste manifests between dev and prod.
  • Pin image tags by SHA, not latest. A digest is the only fully reproducible reference.
  • Enable progressive delivery via Argo Rollouts (canary, blue/green, analysis) for high-risk services.
  • Set resource requests and limits on every workload, including ArgoCD itself.
  • Run argocd-image-updater to automatically open PRs when new image versions are published.
  • Monitor sync status with Prometheus (argocd_app_sync_status) and alert on prolonged OutOfSync.
  • Back up Application CRDs and the argocd-cm ConfigMap so the controller itself can be restored from cold.

Common mistakes

  • Storing secrets in plain YAML. Always seal or encrypt.
  • Sharing one Application across multiple clusters. One Application = one cluster + one path. Use App-of-Apps for fleets.
  • Skipping selfHeal. Without it, manual edits silently drift from Git.
  • Long-lived branches per environment with cherry-picks. This breaks the audit trail. Prefer overlays + tag promotion.
  • Ignoring SyncWaves and hooks. Database migrations must run before app pods roll. Annotate jobs with argocd.argoproj.io/sync-wave: "-1".
  • Granting cluster-admin to the ArgoCD service account. Scope it down.

Troubleshooting

  • ComparisonError: rpc error: code = Unknown — usually a Git auth failure. Re-add the repository.
  • App stuck in Progressing — a probe is failing. Run kubectl describe pod in the target namespace.
  • OutOfSync after every commit — Kustomize or Helm rendering produces non-deterministic output (e.g. random suffixes). Pin generators or use spec.ignoreDifferences.
  • PermissionDenied on apply — the ArgoCD service account is missing RBAC for that resource type. Add a Role/ClusterRole.
  • Sync hangs forever — a webhook validating admission controller is rejecting the manifest. Check the cluster audit log.

FAQ

Is ArgoCD better than Flux? Both are CNCF-graduated GitOps controllers. ArgoCD has a richer UI and Application abstraction; Flux is more composable and integrates tightly with Kustomize and Helm. Either is production-ready.

Do I need a separate Git repo for manifests? A separate "config repo" is the most common pattern. It decouples application release cadence from infrastructure change review and keeps the deployment audit trail clean.

How do I deploy database migrations? Run them as a Kubernetes Job with argocd.argoproj.io/sync-wave: "-1" and argocd.argoproj.io/hook: PreSync so they finish before the app rolls.

Can ArgoCD deploy to clusters it does not run in? Yes. Register external clusters with argocd cluster add. The controller stores a kubeconfig as a Secret and reconciles remotely.

How do I roll back without touching Git? Use the UI's History → Rollback action. ArgoCD pins a revision until the next manual sync. Always follow up with a Git revert so the next reconcile does not undo the rollback.

Does GitOps work for stateful workloads? Yes, with care. Use StatefulSets, persistent volume claims and operators (e.g. CloudNativePG, MongoDB Operator). Treat database schema migrations as code changes that flow through the same PR process.

How do I integrate with Helm? Set source.helm with valueFiles per environment. ArgoCD renders the chart server-side via the Repo Server.

What about progressive delivery (canary, blue/green)? Add Argo Rollouts. It introduces a Rollout CRD that replaces Deployment and integrates with metrics providers for automatic analysis.

How do I prevent accidental production deploys? Use AppProject destination whitelists, require two-person review on the production overlay path with CODEOWNERS, and disable automated sync on the production Application so promotion requires a manual click.

Is ArgoCD safe for hundreds of Applications? Yes. Tune --repo-server-parallelism-limit, shard the Application Controller with controller.replicas, and use webhook-based Git updates instead of polling.

Key takeaways

  • GitOps makes Git the single source of truth for cluster state.
  • ArgoCD continuously reconciles the cluster to match the Git-declared manifests.
  • Auto-sync + prune + self-heal is the production trifecta.
  • Multi-environment promotion is a pull request that moves an image tag.
  • Rollbacks are Git reverts — fully auditable, fully reversible.
  • Always pair GitOps with sealed secrets, signed commits, and scoped RBAC.

Related tutorials

Conclusion

GitOps with ArgoCD turns deployments from a series of ad-hoc commands into a disciplined, auditable, reversible workflow. The investment to set it up is small — a namespace, a few CRDs, a Git repo — and the payoff compounds across every environment, every team and every incident response. Adopt the patterns in this tutorial early, and you will spend the rest of your platform's life shipping faster instead of debugging kubectl apply history.

Architecture

Kubernetes Deployment Architecture

CLIENTINGRESSSERVICEPODSDATAHTTPSUsersIngressNGINX / ALBServiceClusterIPPodReplica 1PodReplica 2PodReplica 3PostgreSQLManagedRedisCache
Ingress routes external traffic to a Service that load-balances across replica Pods. Pods read config from ConfigMaps and persist via managed databases.

TL;DR

Key takeaways

  • Understand the core concepts behind GitOps with ArgoCD — The Modern Kubernetes Deployment Strategy in a production context.
  • Apply the patterns to real DevOps & CI/CD systems, not just toy examples.
  • Recognize the trade-offs, failure modes, and operational concerns before adopting them.
  • Get a clear path to the next step — related tutorials, tools, and reference architectures.

Avoid these

Common mistakes

  • 1. Copy-pasting code without understanding the trade-offs

    It's tempting to ship a snippet from a blog post into production, but DevOps & CI/CD patterns only work when the failure modes are understood. Always reason about timeouts, retries, and consistency.

  • 2. Skipping observability from day one

    Structured logs, metrics, and traces are not optional. Wire them in before you ship — debugging DevOps & CI/CD systems without them is painful and expensive.

  • 3. Optimizing too early

    Premature caching, sharding, or microservice extraction adds operational cost. Validate the bottleneck with real measurements first.

  • 4. Ignoring security defaults

    Secrets in env files, open management ports, missing RBAC — these are the most common production incidents. Treat security as part of the definition of done.

Ship it safely

Production best practices

Apply these before promoting GitOps with ArgoCD — The Modern Kubernetes Deployment Strategy to a real production environment.

Scalability

Design DevOps & CI/CD services to scale horizontally. Keep request handlers stateless, push session and cache state to external stores (Redis, the database), and benchmark p95/p99 latency under realistic load before tuning.

Monitoring & Observability

Emit metrics (RED/USE), structured JSON logs, and distributed traces from day one. Wire dashboards and alerts to SLOs you actually care about — error rate, latency, saturation — not vanity metrics.

Logging

Log with correlation IDs, never log secrets or PII, and centralize logs (ELK, Loki, CloudWatch). Use levels deliberately: INFO for state changes, WARN for recoverable issues, ERROR for incidents.

Security

Apply least-privilege IAM, rotate secrets through a vault, validate every input, and patch dependencies on a schedule. For HTTP services, enable TLS everywhere and set sensible security headers.

Testing

Layer unit, integration, and contract tests. Run them in CI on every PR, and add smoke tests post-deploy. For DevOps & CI/CD systems, also run chaos and load tests before a major release.

Reliability & Rollouts

Ship with health checks, readiness probes, graceful shutdown, and a rollback strategy. Prefer canary or blue/green deploys over big-bang releases.

Questions

Frequently asked questions

Is this tutorial up to date?

Yes. This tutorial was last reviewed and updated on June 2, 2026. We revisit popular DevOps & CI/CD tutorials regularly to keep them aligned with current best practices.

What level is this tutorial aimed at?

It is written for working developers with some backend experience. Beginners can still follow along, and senior engineers will find production-grade patterns and trade-off discussions.

Do I need to follow every step in order?

The walkthrough is sequential because each step depends on the previous one. If you only need a specific concept, the table of contents at the top of the article lets you jump straight to that section.

Where can I find the source code?

The full source code is available on GitHub: https://github.com/masterlabsystems/gitops-argocd-demo. Fork it, run it locally, and adapt it to your own project.

Go deeper

Further reading

Source Code

Get the full project on GitHub

View repo →
#GitOps#ArgoCD#Kubernetes#CI/CD#DevOps

More From the Channel

Follow the full tutorial series on YouTube

The MasterLabSystems channel publishes in-depth, project-based tutorials on Java, Spring Boot, microservices, Docker, Kubernetes, AWS and DevOps — the same topics covered on this site, with full code walkthroughs.

Stay in the Loop

Get the next tutorial in your inbox

next tutorial →

Infrastructure as Code with Terraform — Deploy AWS Resources Like a Pro

Related tutorials