16 May, 202512 min read
Modern DevOps: Kubernetes, Kustomize & ArgoCD

Modern DevOps: Kubernetes, Kustomize & ArgoCD

#Kubernetes#DevOps#Kustomize#ArgoCD#GitOps#.NET

Deploying applications used to be a headache. You'd finish your code, build a container, and then manually run commands to get it onto a server. If you had different settings for your "testing" environment and your "production" environment, you often ended up with two nearly identical files that were a nightmare to keep in sync.

That's where the trio of Kubernetes, Kustomize, and ArgoCD comes in.

In this guide, we'll walk through how to set up a complete pipeline from scratch.

Why this stack?

Before we dive into the steps, let's talk about why we care:

  1. Kubernetes: It's the engine. It makes sure your app is running, handles restarts if it crashes, and scales it up when traffic hits.
  2. Kustomize: It's the "Lego" of configuration. Instead of copying and pasting huge manifest files for every environment, you write a "Base" once. Then, you just write small "Patches" for what changes (like using a bigger database in production).
  3. ArgoCD: It's the "Auto-Pilot". It watches your GitHub repo. The moment you push a change to your configuration, ArgoCD notices and automatically updates your cluster to match. This is called GitOps.

Step 1: The Foundation (.NET App)

First, we need something to deploy. We'll use a simple .NET Web API. If you don't have one, you can create it with:

dotnet new webapi -o app1

To make sure it works locally:

cd app1
dotnet run

Check http://localhost:<port>/WeatherForecast and you should see some data.


Step 2: The Container (Dockerfile)

Kubernetes doesn't run raw code; it runs "containers". We need to pack our app into a Docker image.

Create a file named Dockerfile in your app folder:

# Use the official .NET runtime
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY ./publish /app
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 8080
ENTRYPOINT ["dotnet", "app1.dll"]

Now, build and "package" your app:

dotnet publish -c Release -o ./publish
docker build -t your-username/app1:v1 .
docker push your-username/app1:v1

Step 3: The Kubernetes "Base"

Now for the fun part. We need to tell Kubernetes how to run this image. We'll create a "Base" configuration that works everywhere.

In a new folder kubernetes/apps/app1/base, create two files:

deployment.yaml (Defines how the app runs)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app1
  template:
    metadata:
      labels:
        app: app1
    spec:
      containers:
      - name: app1
        image: your-username/app1:v1
        ports:
        - containerPort: 8080

service.yaml (Exposes the app to the world)

apiVersion: v1
kind: Service
metadata:
  name: app1
spec:
  selector:
    app: app1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer

Finally, create a kustomization.yaml in the same folder to tie them together:

resources:
  - deployment.yaml
  - service.yaml

Step 4: Environment Overlays (Kustomize)

This is where Kustomize shines. Let's say in Production, you want 3 copies (replicas) of your app instead of 1.

Create a folder kubernetes/apps/app1/overlays/production. Inside, create a deployment.patch.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1
spec:
  replicas: 3

And a kustomization.yaml for production:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
patches:
  - path: deployment.patch.yaml

Now, when you "apply" the production folder, Kustomize takes the Base and swaps the replicas: 1 for replicas: 3. No duplication!


Step 5: Automating with ArgoCD

Now we have our code and our manifests. But we don't want to manually run kubectl apply every time.

  1. Install ArgoCD in your cluster:
    kubectl create namespace argocd
    kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.4.7/manifests/install.yaml
  2. Create an "Application" manifest. This tells ArgoCD to watch your Git repo:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: prod-app1
  namespace: argocd
spec:
  project: default
  source:
    repoURL: 'https://github.com/your-username/your-repo.git'
    targetRevision: main
    path: kubernetes/apps/app1/overlays/production
  destination:
    server: 'https://kubernetes.default.svc'
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Apply this one last time manually: kubectl apply -f application.yaml.


The Result

From now on, the workflow is beautiful:

  1. Change your code.
  2. Push a new Docker image.
  3. Update the version in your deployment.yaml in Git.
  4. ArgoCD wakes up, sees the change, and updates your cluster.

No more hassles, Git is your source of truth.


Summary

By using this stack, we've moved away from "manual" work and into "declarative" work. We describe what we want the world to look like in Git, and our tools (Kubernetes, Kustomize, ArgoCD) make it happen.

It keeps your environments clean, your deployments safe, and your developer heart happy. Happy shipping!