Kubernetes  

Kubernetes 1.34 Maintenance: Final .NET Upgrade Tests

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
Secret

does 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 Life

For Kubernetes 1.34:

Release
August 2025
    |
    v
Active Support
    |
    v
Maintenance Mode
August 27, 2026
    |
    v
End of Life
October 27, 2026

The 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
Database

The 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: 8080

A Kubernetes upgrade therefore needs to validate both:

Application
+
Deployment Platform

Start With the Current Cluster Version

Before upgrading anything, establish exactly what is running.

Use:

kubectl version

You can also inspect nodes:

kubectl get nodes

and workloads:

kubectl get deployments -A

The goal is to understand:

Control Plane Version
Node Versions
Namespaces
Deployments
Services
Ingress
Operators
CRDs

Do 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: Deployment

which 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 Resources

The objective is to identify APIs that have been deprecated or removed.

A simple repository search can help:

grep -R "apiVersion:" ./k8s

For 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
    |
    v1

The 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/v1beta1

while the newer platform expects:

apiVersion: example.io/v1

The 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 shutdown

For 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: 8080

Before 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  = Healthy

This distinction becomes especially useful during rolling upgrades.

Test Rolling Deployments

A normal deployment might use:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 0
    maxSurge: 1

This 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 Terminates

If 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 Stops

The 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 changes

For a three-replica API:

Before

Pod A
Pod B
Pod C

During replacement:

Pod A
Pod B
Pod C
Pod D

Then:

Pod B
Pod C
Pod D

The 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-api

For 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: 70

During upgrade testing, verify:

Traffic increases
      |
      v
CPU increases
      |
      v
HPA scales
      |
      v
New Pods become ready
      |
      v
Traffic distributes

Do 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 Operators

These 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 Controller

Each 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.yaml

Render the manifests before deployment:

helm template orders-api ./orders-api

Then inspect:

apiVersion
kind
annotations
labels
probes
resources
securityContext

This 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 rate

Then tune the resource configuration based on actual behavior.

Test .NET Startup Time

Startup time matters during rolling upgrades.

Suppose:

Pod startup = 20 seconds

but the deployment assumes:

Pod ready = immediately

Traffic 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: 5

This gives the application time to initialize before Kubernetes begins applying normal liveness decisions.

Test Database Connections

A Kubernetes upgrade can expose application assumptions around connection handling.

For an EF Core application:

builder.Services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(
        connectionString,
        sqlOptions =>
        {
            sqlOptions.EnableRetryOnFailure();
        });
});

Test:

Pod restart
Database connection loss
Connection recovery
Application startup
Concurrent requests

The goal is to make the application resilient to expected infrastructure transitions.

Test Secrets and Configuration

Check whether your application depends on:

Secrets
ConfigMaps
Environment Variables
Mounted Files
External Secret Controllers

For example:

env:
  - name: ConnectionStrings__Default
    valueFrom:
      secretKeyRef:
        name: orders-api
        key: connection-string

Make sure the secret exists in the target namespace:

kubectl get secrets -n production

Do not print secret contents during troubleshooting.

Test Network Policies

Network policies can affect application behavior during cluster changes.

A typical .NET application may require:

API
 |
 +--> Database
 |
 +--> Redis
 |
 +--> Message Broker
 |
 +--> External API

If a policy accidentally blocks one dependency:

API
 |
 X--> Database

the application may fail even though the deployment itself is healthy.

Test actual traffic paths.

Test Ingress

Ingress is another important area.

Verify:

TLS
Hostnames
Path Routing
Timeouts
Headers
Client IP Handling
Health Checks

For example:

spec:
  rules:
    - host: api.example.internal
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: orders-api
                port:
                  number: 80

Ingress behavior also depends on the ingress controller, so test the controller version independently from Kubernetes itself.

Build a Pre-Upgrade Test Matrix

A practical matrix might look like:

AreaTestExpected Result
ApplicationAPI startupSuccessful
HealthReadinessCorrect state
HealthLivenessCorrect state
DeploymentRolling updateNo unexpected outage
DatabaseConnectionSuccessful
DatabaseRetry behaviorRecovers from transient issue
ScalingHPAScales correctly
NetworkingService-to-serviceSuccessful
IngressHTTPSSuccessful
SecretsConfigurationLoaded correctly
StoragePersistent volumeData remains available
Background jobsGraceful shutdownNo lost work
ObservabilityLogs/metricsAvailable
SecurityRBACExpected permissions
CRDsControllersCompatible

This makes the upgrade measurable.

Common Mistakes

Mistake 1: Upgrading Production First

Always test in a representative non-production cluster.

Mistake 2: Checking Only the Control Plane

Nodes, operators, controllers, and workloads also matter.

Mistake 3: Ignoring CRDs

Third-party controllers may have their own Kubernetes compatibility requirements.

Mistake 4: Testing Only Application Startup

A successful startup does not prove that the workload is healthy under rolling replacement.

Mistake 5: Ignoring Deprecated APIs

Old manifests can fail when an API is removed.

Mistake 6: Forgetting Ingress and Storage

Applications depend on more than Deployments and Services.

Mistake 7: Treating a Cluster Upgrade as an Application Deployment

Infrastructure upgrades need their own validation process.

Troubleshooting

ProblemWhat to Check
Deployment failsAPI versions and manifest validation
Pods remain PendingResource requests, node capacity, scheduling rules
Pods restartLiveness probe, application exceptions, memory limits
Pods never become ReadyReadiness probe and dependency availability
Ingress stops workingController version and routing configuration
Database unavailableSecrets, network policies, connection settings
HPA does not scaleMetrics availability and HPA configuration
CRD failsOperator/controller compatibility
Helm deployment failsRendered manifests and chart compatibility
Background jobs lose workGraceful shutdown and queue semantics

Best Practices

Establish a Baseline

Record application behavior before changing the cluster.

Test the Entire Dependency Chain

Do not test Kubernetes in isolation.

Review APIs

Search manifests and Helm templates for deprecated or obsolete APIs.

Validate Controllers

Check ingress, storage, monitoring, and other operators.

Test Rolling Behavior

A production upgrade should not be considered successful if applications cannot survive normal pod replacement.

Verify Health Probes

Make sure readiness and liveness represent the application's actual state.

Keep Resource Configuration Realistic

Use observed CPU and memory behavior instead of arbitrary values.

Test Failure Scenarios

Include pod termination, node drain, dependency failure, and connection recovery.

Maintain a Rollback Plan

Know what you will do if the upgrade does not behave as expected.

Test Before the Deadline

Do not wait until maintenance mode begins to discover compatibility problems.

Advantages of Testing Before Maintenance

Reduced Upgrade Risk

Problems can be identified before the production change.

Better Application Reliability

Testing probes, graceful shutdown, scaling, and dependencies improves the application's overall resilience.

Easier Planning

Teams have time to coordinate infrastructure and application changes.

Better Documentation

The upgrade process becomes repeatable instead of relying on tribal knowledge.

Opportunity to Remove Technical Debt

Old manifests, outdated Helm charts, and unnecessary dependencies can be identified during the review.

Disadvantages and Challenges

Upgrade Testing Takes Time

A production-like environment is required for meaningful testing.

Multiple Dependencies Must Be Validated

The Kubernetes version is only one part of the platform.

Some Failures Are Environment-Specific

A local cluster may not reproduce managed Kubernetes behavior.

Rollback Can Be Complicated

Database migrations and application changes can make rollback more difficult.

Third-Party Components Add Risk

Operators, ingress controllers, and other extensions need their own compatibility testing.

A Practical Final Test Plan

For a .NET application running on Kubernetes 1.34, a useful pre-upgrade sequence is:

1. Record current Kubernetes versions
          |
          v
2. Inventory workloads and APIs
          |
          v
3. Review deprecated APIs
          |
          v
4. Check Helm charts and CRDs
          |
          v
5. Verify .NET application health
          |
          v
6. Test database and external dependencies
          |
          v
7. Test rolling deployments
          |
          v
8. Test pod disruption
          |
          v
9. Test HPA and resource behavior
          |
          v
10. Validate ingress and networking
          |
          v
11. Upgrade a staging cluster
          |
          v
12. Run regression tests
          |
          v
13. Upgrade production
          |
          v
14. Monitor closely

The current Kubernetes release schedule makes this particularly timely: Kubernetes 1.34 is scheduled to enter maintenance mode on August 27, 2026, and its current end-of-life date is October 27, 2026. (Kubernetes)

What .NET Teams Should Verify

Before moving away from Kubernetes 1.34, make sure you can answer these questions:

[ ] Is the target Kubernetes version supported by our platform?

[ ] Are all Kubernetes APIs still supported?

[ ] Are our Helm charts compatible?

[ ] Are our CRDs and operators compatible?

[ ] Does the ASP.NET Core application start correctly?

[ ] Do readiness and liveness probes behave correctly?

[ ] Does graceful shutdown work?

[ ] Do database connections recover correctly?

[ ] Does HPA behave as expected?

[ ] Do network policies still allow required traffic?

[ ] Does ingress continue routing correctly?

[ ] Are secrets and configuration available?

[ ] Do background jobs survive pod replacement?

[ ] Does observability continue working?

[ ] Have we tested rolling upgrades?

[ ] Do we have a rollback plan?

If several answers are unknown, the cluster is not ready for a production upgrade.

Conclusion

Kubernetes 1.34 entering maintenance mode is a good reminder that Kubernetes upgrades should be treated as engineering projects rather than simple version changes. For .NET teams, the most important work is not only checking whether the cluster starts after an upgrade. You need to verify the complete application lifecycle, including ASP.NET Core startup, health probes, rolling deployments, database connections, background workers, scaling, ingress, networking, secrets, storage, and observability. Kubernetes 1.34 is scheduled to enter maintenance mode on August 27, 2026, so teams still running it should use the remaining time to establish a baseline, test their workloads against the target version, and identify compatibility issues early. A well-tested upgrade is much easier to manage than discovering a Kubernetes compatibility problem during a production deployment.