🏗 Application Manifest — Why It Matters
A FastAPI microservice typically runs inside a container, but without an Argo CD Application object the GitOps controller cannot reconcile the desired state. The manifest below defines the source repository, target cluster, and namespace, enabling continuous delivery for the service.
📑 Table of Contents
- 🏗 Application Manifest — Why It Matters
- 📦 Container Image & Build — How to Package
- 🐍 Docker Build Command
- ⚙️ Kubernetes Resources — Defining Deployments and Services
- 🚀 Deployment Details
- 🌐 Service Exposure
- 🔗 Argo CD Sync Settings — Controlling Sync Behaviour
- 🟩 Final Thoughts
- ❓ Frequently Asked Questions
- How do I expose the FastAPI service to the internet?
- Can I use Helm instead of raw YAML for the manifests?
- What if I need to change the container image tag without updating the whole repo?
- 📚 References & Further Reading
📦 Container Image & Build — How to Package
A Docker image bundles the FastAPI code, its dependencies, and the ASGI server. Building the image from source guarantees that every environment receives the identical artifact, eliminating version drift.
# Dockerfile
FROM python:3.11-slim # Install build dependencies
RUN apt-get update && apt-get install -y -no-install-recommends gcc && rm -rf /var/lib/apt/lists/* # Create a non‑root user
RUN useradd -m appuser
WORKDIR /app
COPY requirements.txt .
RUN pip install -no-cache-dir -r requirements.txt # Copy application code
COPY ./app ./app # Switch to non‑root user
USER appuser # Expose the port used by uvicorn
EXPOSE 8000 # Run the ASGI server
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
What this does:
- FROM python:3.11-slim: provides a minimal base with the correct interpreter.
- RUN apt-get … gcc: installs a compiler needed for wheels that require native extensions.
- RUN useradd …: creates a non‑root user to improve container security.
- COPY requirements.txt & pip install: layers dependencies separately from source code for better caching.
- COPY ./app: copies the FastAPI package into the image.
- EXPOSE 8000: declares the port expected by the Service.
- CMD uvicorn …: starts the application with the ASGI server.
Building from source guarantees that the exact code version is packaged, and the build step can be audited for security compliance.
🐍 Docker Build Command
$ docker build -t ghcr.io/example/fastapi:latest .
Sending build context to Docker daemon 45.6MB
Step 1/12: FROM python:3.11-slim --> 1a2b3c4d5e6f
...
Successfully built 9f8e7d6c5b4a
Successfully tagged ghcr.io/example/fastapi:latest
The output confirms that Docker created the image and tagged it for later push.
⚙️ Kubernetes Resources — Defining Deployments and Services
Deployments manage pod lifecycle; Services provide stable networking. Together they ensure the FastAPI microservice scales and remains reachable within the cluster.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: fastapi-deployment labels: app: fastapi
spec: replicas: 3 selector: matchLabels: app: fastapi template: metadata: labels: app: fastapi spec: containers: - name: fastapi image: ghcr.io/example/fastapi:latest ports: - containerPort: 8000 resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi"
What this does:
- replicas: 3: creates three identical pods for load distribution.
- selector.matchLabels: ties the Deployment to pods with the same label.
- containers.image: references the Docker image built earlier.
- resources.requests/limits: informs the scheduler of CPU/memory expectations, enabling QoS enforcement.
Key point: Deployments include a self‑healing control loop; if a pod crashes, the controller spawns a replacement automatically.
🚀 Deployment Details
Verify the Deployment:
$ kubectl get deployment fastapi-deployment -n fastapi-prod
NAME READY UP-TO-DATE AVAILABLE AGE
fastapi-deployment 3/3 3 3 2m
🌐 Service Exposure
# service.yaml
apiVersion: v1
kind: Service
metadata: name: fastapi-service labels: app: fastapi
spec: selector: app: fastapi ports: - protocol: TCP port: 80 targetPort: 8000 type: ClusterIP
What this does:
- type: ClusterIP: creates an internal load balancer reachable only inside the cluster.
- port 80 → targetPort 8000: maps external HTTP traffic to the FastAPI container port.
- selector.app: binds the Service to the pods created by the Deployment.
A LoadBalancer Service would incur additional cloud cost and bypass the Ingress controller that performs TLS termination. (Also read: ⚙️ Setting up Kubernetes HPA for a FastAPI application made easy)
Check the Service:
$ kubectl get svc fastapi-service -n fastapi-prod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fastapi-service ClusterIP 10.96.12.34 80/TCP 1m
🔗 Argo CD Sync Settings — Controlling Sync Behaviour
Sync policies dictate how Argo CD applies changes from Git to the cluster. A well‑tuned syncPolicy reduces drift while avoiding unnecessary restarts.
# application-sync.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: fastapi-app
spec: syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true - PruneLast=true retry: limit: 5 backoff: duration: 5s factor: 2 maxDuration: 3m
What this does:
- prune: true: removes resources that are no longer defined in Git.
- selfHeal: true: detects out‑of‑band changes and restores the declared state.
- syncOptions.CreateNamespace=true: creates the target namespace automatically on first sync.
- retry.limit & backoff: implements exponential back‑off for transient failures.
According to the Argo CD documentation, enabling selfHeal is the recommended default for production workloads because it guarantees that manual edits do not persist unintentionally.
Trigger a manual sync to see the policy in action:
$ argocd app sync fastapi-app
SYNCING: fastapi-app
STATUS: Synced
Key point: Automated sync with pruning and self‑heal keeps the cluster declaratively aligned with the Git repository, which is the core premise of GitOps.
Argo CD turns a Git repository into the single source of truth for Kubernetes, and the Application manifest is the bridge that makes that possible.
🟩 Final Thoughts
Building an Argo CD application manifest yaml FastAPI involves three layers: the Argo Application that points to a Git directory, the Kubernetes resources that run the FastAPI container, and the sync policy that enforces declarative state. By separating these concerns, the workflow stays reproducible, auditable, and easy to extend with additional microservices.
Once the manifest is committed, any change—whether a code update or a configuration tweak—propagates automatically through Argo CD without manual kubectl commands. This reduces human error, shortens delivery cycles, and provides a built‑in rollback mechanism by simply reverting the Git commit.
❓ Frequently Asked Questions
How do I expose the FastAPI service to the internet?
Deploy an Ingress resource with an Ingress controller (e.g., NGINX or Traefik). The Ingress maps a host name to fastapi-service and handles TLS termination, keeping the pods internal.
Can I use Helm instead of raw YAML for the manifests?
Yes. Helm charts can template the Deployment, Service, and Application resources, which Argo CD can still sync. The underlying objects remain the same; Helm only adds a packaging layer.
What if I need to change the container image tag without updating the whole repo?
Argo CD supports parameter overrides via argocd app set or Kustomize patches. Updating the image tag in the Deployment spec and committing the change triggers a new sync automatically.
💡 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 Application CRDs and sync policies: argo-cd.readthedocs.io
- FastAPI deployment guide – best practices for containerizing FastAPI applications: fastapi.tiangolo.com
- Kubernetes official docs – details on Deployments, Services, and Ingress resources: kubernetes.io

Top comments (0)