Kubernetes has become the standard platform for orchestrating containerized applications. As a .NET developer, understanding Kubernetes is essential for deploying modern, scalable applications. This guide provides practical insights for .NET developers working with Kubernetes.
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Api/Api.csproj", "Api/"]
RUN dotnet restore "Api/Api.csproj"
COPY . .
WORKDIR "/src/Api"
RUN dotnet build "Api.csproj" -c Release -o /app/build
# Publish stage
FROM build AS publish
RUN dotnet publish "Api.csproj" -c Release -o /app/publish
# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Api.dll"]Multi-stage builds reduce image size and improve security:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
# ... build steps
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
# ... runtime stepsapiVersion: apps/v1
kind: Deployment
metadata:
name: dotnet-api
spec:
replicas: 3
selector:
matchLabels:
app: dotnet-api
template:
metadata:
labels:
app: dotnet-api
spec:
containers:
- name: api
image: myregistry.azurecr.io/dotnet-api:latest
ports:
- containerPort: 8080
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
- name: ConnectionStrings__DefaultConnection
valueFrom:
secretKeyRef:
name: app-secrets
key: connection-string
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 10
periodSeconds: 5apiVersion: v1
kind: Service
metadata:
name: dotnet-api-service
spec:
selector:
app: dotnet-api
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer// Program.cs
builder.Services.AddHealthChecks()
.AddCheck("liveness", () => HealthCheckResult.Healthy())
.AddCheck("readiness", () =>
{
// Check database connectivity, external dependencies
return HealthCheckResult.Healthy();
});
app.MapHealthChecks("/health");
app.MapHealthChecks("/ready", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("readiness")
});apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
appsettings.json: |
{
"Logging": {
"LogLevel": "Information"
},
"AllowedHosts": "*"
}apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
connection-string: <base64-encoded-value>// Load from environment variables (Kubernetes injects these)
var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings__DefaultConnection");
// Or use IConfiguration
var connectionString = configuration.GetConnectionString("DefaultConnection");apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: dotnet-api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: dotnet-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80// Use Serilog for structured logging
builder.Host.UseSerilog((context, configuration) =>
{
configuration
.ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.Seq("http://seq-service:5341");
});// Prometheus metrics
builder.Services.AddSingleton<IMetricsFactory, PrometheusMetricsFactory>();
app.UseMetricServer(); // Exposes /metrics endpointspec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0Use separate deployments and switch traffic between them.
Gradually roll out new versions to a subset of users.
# View pods
kubectl get pods
# View logs
kubectl logs <pod-name>
# Describe pod
kubectl describe pod <pod-name>
# Execute command in pod
kubectl exec -it <pod-name> -- /bin/bashKubernetes provides powerful capabilities for deploying and managing .NET applications at scale. By following these practices and understanding Kubernetes concepts, .NET developers can build robust, scalable cloud-native applications.