8. December 2025 By Julian Paul
GitOps in practice: continuous deployment with ArgoCD and the app-of-apps pattern
Why GitOps? (And what was the problem again?)
In the world of cloud-native development, continuous deployment (CD) is a must. But classic, imperative ‘push’ pipelines quickly reach their limits. Perhaps you are familiar with this: manual triggering, lack of transparency and the constant worry about ‘environment drift’.
Environment drift describes the state in which the actual configuration of an environment (for example, a Kubernetes cluster) differs from the desired configuration defined in version control (Git).
In the context of GitOps, this means that the ‘live’ environment is no longer synchronised with the Git repository. This often occurs when manual changes are made directly to the cluster and these changes are not tracked in the Git repository. Tools such as ArgoCD detect this drift and can either report that a sync is required or automatically reset the environment to the desired state (self-healing).
This is exactly where GitOps comes in. It is an approach that takes the principles of Infrastructure as Code (IaC) and applies them consistently to application deployment. Before we dive deeper into ArgoCD, let's review the core principles:
- Git as the single source of truth: Everything, absolutely everything – from app configuration to infrastructure – is described declaratively in Git.
- Declarative target state: We describe what should run, not how it gets there.
- Continuous synchronisation (pull principle): An agent in the cluster (such as ArgoCD) automatically pulls the changes from Git and compares the live state with the target state.
- Automatic correction: If the live state deviates (drift), the agent restores the target state from Git.
ArgoCD: The GitOps operator for Kubernetes
ArgoCD is an open-source, declarative GitOps tool designed specifically for Kubernetes. It is now a ‘graduated’ project of the Cloud Native Computing Foundation (CNCF) – a clear indicator of its maturity and popularity.
Think of ArgoCD as a tireless agent (a Kubernetes operator) that lives in your cluster. Its sole task is to compare the state of your cluster (the live state) with the target state you have defined in a Git repository.
The workflow is very simple and robust:
- 1. You (or a CI pipeline) change a manifest in Git (for example, you increase the image version of your microservice).
- 2. ArgoCD notices this change (via webhook or regular polling).
- 3. ArgoCD compares the new target state (Git) with the live state (Kubernetes). It determines: ‘Aha, the application is “OutOfSync”.’
- 4. ArgoCD initiates the synchronisation (either automatically or after your manual approval) and applies the changes to the cluster until the live state exactly matches the target state in Git.
Beyond this pure synchronisation, ArgoCD offers other core features that make it so valuable for DevOps teams:
- The visual web interface: This is often the biggest ‘wow effect’. You can see the status of all your applications at a glance. Is something ‘OutOfSync’? Has there been a configuration drift? The UI makes the status of the entire cluster transparent and traceable.
- Automatic self-healing: You can configure ArgoCD to not only report deviations, but also proactively correct them. If a team member manually changes a configuration in the cluster via
kubectl(drift), ArgoCD automatically restores the target state defined in Git. This enforces the ‘single source of truth’. - Flexible synchronisation strategies: Not every change should go live immediately. You can decide for each application: Should the sync be automatic (e.g. in “dev”) or manual after approval (e.g. in “prod”)? You can also specify whether ArgoCD should automatically remove obsolete resources that are no longer in Git (pruning).
Holistic optimisation of IT service organisations
We take your IT to the next level
Our ITMC team optimises IT service organisations strategically, technically and procedurally by consulting and implementing customised solutions.
Discover how we holistically implement DevOps, GitOps and cloud service management in demanding enterprise environments. Our experts support you in combining automated deployment processes, scalable Kubernetes architectures and modern operating models.
The scaling trap: When one tool is not enough
ArgoCD is an excellent solution for the problem of automated application synchronisation. But what happens if you don't just have one application, but a complex microservice architecture with 10, 50 or even 200 services?
This is where the naive approach quickly reaches its limits. You would have to create and maintain a separate ArgoCD application resource (i.e. a YAML manifest) for each individual microservice. This is not only tedious, but also prone to errors.
Imagine you want to set up a completely new environment, let's say ‘staging’. You would now have to copy 50 individual application manifests, customise them and ensure that all services are actually registered in the cluster. If you forget one, it will be missing from the environment. This manual approach is the exact opposite of the robust, automated process we actually want to achieve with GitOps.
It does not scale. So we need a way to manage entire application landscapes centrally and automatically.
Practice: Scaling with the ‘app-of-apps’ pattern
This is where the ‘app-of-apps’ pattern comes in. The idea is as simple as it is ingenious: what if we use ArgoCD to manage ArgoCD applications themselves?
You create a single ArgoCD application, which we call the ‘root app’ or ‘app-of-apps’. This application points to a Git repository. The key difference is that this repository does not contain deployment manifests for your microservices, but only the application manifests for all other services.
The ‘root app’ therefore has only one task: to synchronise other ArgoCD applications. Think of it like a tree: the ‘app-of-apps’ is the trunk and each of your 50 microservice applications is a branch.
How to structure your Git repository
To use this pattern efficiently, a folder structure that clearly separates your environments (e.g. dev, staging, prod) has proven to be effective.
A common approach is to use Helm, the package manager for Kubernetes. You create a so-called umbrella chart. This Helm chart is basically your ‘app of apps’.
Imagine the following repository structure:
gitops-repo/
├── environments/
│ ├── dev/
│ │ ├── values.yaml # Hier werden alle Apps für 'dev' aktiviert
│ ├── staging/
│ │ ├── values.yaml # Hier werden alle Apps für 'staging' aktiviert
│ └── prod/
│ ├── values.yaml # Hier werden alle Apps für 'prod' aktiviert
│
└── app-of-apps-chart/ # Das Helm Umbrella-Chart
├── Chart.yaml
├── templates/
│ └── application.yaml # Template, das ArgoCD-Apps generiert
└── values.yaml # Standard-Werte (meist leer)
The Helm chart as an app generator
The core component is the file app-of-apps-chart/templates/application.yaml. It is not a normal Kubernetes resource, but rather a template that generates ArgoCD application resources.
In simplified terms, it could look like this:
# app-of-apps-chart/templates/application.yaml
{{- range .Values.applications }}
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ .name }}
namespace: argocd
spec:
project: default
source:
repoURL: {{ .repoURL }}
targetRevision: {{ .targetRevision }}
path: {{ .path }}
destination:
server: https://kubernetes.default.svc
namespace: {{ .namespace }}
syncPolicy:
automated:
prune: true
selfHeal: true
---
{{- end }}
The values.yaml as a central control element
The magic now happens in the values.yamlfiles of your environments. To deploy a service in dev, simply enter it there:
# environments/dev/values.yaml
applications:
- name: user-service-dev
namespace: dev
repoURL: "https://git.euer-server.de/user-service.git"
targetRevision: "main"
path: "helm/charts"
- name: payment-service-dev
namespace: dev
repoURL: "https://git.euer-server.de/payment-service.git"
targetRevision: "main"
path: "helm/charts"
# ... weitere 48 Applikationen
You now have an ArgoCD application (the ‘root app’ for dev) that points to environments/dev/. If you want to add a new service, all you have to do is edit this one values.yaml file in the Git repository. ArgoCD and Helm will do the rest, generating the new application resource and deploying your service.
This pattern is the crucial step in elevating GitOps from managing individual services to orchestrating entire landscapes, while remaining clean and scalable even in complex enterprise environments.
Conclusion
GitOps is more than just a buzzword; it is a fundamental shift towards more robust and transparent deployment processes on Kubernetes. Tools such as ArgoCD make the implementation of this pull principle tangible and efficient.
As we have seen, ArgoCD solves the pure deployment problem excellently. However, the decisive step for use in complex enterprise environments is the ‘app-of-apps’ pattern. It is the answer to the scaling trap and enables you to manage dozens or hundreds of applications centrally, automatically and clearly. Only then does GitOps truly become the scalable backbone of your continuous deployment.
Cloud partnerships that make GitOps possible
Modern GitOps approaches such as continuous deployment with ArgoCD and the app-of-apps pattern only reach their full potential on a strong, cloud-native basis. Our cloud partnerships – from hyperscale platforms and managed Kubernetes services to secure European cloud options – provide exactly that foundation. Learn more about how we work with leading technology partners to deliver the infrastructure that reliably powers scalable GitOps architectures, automated deployments and resilient cloud operations.