Overview
Complete CI/CD walkthrough: containerise .NET, write Helm charts, configure AKS, and automate deployment.
Multi-Stage Docker Build
Efficient Docker images for .NET require multi-stage builds. The SDK stage compiles and publishes your app; the runtime stage contains only the published output. This takes a typical .NET image from 800MB to under 120MB.
Use Microsoft's chiseled images for maximum security and minimal size—they contain only the .NET runtime with no shell or package manager.
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyApp/MyApp.csproj", "MyApp/"]
RUN dotnet restore "MyApp/MyApp.csproj"
COPY . .
RUN dotnet publish "MyApp/MyApp.csproj" -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]Helm Chart Structure
Helm charts template Kubernetes manifests with environment-specific values. A typical .NET service chart includes a Deployment, Service, HorizontalPodAutoscaler, and Ingress resource.
We maintain a shared base chart for all Omni Stack microservices with standardised health check paths, resource limits, and pod disruption budgets—ensuring consistency across services.
- templates/deployment.yaml - Pod spec and replicas
- templates/service.yaml - ClusterIP service
- templates/hpa.yaml - Auto-scaling rules
- templates/ingress.yaml - External routing
- values.yaml - Environment-specific overrides
GitHub Actions Pipeline
A production pipeline for AKS deployment has three key stages: build and push the Docker image, run integration tests against the image, and deploy to staging before production with a manual approval gate.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: azure/login@v1
- uses: azure/docker-login@v1
- run: docker build -t myregistry.azurecr.io/myapp:${{ github.sha }} .
- run: docker push myregistry.azurecr.io/myapp:${{ github.sha }}
deploy:
needs: build
environment: production
steps:
- uses: azure/aks-set-context@v3
- run: helm upgrade --install myapp ./charts/myapp --set image.tag=${{ github.sha }}Key Takeaways
- Use multi-stage builds to minimise image size
- Chiseled base images improve security
- Helm enables environment-specific deployments
- Use GitHub Environments for production approval gates
- Always set resource requests and limits in Kubernetes
Saurav Rai
Founder & Lead Architect, Omni Stack
7+ years building enterprise .NET and cloud applications for clients across Australia, USA, and the Middle East. Passionate about clean architecture, developer experience, and shipping fast.