Skip to main content

Deploy .NET Microservices to Azure Kubernetes Service (AKS)

Learn how to deploy .NET microservices to Azure Kubernetes Service (AKS) with Docker, YAML, and CI/CD. Step-by-step AKS tutorial with C# code—start now.

Azure Kubernetes Service (AKS) has become the default way modern teams run containerized workloads in the cloud, and if you build with .NET, it is one of the most powerful tools you can add to your stack. In this tutorial you will learn how to deploy .NET microservices to Azure Kubernetes Service step by step—from containerizing an ASP.NET Core Web API with Docker to writing production-ready Kubernetes YAML and rolling out updates safely. Whether you are a beginner searching "how to deploy .NET to Kubernetes" or a senior engineer looking for AKS best practices, this guide covers the practical WHY behind every step.

What Is Azure Kubernetes Service (AKS)?

Azure Kubernetes Service is Microsoft's managed Kubernetes offering. Kubernetes is an open-source container orchestrator that handles scheduling, scaling, self-healing, and networking for your containers. Running Kubernetes yourself means managing the control plane—the API server, scheduler, etcd, and controller manager—which is complex and error-prone. AKS manages the control plane for you (and it's free; you only pay for the worker nodes), so you focus on your .NET microservices instead of cluster plumbing.

For .NET developers, AKS is a natural fit. ASP.NET Core is cross-platform, produces small Linux container images, and starts fast—exactly the properties Kubernetes rewards. Combined with Azure Container Registry (ACR), Azure Monitor, and managed identity, AKS gives you an end-to-end path from source code to scalable production cloud infrastructure.

Why Microservices on Kubernetes?

Microservices split a large application into small, independently deployable services—each owning its own data and business capability. The challenge is operational: now you have ten services instead of one, each needing deployment, scaling, health checks, and service discovery. This is precisely the problem Kubernetes solves. It gives every service a stable network identity, restarts crashed containers automatically, and scales replicas up or down based on load. That is why "deploy .NET microservices to AKS" is one of the highest-demand cloud skills in the USA, UK, Canada, and Australia today.

Prerequisites for This AKS Tutorial

  • An active Azure subscription (a free trial works fine)
  • The Azure CLI (az) installed and logged in
  • .NET 8 SDK or later
  • Docker Desktop for building container images
  • kubectl, the Kubernetes command-line tool

Verify your tooling quickly:

// Run these in your terminal
az --version
dotnet --version
docker --version
kubectl version --client

Step 1: Build a Sample .NET Microservice

Let's create a minimal ASP.NET Core Web API that will act as our microservice. It exposes a product endpoint and, critically, a health check endpoint that Kubernetes will use to decide whether the container is alive and ready for traffic.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapControllers();

// Kubernetes probes hit these endpoints
app.MapHealthChecks("/healthz/live");   // liveness
app.MapHealthChecks("/healthz/ready");  // readiness

app.MapGet("/api/products", () => new[]
{
    new { Id = 1, Name = "Keyboard", Price = 49.99m },
    new { Id = 2, Name = "Monitor", Price = 199.99m }
});

app.Run();

Why two health endpoints? A liveness probe answers "is the process broken and needing a restart?" A readiness probe answers "is this instance ready to receive traffic right now?" Separating them prevents Kubernetes from sending requests to a pod that is still warming up (loading config, opening a database pool), which is a common cause of intermittent 500 errors in production.

Step 2: Containerize the .NET App with Docker

AKS runs containers, so you need a Docker image. Use a multi-stage Dockerfile: one stage compiles the app with the full SDK, and a slim runtime stage ships only what's needed. This keeps the final image small and reduces your attack surface.

# ---- Build stage ----
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o /app --no-restore

# ---- Runtime stage ----
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app ./
# Run as a non-root user for security
USER $APP_UID
EXPOSE 8080
ENTRYPOINT ["dotnet", "ProductService.dll"]

Best practice: copy *.csproj and run dotnet restore before copying the rest of the source. Docker caches layers, so as long as your dependencies don't change, rebuilds skip the slow restore step. Running as a non-root user ($APP_UID is built into the official .NET images) is a security best practice that AKS security policies often require.

Step 3: Push to Azure Container Registry

AKS pulls images from a registry. Azure Container Registry integrates tightly with AKS through managed identity, so you never store registry passwords in your cluster.

# Create a resource group and registry
az group create --name rg-aks-demo --location eastus
az acr create --resource-group rg-aks-demo --name myacrdemo123 --sku Basic

# Build and push the image directly in Azure (no local Docker push needed)
az acr build --registry myacrdemo123 --image productservice:v1 .

az acr build is a neat trick: it uploads your source and builds the image in the cloud, so you get consistent builds even from a low-powered laptop or a CI runner without Docker.

Step 4: Create the AKS Cluster

Now provision the Azure Kubernetes Service cluster and attach the registry so image pulls are automatic and secure.

az aks create \
  --resource-group rg-aks-demo \
  --name aks-dotnet-demo \
  --node-count 2 \
  --enable-managed-identity \
  --attach-acr myacrdemo123 \
  --generate-ssh-keys

# Download credentials so kubectl targets your new cluster
az aks get-credentials --resource-group rg-aks-demo --name aks-dotnet-demo

Why --attach-acr? It grants the cluster's managed identity AcrPull permission. Without it, your pods fail with ImagePullBackOff—one of the most-searched AKS errors. Managed identity means no secrets to rotate and no credentials leaking into YAML.

Step 5: Write the Kubernetes Deployment YAML

This is the heart of deploying .NET microservices to Kubernetes. A Deployment declares your desired state—how many replicas, which image, what resources—and Kubernetes continuously reconciles reality to match it.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: productservice
spec:
  replicas: 3
  selector:
    matchLabels:
      app: productservice
  template:
    metadata:
      labels:
        app: productservice
    spec:
      containers:
        - name: productservice
          image: myacrdemo123.azurecr.io/productservice:v1
          ports:
            - containerPort: 8080
          resources:
            requests:      # guaranteed minimum
              cpu: "100m"
              memory: "128Mi"
            limits:        # hard ceiling
              cpu: "500m"
              memory: "256Mi"
          livenessProbe:
            httpGet:
              path: /healthz/live
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 15
          readinessProbe:
            httpGet:
              path: /healthz/ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10

Why set resource requests and limits? Requests tell the scheduler how much CPU and memory to reserve, so it places pods on nodes that can actually run them. Limits protect neighbors from a runaway container. Skipping these is the number-one cause of unstable AKS clusters where one memory-leaking service takes down others on the same node.

Expose the Service

Pods are ephemeral and get new IPs when they restart, so you never talk to them directly. A Service gives your microservice a stable DNS name and load-balances across replicas.

apiVersion: v1
kind: Service
metadata:
  name: productservice
spec:
  type: LoadBalancer   # provisions an Azure public IP
  selector:
    app: productservice
  ports:
    - port: 80
      targetPort: 8080

For a single public endpoint use LoadBalancer. For multiple microservices behind one IP with path-based routing (/products, /orders), use an Ingress controller like NGINX or the AKS Application Gateway Ingress Controller instead—that is the production pattern for real microservices architectures.

Step 6: Deploy and Verify

# Apply your manifests
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# Watch the rollout
kubectl get pods -w
kubectl get service productservice   # copy the EXTERNAL-IP

# Test the live endpoint
curl http:///api/products

When all three pods show Running and READY 1/1, your .NET microservice is live on Azure Kubernetes Service. If a pod is stuck, kubectl describe pod <name> and kubectl logs <name> are your two best debugging friends.

Step 7: Scale and Roll Out Updates Safely

Scaling is a one-liner, and Kubernetes handles the rest:

# Manual scaling
kubectl scale deployment productservice --replicas=5

# Autoscale based on CPU (Horizontal Pod Autoscaler)
kubectl autoscale deployment productservice --cpu-percent=70 --min=3 --max=10

To ship a new version, push productservice:v2 to ACR and update the image. Kubernetes performs a rolling update by default—spinning up new pods and draining old ones only after the new ones pass readiness checks, so users never see downtime.

kubectl set image deployment/productservice \
  productservice=myacrdemo123.azurecr.io/productservice:v2

# If something breaks, roll back instantly
kubectl rollout undo deployment/productservice

AKS Best Practices for .NET Microservices

  • Always define liveness and readiness probes. Without them, Kubernetes can't self-heal or route traffic correctly.
  • Set resource requests and limits on every container to keep the cluster stable and cost-efficient.
  • Use managed identity for ACR and Azure resources—never bake secrets into images or YAML.
  • Store configuration in ConfigMaps and Secrets, not appsettings baked into the image, so the same image runs across dev, staging, and production.
  • Enable Azure Monitor / Container Insights for logs, metrics, and alerting from day one.
  • Pin image tags to versions (v1, v2)—never latest—so deployments are reproducible.
  • Automate with CI/CD using GitHub Actions or Azure DevOps so every merge builds, pushes, and deploys.

Common Pitfalls to Avoid

  • ImagePullBackOff: almost always a missing --attach-acr or a wrong image name. Check the registry path carefully.
  • CrashLoopBackOff: your app throws on startup. Check kubectl logs—often a missing connection string or config value.
  • Pods pending forever: resource requests exceed node capacity. Lower requests or add nodes.
  • Ignoring graceful shutdown: handle SIGTERM so in-flight requests finish during a rollout. ASP.NET Core does this automatically, but long-running work needs a CancellationToken.
  • Running one giant container: resist the urge—keep each microservice single-purpose so it can scale independently.

Conclusion: Key Takeaways

Deploying .NET microservices to Azure Kubernetes Service (AKS) follows a clear, repeatable path: containerize your ASP.NET Core app with a multi-stage Dockerfile, push to Azure Container Registry, create an AKS cluster with managed identity, and describe your desired state in Kubernetes YAML. From there, Kubernetes handles scaling, self-healing, and zero-downtime rolling updates for you.

The most important lessons: always add health probes and resource limits, lean on managed identity instead of secrets, keep configuration outside your image, and automate everything with CI/CD. Master these fundamentals and you'll be able to run resilient, scalable .NET microservices on Azure Kubernetes Service with confidence. Ready to go further? Try adding an NGINX Ingress controller and a Horizontal Pod Autoscaler to your cluster next—and start deploying to AKS today.

About csharp-coder.com
Your go-to resource for C#, .NET, and modern software development. Follow along for daily tutorials, tips, and real-world examples.

Comments

Popular posts from this blog

.NET MAUI Tutorial 2026: Build Cross-Platform Apps in C#

Learn .NET MAUI in 2026 to build iOS, Android, Windows & Mac apps from one C# codebase. Start this cross-platform tutorial with code examples today. .NET MAUI (Multi-platform App UI) is Microsoft's framework for building native iOS, Android, Windows, and macOS apps from a single C# codebase . If you've ever wanted to ship a mobile app without learning Swift, Kotlin, and Win32 separately, this .NET MAUI tutorial for 2026 is your starting point. In this guide you'll learn what .NET MAUI is, why it matters for cross-platform app development in C#, and how to build your first working app — with runnable code examples and the best practices senior engineers actually use in production. What Is .NET MAUI and Why Use It in 2026? .NET MAUI is the evolution of Xamarin.Forms, fully integrated into the modern .NET runtime. With one project and one language — C# — you target four platforms. The framework compiles to native UI controls on each device, so a button on iOS...

Angular 14 : 404 error during refresh page after deployment

In this article, We will learn how to solve 404 file or directory not found angular error in production.  Refresh browser angular 404 file or directory not found error You have built an Angular app and created a production build with ng build --prod You deploy it to a production server. Everything works fine until you refresh the page. The app throws The requested URL was not found on this server message (Status code 404 not found). It appears that angular routing not working on the production server when you refresh the page. The error appears on the following scenarios When you type the URL directly in the address bar. When you refresh the page The error appears on all the pages except the root page.   Reason for the requested URL was not found on this server error In a Multi-page web application, every time the application needs to display a page it has to send a request to the web server. You can do that by either typing the URL in the address bar, clicking on the Me...

Angular 14 CRUD Operation with Web API .Net 6.0

How to Perform CRUD Operation Using Angular 14 In this article, we will learn the angular crud (create, read, update, delete) tutorial with ASP.NET Core 6 web API. We will use the SQL Server database and responsive user interface for our Web app, we will use the Bootstrap 5. Let's start step by step. Step 1 - Create Database and Web API First we need to create Employee database in SQL Server and web API to communicate with database. so you can use my previous article CRUD operations in web API using net 6.0 to create web API step by step. As you can see, after creating all the required API and database, our API creation part is completed. Now we have to do the angular part like installing angular CLI, creating angular 14 project, command for building and running angular application...etc. Step 2 - Install Angular CLI Now we have to install angular CLI into our system. If you have already installed angular CLI into your system then skip this step.  To install angular CLI ope...