Introduction
Kubernetes upgrades are rarely difficult because of the version number itself.
The difficult part is everything connected to the cluster.
A production .NET application running on Kubernetes may depend on:
Deployments
Services
Ingress
ConfigMaps
Secrets
Persistent volumes
Health probes
Horizontal Pod Autoscaling
Network policies
Container images
Admission policies
Observability components
CI/CD tooling
When a Kubernetes version approaches maintenance mode, teams have a useful opportunity to review those dependencies before the platform moves into a less active support phase.
Kubernetes 1.34 is scheduled to enter maintenance mode on August 27, 2026, with end of life currently scheduled for October 27, 2026. The 1.34 release series is currently listed with 1.34.9 as the latest released patch version. (Kubernetes)
That makes August 2026 a practical point for teams running .NET workloads on Kubernetes 1.34 to review their upgrade plans, test workloads against a newer Kubernetes version, and identify anything that could cause problems during the transition.
What Does Maintenance Mode Mean?
Maintenance mode does not mean that a Kubernetes cluster suddenly stops working.
Your existing:
Pod
Service
Deployment
Ingress
ConfigMap
Secretdoes not automatically become invalid when a release enters maintenance mode.
The bigger concern is the support lifecycle.
A simplified lifecycle looks like:
New Release
|
v
Active Development
|
v
Regular Maintenance
|
v
Maintenance Mode
|
v
End of LifeFor Kubernetes 1.34:
Release
August 2025
|
v
Active Support
|
v
Maintenance Mode
August 27, 2026
|
v
End of Life
October 27, 2026The exact operational implications depend on how Kubernetes is deployed and which distribution or managed Kubernetes service you use.
Therefore, teams should also check the support policy of their specific Kubernetes platform.
Why .NET Developers Should Care
A Kubernetes upgrade is an infrastructure change, but application developers can still be affected.
Consider an ASP.NET Core application:
Internet
|
v
Ingress
|
v
Service
|
v
ASP.NET Core Pods
|
v
DatabaseThe application may not contain any Kubernetes-specific C# code.
However, the deployment depends on Kubernetes APIs and runtime behavior.
For example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
spec:
replicas: 3
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
spec:
containers:
- name: orders-api
image: orders-api:latest
ports:
- containerPort: 8080A Kubernetes upgrade therefore needs to validate both:
Application
+
Deployment PlatformStart With the Current Cluster Version
Before upgrading anything, establish exactly what is running.
Use:
kubectl versionYou can also inspect nodes:
kubectl get nodesand workloads:
kubectl get deployments -AThe goal is to understand:
Control Plane Version
Node Versions
Namespaces
Deployments
Services
Ingress
Operators
CRDsDo not assume every node is running the same version simply because the control plane has been upgraded.
Inventory Your Kubernetes APIs
One of the most important upgrade checks is API compatibility.
A manifest might contain:
apiVersion: apps/v1
kind: Deploymentwhich is a well-established API.
But a legacy application may still contain older API versions.
Look through:
Deployment
StatefulSet
DaemonSet
Ingress
CronJob
RBAC
NetworkPolicy
Custom ResourcesThe objective is to identify APIs that have been deprecated or removed.
A simple repository search can help:
grep -R "apiVersion:" ./k8sFor a larger repository, use your normal code-search tooling.
Why API Versions Matter
Kubernetes APIs evolve.
A resource might move through a lifecycle such as:
v1alpha1
|
v1beta1
|
v1The problem occurs when an old API is no longer served by the Kubernetes version you are upgrading to.
For example, an old manifest may contain:
apiVersion: example.io/v1beta1while the newer platform expects:
apiVersion: example.io/v1The application code may be perfectly healthy.
The deployment can still fail because the cluster no longer understands the old API.
Test the .NET Application Before the Upgrade
Create a baseline.
Record:
Application startup
Health checks
API requests
Background jobs
Database connectivity
Message processing
Scaling behavior
Deployment rollout
Graceful shutdownFor an ASP.NET Core application, verify the health endpoint:
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/health");
app.Run();A Kubernetes probe can then use:
livenessProbe:
httpGet:
path: /health
port: 8080
readinessProbe:
httpGet:
path: /health
port: 8080Before upgrading Kubernetes, make sure these probes actually represent the application's health correctly.
Liveness vs Readiness
This is particularly important during upgrades.
Readiness
Readiness answers:
"Can this pod receive traffic?"Liveness
Liveness answers:
"Is this container still functioning?"They should not automatically use exactly the same logic.
For example, if an application temporarily loses access to a downstream database, marking the container as completely dead may cause unnecessary restarts.
A better design might allow the application to remain alive while reporting itself as not ready.
Database unavailable
|
v
Readiness = Failed
Liveness = HealthyThis distinction becomes especially useful during rolling upgrades.
Test Rolling Deployments
A normal deployment might use:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1This tells Kubernetes to maintain availability while replacing pods.
Before upgrading the cluster, verify that the application itself behaves correctly during rolling replacement.
Test:
Old Pod
|
v
New Pod Starts
|
v
Readiness Passes
|
v
Traffic Moves
|
v
Old Pod TerminatesIf the application takes 30 seconds to initialize but the readiness probe starts immediately, Kubernetes may make decisions based on incomplete application state.
Graceful Shutdown Matters
ASP.NET Core applications should handle termination properly.
When Kubernetes replaces a pod:
SIGTERM
|
v
Application Shutdown
|
v
Existing Requests Finish
|
v
Container StopsThe application should avoid abruptly terminating active work.
For background services:
public sealed class Worker(
ILogger<Worker> logger)
: BackgroundService
{
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await ProcessWorkAsync(stoppingToken);
await Task.Delay(
TimeSpan.FromSeconds(10),
stoppingToken);
}
}
}The cancellation token is important because the application needs a way to stop work cleanly.
Test Pod Disruption
An upgrade can result in node or pod movement.
Therefore, test how the application behaves when:
Pod disappears
Node drains
Pod restarts
Deployment rolls out
Replica count changesFor a three-replica API:
Before
Pod A
Pod B
Pod CDuring replacement:
Pod A
Pod B
Pod C
Pod DThen:
Pod B
Pod C
Pod DThe application should remain available throughout the expected transition.
Review PodDisruptionBudgets
A PodDisruptionBudget can help protect application availability during voluntary disruptions.
For example:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: orders-api-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: orders-apiFor a three-replica application, this expresses an intention to keep at least two replicas available during supported voluntary disruptions.
However, a PodDisruptionBudget is not a guarantee against every type of failure.
It should be considered together with:
Replica count
Node distribution
Pod topology
Application startup time
Readiness probes
Test Horizontal Pod Autoscaling
A .NET API may use:
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: 70During upgrade testing, verify:
Traffic increases
|
v
CPU increases
|
v
HPA scales
|
v
New Pods become ready
|
v
Traffic distributesDo not assume that an HPA configuration that worked previously will behave exactly the same under every new cluster configuration.
Review Custom Resource Definitions
Many production clusters use CRDs.
Examples include:
Ingress Controllers
Certificate Management
Monitoring
Service Mesh
GitOps
Cloud Integrations
Storage OperatorsThese resources may have their own compatibility requirements.
The Kubernetes version is only one component of the upgrade.
Your actual dependency graph might look like:
Kubernetes
|
+--> Ingress Controller
|
+--> CSI Driver
|
+--> Monitoring Operator
|
+--> Certificate Controller
|
+--> Service Mesh
|
+--> GitOps ControllerEach component should have a tested compatibility path.
Check Helm Charts
If your .NET application is deployed using Helm, inspect the chart.
For example:
orders-api/
├── Chart.yaml
├── values.yaml
└── templates/
├── deployment.yaml
├── service.yaml
├── ingress.yaml
└── hpa.yamlRender the manifests before deployment:
helm template orders-api ./orders-apiThen inspect:
apiVersion
kind
annotations
labels
probes
resources
securityContextThis catches problems before they reach the cluster.
Test Resource Requests and Limits
A deployment might define:
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"These values influence scheduling and runtime behavior.
Do not simply copy resource values from another application.
Measure your workload.
For example:
Application
|
+--> CPU usage
+--> Memory usage
+--> Startup time
+--> Request rateThen tune the resource configuration based on actual behavior.
Test .NET Startup Time
Startup time matters during rolling upgrades.
Suppose:
Pod startup = 20 secondsbut the deployment assumes:
Pod ready = immediatelyTraffic may reach the application before it is actually ready.
Use readiness probes and appropriate startup configuration.
For applications with longer initialization periods, a startup probe may be useful:
startupProbe:
httpGet:
path: /health
port: 8080
failureThreshold: 30
periodSeconds: 5This gives the application time to initialize before Kubernetes begins applying normal liveness decisions.
Join the conversation! Your thoughts help the community grow.