π Direct Answer β Argo CD app of apps Python microservice tutorial
Argo CD app of apps Python microservice tutorial shows how to deploy a Python microservice stack using the App of Apps pattern in Argo CD by defining a parent Application that references child Applications for each service, letting Argo CD reconcile the entire stack automatically.
π Table of Contents
- π Direct Answer β Argo CD app of apps Python microservice tutorial
- π Architecture β Why It Scales
- π Python Service β What the Container Looks Like
- π¦ Helm Chart β How to Package the Service
- π Deployment Manifest
- π§ Service Manifest
- π Argo CD β How to Synchronize the Stack
- π Parent Application
- π§© Child Applications
- π‘ Observability β Adding Health Checks
- π© Final Thoughts
- β Frequently Asked Questions
- How does the App of Apps pattern differ from using multiple independent Argo CD Applications?
- Can I use Kustomize instead of Helm for the child Applications?
- What is the recommended way to handle secret management for the Python services?
- π References & Further Reading
π Architecture β Why It Scales
A parent Application in Argo CD is a Kubernetes custom resource that references multiple child Applications, enabling hierarchical sync and version control across the entire microservice stack.
# parent-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: python-microservices namespace: argocd
spec: project: default source: repoURL: https://github.com/example/python-microservices targetRevision: HEAD path: apps destination: server: https://kubernetes.default.svc namespace: default syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true
What this does:
- metadata.name: identifier for the parent Application.
- spec.source.repoURL: Git repository that stores child Application manifests.
- spec.syncPolicy.automated.prune: removes resources that are no longer defined.
- syncOptions.CreateNamespace: ensures the target namespace exists before applying resources.
Why not use a single large Helm chart? A monolithic chart forces all services to share a single release cycle, whereas the App of Apps pattern lets each microservice evolve independently while still being managed centrally.
Key point: The parent Application provides a single point of control, yet each child can be versioned and rolled back separately, reducing blast radius during failures.
π Python Service β What the Container Looks Like
A Dockerfile builds a reproducible image that contains the Python runtime, dependencies, and the application code, ensuring consistent behavior across environments.
# Dockerfile
FROM python:3.11-slim # Install build dependencies
RUN apt-get update && apt-get install -y -no-install-recommends gcc libpq-dev && rm -rf /var/lib/apt/lists/* # Create nonβroot user
RUN useradd -create-home appuser
WORKDIR /app
COPY requirements.txt .
RUN pip install -no-cache-dir -r requirements.txt # Copy source
COPY src/ . # Switch to nonβroot user
USER appuser EXPOSE 8080
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
What this does:
- FROM python:3.11-slim: base image with minimal OS footprint.
- RUN apt-get β¦: installs compiledβextension build tools needed for some Python packages.
- USER appuser: runs the container as a nonβroot user for security.
- CMD β¦: starts the FastAPI server with uvicorn.
Why not use a preβbuilt image from Docker Hub? Building the image locally guarantees that compiled dependencies match the exact OS version of the target environment, avoiding runtime ABI mismatches.
Build and push the image: (Also read: π Creating aws s3 bucket policy with python boto3 tutorial)
$ docker build -t ghcr.io/example/python-service:v1.0 .
Sending build context to Docker daemon 12.34MB
Step 1/10: FROM python:3.11-slim
...
Successfully tagged ghcr.io/example/python-service:v1.0
$ docker push ghcr.io/example/python-service:v1.0
The push refers to repository [ghcr.io/example/python-service]
...
Digest: sha256:3b2c5f...
π¦ Helm Chart β How to Package the Service
A Helm chart bundles Kubernetes manifests and default values, allowing the same chart to be reused for multiple environments.
# Chart.yaml
apiVersion: v2
name: python-service
description: Helm chart for the Python microservice
type: application
version: 0.1.0
appVersion: "1.0"
What this does: declares chart metadata; appVersion tracks the Docker image tag.
π Deployment Manifest
The Deployment defines pod replicas, container image, and health probes.
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: {{ include "python-service.fullname" . }}
spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app: {{ include "python-service.name" . }} template: metadata: labels: app: {{ include "python-service.name" . }} spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" ports: - containerPort: 8080 livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 30 readinessProbe: httpGet: path: /ready port: 8080 initialDelaySeconds: 5 periodSeconds: 15
What this does:
- replicas: number of pod instances, scaling horizontally.
- livenessProbe / readinessProbe: Kubernetes health checks that restart unhealthy pods and control service traffic.
-
image.repository & image.tag: injected from
values.yaml, enabling version upgrades without editing manifests.
π§ Service Manifest
The Service exposes the pods on a stable ClusterIP for internal traffic. (Also read: π CI/CD Python App Service vs AKS β Which One Should You Use?)
# templates/service.yaml
apiVersion: v1
kind: Service
metadata: name: {{ include "python-service.fullname" . }}
spec: selector: app: {{ include "python-service.name" . }} ports: - protocol: TCP port: 80 targetPort: 8080
Why not use a LoadBalancer Service here? The microservice is intended to be accessed only via an Ingress controller; exposing a LoadBalancer would allocate a public IP per service, increasing cost and attack surface. (More onPythonTPoint tutorials)
Install the chart into the cluster:
$ helm upgrade -install python-service ./python-service \ -namespace default \ -create-namespace
Release "python-service" does not exist. Installing now.
NAME: python-service
LAST DEPLOYED: Sun Oct 1 12:34:56 NAMESPACE: default
STATUS: deployed
REVISION: 1
π Argo CD β How to Synchronize the Stack
Argo CD Applications declare the source repository, target namespace, and sync policy for each Helm chart, enabling continuous delivery.
π Parent Application
The parent Application references a directory that contains child Application manifests for each microservice.
# apps/python-microservices/parent.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: python-microservices
spec: project: default source: repoURL: https://github.com/example/python-microservices targetRevision: HEAD path: apps/children destination: server: https://kubernetes.default.svc namespace: default syncPolicy: automated: prune: true selfHeal: true
What this does:
- source.path: points to the folder containing child Application YAML files.
- syncPolicy.automated.selfHeal: forces Argo CD to correct drift automatically.
π§© Child Applications
Each child Application points to a Helm chart for a single microservice.
# apps/children/python-service.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: python-service
spec: project: default source: repoURL: https://github.com/example/python-microservices targetRevision: HEAD chart: python-service helm: valueFiles: - values.yaml destination: server: https://kubernetes.default.svc namespace: default syncPolicy: automated: prune: true selfHeal: true
What this does:
- source.chart: name of the Helm chart to render.
- helm.valueFiles: list of values files that override chart defaults.
Apply the parent Application to Argo CD:
$ kubectl apply -f apps/python-microservices/parent.yaml
application.argoproj.io/python-microservices created
NAME HEALTH STATUS AGE
python-microservices Healthy Synced 10s
python-service Healthy Synced 8s
βWith the App of Apps pattern, a single Git commit can roll out a coordinated update across every microservice.β
According to the Argo CD documentation, the App of Apps pattern βenables hierarchical application management, making it possible to group related applications under a single parent for coordinated sync and versioning.β
Key point: Child Applications inherit the parentβs sync policy, ensuring consistent drift correction across the entire stack without extra configuration.
π‘ Observability β Adding Health Checks
Kubernetes health probes call specific HTTP endpoints; the application must expose them for the probes to succeed.
# src/main.py
from fastapi import FastAPI app = FastAPI() @app.get("/health")
async def health(): return {"status": "ok"} @app.get("/ready")
async def ready(): # Insert readiness logic, e.g., DB connection test return {"ready": True}
What this does:
- /health: simple liveness endpoint that always returns 200.
- /ready: readiness endpoint that can include checks such as database connectivity.
After updating the image, trigger a sync in Argo CD:
$ argocd app sync python-microservices
Syncing application 'python-microservices'...
APPLICATION STATUS HEALTH SYNCED AGE
python-microservices Synced Healthy True 2s
Why not rely solely on external monitoring? Native Kubernetes probes allow the kubelet to restart unhealthy pods instantly, reducing mean time to recovery (MTTR) compared with an external alert loop.
π© Final Thoughts
Using the App of Apps pattern in Argo CD provides a single source of truth for a multiβservice Python stack while preserving independent versioning. Each microservice can follow its own release cadence, yet the parent Application guarantees systemβwide synchronization, lowering operational overhead and preventing costly drift.
Developers can focus on writing Python code and packaging it as a Helm chart; the Gitβops pipeline handles deployment, health monitoring, and rollback. The outcome is a reproducible, auditable, and costβeffective production environment.
β Frequently Asked Questions
How does the App of Apps pattern differ from using multiple independent Argo CD Applications?
Both use separate Application resources, but the App of Apps pattern nests them under a parent, allowing a single sync operation, shared sync policies, and hierarchical RBAC, which simplifies management of large microservice fleets.
Can I use Kustomize instead of Helm for the child Applications?
Yes, Argo CD supports both Helm and Kustomize. Choose Kustomize when you need simple overlays without templating logic; Helm is preferable for parameterized charts and complex dependency management.
What is the recommended way to handle secret management for the Python services?
Store secrets in Kubernetes Secret objects and reference them in the Helm values file using envFrom or env. For production, integrate with external secret stores such as HashiCorp Vault or AWS Secrets Manager, and configure the pod to retrieve them at runtime.
π‘ Want to practise this hands-on? DigitalOcean gives new accounts $200 free credit for 60 days β enough to spin up a full Linux/Docker/Kubernetes environment at no cost.
π Recommended reading: Best DevOps & cloud books on Amazon β from Linux fundamentals to Kubernetes in production, curated for working engineers.
π References & Further Reading
- Official Argo CD documentation β comprehensive guide to the App of Apps pattern: argo-cd.readthedocs.io
- FastAPI official docs β building asynchronous Python APIs: fastapi.tiangolo.com
- Helm documentation β packaging Kubernetes applications: helm.sh

Top comments (0)