Introduction
Kubernetes upgrades are rarely difficult because of the version number itself.
The difficult part is everything running on top of Kubernetes.
For .NET teams, that can include ASP.NET Core APIs, background workers, gRPC services, scheduled jobs, ingress controllers, service meshes, autoscaling, persistent storage, observability agents, and deployment automation.
Kubernetes 1.34 introduced several changes that are worth testing against .NET workloads before moving production clusters. Kubernetes follows a release lifecycle in which each minor release receives approximately 12 months of support, making upgrade planning an ongoing operational requirement.
The right strategy is not:
New Kubernetes Version
|
v
Upgrade Production
It is:
Current Cluster
|
v
Compatibility Tests
|
v
Application Tests
|
v
Infrastructure Tests
|
v
Staging Upgrade
|
v
Production Canary
|
v
Full Rollout
This article explains how to test .NET workloads against Kubernetes 1.34 before making the upgrade a production dependency.
Why Kubernetes Version Testing Matters
A .NET application does not run in isolation.
A typical production deployment may look like this:
Kubernetes Cluster
|
+------------------+------------------+
| | |
v v v
ASP.NET Core Worker Service CronJob
| | |
+------------------+------------------+
|
Service / Ingress
|
Config / Secrets
|
Storage / Network
The application may continue compiling perfectly while the Kubernetes environment introduces an operational regression.
Examples include:
Changed API behavior
Deprecated resources
Container runtime differences
Scheduling behavior
Resource management changes
Network policy issues
Admission-controller incompatibilities
Autoscaling differences
Monitoring-agent failures
That is why Kubernetes upgrades require infrastructure-level regression testing.
Understand the Kubernetes Release Lifecycle
Kubernetes minor releases have a relatively short support window compared with many application frameworks.
The Kubernetes project documents a release lifecycle of approximately one year for each minor release.
That means cluster upgrades should be treated as a recurring engineering process rather than an occasional emergency.
A healthy upgrade cycle looks like:
Current Version
|
v
Compatibility Review
|
v
Next Supported Version
|
v
Staging Validation
|
v
Production Upgrade
|
v
Next Upgrade Planning
Waiting until a cluster is close to the end of support creates unnecessary migration pressure.
Inventory the .NET Workloads First
Before testing Kubernetes 1.34, build an inventory.
For example:
| Workload | Type | Criticality | Dependencies |
|---|---|---|---|
| Orders API | ASP.NET Core | High | PostgreSQL, Redis |
| Worker | .NET Worker | High | Queue |
| Reporting API | ASP.NET Core | Medium | Database |
| Scheduler | CronJob | Medium | Storage |
| gRPC API | ASP.NET Core | High | Internal services |
Also record:
.NET version
Container base image
CPU requests
Memory requests
CPU limits
Memory limits
Replicas
Probes
Ingress
Service
ConfigMaps
Secrets
PersistentVolumes
HPA
PDB
NetworkPolicies
This inventory becomes your upgrade test matrix.
Verify the Container Images
Kubernetes upgrades do not automatically upgrade your .NET runtime.
Your container image remains responsible for the runtime environment.
For example:
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY publish/ .
ENTRYPOINT ["dotnet", "Orders.Api.dll"]
The important compatibility questions are:
Kubernetes 1.34
|
v
Container Runtime
|
v
Linux Kernel
|
v
.NET Runtime
|
v
ASP.NET Core
Test the complete chain.
Do not assume that because the .NET application works on the current cluster, it will automatically behave identically after the infrastructure upgrade.
Test Readiness and Liveness Probes
Health probes are one of the first things to validate.
A typical ASP.NET Core deployment might use:
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Test:
Application starts
|
v
Readiness becomes healthy
|
v
Traffic begins
|
v
Application failure
|
v
Liveness reacts
The upgrade should not change the expected health lifecycle.
Test Graceful Shutdown
.NET applications need to shut down cleanly when Kubernetes terminates a pod.
Test:
Pod receives termination
|
v
Application receives shutdown
|
v
Stop accepting work
|
v
Finish active requests
|
v
Release resources
|
v
Process exits
For APIs, monitor:
In-flight requests
HTTP 5xx responses
Request completion
Connection cleanup
Background task termination
For workers:
Message acknowledgement
Job completion
Duplicate processing
Queue visibility timeout
A Kubernetes upgrade is a good opportunity to verify graceful termination instead of assuming it works.
Test Resource Requests and Limits
A common .NET deployment configuration is:
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"
These values influence scheduling and runtime behavior.
Measure before and after the upgrade:
CPU utilization
Memory utilization
CPU throttling
OOMKills
Pod restarts
Request latency
Throughput
Do not simply compare whether the application is "up."
A workload can remain healthy while performance has degraded.
Benchmark ASP.NET Core APIs
Create a baseline before upgrading.
For example:
Endpoint RPS p95 p99
------------------------------------------------
GET /orders 1,200 42 ms 85 ms
GET /orders/{id} 1,500 31 ms 64 ms
POST /orders 850 73 ms 140 ms
After moving to Kubernetes 1.34, run the same workload.
The goal is not to prove that every number is identical.
The goal is to identify statistically meaningful regressions.
Track:
Throughput
p50 latency
p95 latency
p99 latency
Error rate
CPU
Memory
Pod restarts
Test Horizontal Pod Autoscaling
Autoscaling is especially important for .NET APIs.
A typical HPA might look like:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: orders-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: orders-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Test:
Low Load
|
v
2 Pods
High Load
|
v
Scale Out
Load Falls
|
v
Scale In
Measure:
Scale-up time
Maximum replicas
Scale-down behavior
Request latency during scaling
CPU utilization
Pod startup time
Test Startup Time
Autoscaling only works well if new pods become ready quickly.
Measure:
Image Pull
+
Container Start
+
.NET Runtime Start
+
Application Initialization
+
Readiness
For a .NET service:
Pod Created
|
v
Container Started
|
v
.NET Starts
|
v
Dependency Initialization
|
v
Health Endpoint Ready
|
v
Traffic
Compare startup times before and after the cluster upgrade.
Test Deployment Rollouts
Use a controlled deployment:
kubectl rollout status deployment/orders-api
Then test:
Old Pods
|
v
New Pods
|
v
Readiness
|
v
Traffic Shift
|
v
Old Pods Terminated
Monitor:
Available replicas
Unavailable replicas
Restart count
HTTP errors
Latency
The upgrade should not introduce unexpected rollout behavior.
Test Pod Disruption Budgets
A production API may use:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: orders-api
spec:
minAvailable: 2
selector:
matchLabels:
app: orders-api
Test the behavior during node maintenance and cluster operations.
The objective is:
Node Maintenance
|
v
Pod Eviction
|
v
Enough replicas remain available

Join the conversation! Your thoughts help the community grow.