When your .NET applications outgrow simple PaaS hosting, you’ll likely move toward containerization and orchestration. Containers make your apps portable, and Kubernetes provides the automation for deploying, scaling, and managing them at cloud scale.
In this article, we’ll explore how to:
Containerize a .NET app with Docker
Deploy it to Azure Kubernetes Service (AKS)
Deploy it to Amazon Elastic Kubernetes Service (EKS)
1. Why Containers for .NET?
Portability – Runs consistently across dev, test, and cloud.
Scalability – Easily scale pods across clusters.
Microservices Ready – Break monoliths into smaller services.
Cloud-Native – Kubernetes is the industry standard for orchestration.
2. Containerize a .NET App with Docker
Create a new ASP.NET Core app:
dotnet new webapi -o MyKubeApp
cd MyKubeApp
Create a Dockerfile
:
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyKubeApp.dll"]
Build and run locally:
docker build -t mykubeapp .
docker run -p 8080:80 mykubeapp
3. Deploy to Azure Kubernetes Service (AKS)
Step 1. Create AKS Cluster
az group create --name MyKubeGroup --location eastus
az aks create --resource-group MyKubeGroup --name MyKubeCluster --node-count 2 --enable-addons monitoring --generate-ssh-keys
az aks get-credentials --resource-group MyKubeGroup --name MyKubeCluster
Step 2. Push Image to Azure Container Registry (ACR)
az acr create --resource-group MyKubeGroup --name MyKubeRegistry --sku Basic
az acr login --name MyKubeRegistry
docker tag mykubeapp MyKubeRegistry.azurecr.io/mykubeapp:v1
docker push MyKubeRegistry.azurecr.io/mykubeapp:v1
Step 3. Kubernetes Deployment File (deployment.yaml
)
apiVersion: apps/v1
kind: Deployment
metadata:
name: mykubeapp
spec:
replicas: 2
selector:
matchLabels:
app: mykubeapp
template:
metadata:
labels:
app: mykubeapp
spec:
containers:
- name: mykubeapp
image: mykuberegistry.azurecr.io/mykubeapp:v1
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: mykubeapp-service
spec:
type: LoadBalancer
selector:
app: mykubeapp
ports:
- protocol: TCP
port: 80
targetPort: 80
Apply deployment:
kubectl apply -f deployment.yaml
Your app will be exposed via an Azure Load Balancer IP.
4. Deploy to Amazon Elastic Kubernetes Service (EKS)
Step 1. Create EKS Cluster
eksctl create cluster --name mykubecluster --region us-east-1 --nodes 2
Step 2. Push Image to Amazon Elastic Container Registry (ECR)
aws ecr create-repository --repository-name mykubeapp
$(aws ecr get-login --no-include-email --region us-east-1)
docker tag mykubeapp <account_id>.dkr.ecr.us-east-1.amazonaws.com/mykubeapp:v1
docker push <account_id>.dkr.ecr.us-east-1.amazonaws.com/mykubeapp:v1
Step 3. Apply the Same Kubernetes Manifest
Update the image in deployment.yaml
to use your AWS ECR URL, then deploy:
kubectl apply -f deployment.yaml
AWS will provision an ELB (Elastic Load Balancer) and provide a public endpoint.
5. Side-by-Side: AKS vs. EKS
Feature | AKS (Azure) | EKS (AWS) |
---|
Setup | Easy via Azure CLI & Portal | Requires eksctl or Terraform, more setup |
Registry | Azure Container Registry (ACR) | Amazon Elastic Container Registry (ECR) |
Load Balancer | Azure Load Balancer auto-configured | AWS ELB auto-configured |
Monitoring | Azure Monitor + Application Insights | CloudWatch + AWS X-Ray |
Best For | Teams already using Azure DevOps & App Services | Teams needing AWS’s global reach & flexibility |
6. Best Practices
CI/CD Pipelines
Secrets Management
Autoscaling: Enable Kubernetes Horizontal Pod Autoscaler (HPA).
Observability: Use Prometheus + Grafana, or native cloud monitoring.
Multi-Cloud Portability: Keep manifests provider-agnostic, rely on Helm charts or Dapr.
Conclusion
By combining Docker and Kubernetes, your .NET applications become portable, scalable, and ready for production workloads on both Azure AKS and AWS EKS. Azure offers simplicity and deep Microsoft integration, while AWS provides flexibility and global infrastructure.
This dual approach ensures you’re not locked into one cloud and can leverage the best of both worlds.