Kubernetes  

Kubernetes 1.34 Upgrade: Testing .NET Application Compatibility Before EOL

Introduction

Kubernetes upgrades are rarely difficult because of the version change alone. The real challenge is discovering what the application, container image, deployment manifests, admission controllers, observability stack, and infrastructure integrations expect from the cluster.

For .NET applications, an upgrade should therefore be treated as a compatibility exercise, not simply a control-plane operation.

Kubernetes 1.34 was released in August 2025 and introduced 58 enhancements across stable, beta, and alpha stages. The 1.34 release series is scheduled to enter maintenance mode on August 27, 2026, with end of life on October 27, 2026.

That makes compatibility testing especially relevant for teams still running applications on Kubernetes 1.33 or earlier and planning their upgrade path.

The key question is not:

"Will my .NET container start on Kubernetes 1.34?"

It is:

"Will my complete .NET workload behave correctly after the cluster upgrade?"

This article presents a practical compatibility-testing strategy for .NET applications before moving to Kubernetes 1.34.

What Can Break During a Kubernetes Upgrade?

A .NET application does not communicate only with Kubernetes itself.

A typical production deployment looks more like this:

                    Kubernetes Cluster
                           |
          +----------------+----------------+
          |                |                |
       Ingress          Service          Config
          |                |                |
          +----------------+----------------+
                           |
                         Pod
                           |
                    ASP.NET Core
                           |
              +------------+------------+
              |            |            |
           .NET SDK      Secrets      ConfigMap
              |
           Container

Compatibility problems can therefore appear in several places:

  • Kubernetes API versions

  • Deployment manifests

  • Ingress configuration

  • Service behavior

  • Probes

  • Resource limits

  • Security contexts

  • Admission webhooks

  • Container runtime behavior

  • CSI storage integrations

  • Network plugins

  • Monitoring agents

  • Logging agents

  • Helm charts

  • Operators

  • Custom Resource Definitions

  • .NET container images

The application may compile successfully and still fail after deployment.

Start With the Current Cluster Inventory

Before testing Kubernetes 1.34, document the current environment.

For example:

kubectl version
kubectl get nodes -o wide
kubectl get pods -A
kubectl get crd
kubectl get validatingwebhookconfigurations
kubectl get mutatingwebhookconfigurations

Also inspect the workloads:

kubectl get deployments -A
kubectl get statefulsets -A
kubectl get daemonsets -A

For a .NET application, record at least:

ComponentCurrent Value
Kubernetes versionCurrent production version
.NET runtime8/9/10/etc.
Container base imageLinux distribution + version
CPU requestApplication-specific
Memory requestApplication-specific
CPU limitApplication-specific
Memory limitApplication-specific
Ingress controllerCurrent version
CSI driverCurrent version
Observability agentCurrent version
Helm chartCurrent version

This inventory becomes the baseline for the compatibility test.

Understand Kubernetes Version Skew

Kubernetes does not require every component to change simultaneously.

The Kubernetes version-skew policy defines supported relationships between components. For example, kubelet must not be newer than kube-apiserver, while it can be several minor versions older within the documented limits. kubectl is supported within one minor version of the API server.

For an upgrade from Kubernetes 1.33 to 1.34, this means you should test the upgrade order rather than independently upgrading random components.

A simplified sequence is:

Current Cluster
      |
      v
Upgrade Control Plane
      |
      v
Validate API + Controllers
      |
      v
Upgrade Worker Nodes
      |
      v
Validate .NET Workloads
      |
      v
Production

The exact procedure depends on how the cluster is managed.

Build a Kubernetes 1.34 Test Environment

The safest approach is to create a representative non-production environment.

It should resemble production in the areas that affect application behavior:

Production
   |
   +-- .NET version
   +-- Container image
   +-- Kubernetes manifests
   +-- Ingress
   +-- Secrets
   +-- ConfigMaps
   +-- Storage
   +-- Network policies
   +-- Observability
   +-- Autoscaling

Avoid creating a test cluster that contains only the basic Deployment and Service.

That may prove that the container starts, but it does not provide meaningful compatibility evidence.

Test the .NET Container Independently

Before testing Kubernetes behavior, verify the application image itself.

A simple Dockerfile might look like:

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app

EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

COPY ["MyApi/MyApi.csproj", "MyApi/"]
RUN dotnet restore "MyApi/MyApi.csproj"

COPY . .
WORKDIR "/src/MyApi"

RUN dotnet publish \
    "MyApi.csproj" \
    -c Release \
    -o /app/publish \
    /p:UseAppHost=false

FROM base AS final
WORKDIR /app

COPY --from=build /app/publish .

ENTRYPOINT ["dotnet", "MyApi.dll"]

Test the image outside Kubernetes:

docker build -t myapi:test .
docker run --rm -p 8080:8080 myapi:test

Then verify:

curl http://localhost:8080/health

This separates container problems from Kubernetes problems.

Test the Kubernetes Deployment

A basic ASP.NET Core deployment could look like:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapi
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapi
  template:
    metadata:
      labels:
        app: myapi
    spec:
      containers:
        - name: myapi
          image: myapi:test
          ports:
            - containerPort: 8080

          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"

          readinessProbe:
            httpGet:
              path: /health/ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10

          livenessProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 15
            periodSeconds: 20

Apply it to the test cluster:

kubectl apply -f deployment.yaml

Then inspect:

kubectl get pods
kubectl describe pod <pod-name>
kubectl logs <pod-name>

The important point is to test the application exactly as production deploys it.

Validate Kubernetes API Usage

One of the most important upgrade checks is API compatibility.

Search deployment repositories for:

apiVersion:

For example:

apiVersion: apps/v1
kind: Deployment

Review:

  • Deployment

  • StatefulSet

  • DaemonSet

  • Ingress

  • CronJob

  • Role

  • RoleBinding

  • NetworkPolicy

  • PodDisruptionBudget

  • Custom resources

A .NET application may not directly use these APIs from C#, but its deployment infrastructure certainly does.

An API removal can therefore break deployment without changing a single line of C#.

Test Ingress Behavior

ASP.NET Core applications commonly sit behind an ingress layer.

Test:

Client
   |
   v
Ingress
   |
   v
Service
   |
   v
ASP.NET Core Pod

Validate:

  • HTTP routing

  • HTTPS termination

  • TLS certificates

  • Path rewriting

  • Headers

  • WebSocket connections

  • Request body limits

  • Timeouts

  • Client IP forwarding

For applications using authentication, specifically test:

Authorization header
Cookie
X-Forwarded-For
X-Forwarded-Proto
Host

A cluster upgrade can expose assumptions in proxy configuration that were not visible during normal application testing.

Validate ASP.NET Core Forwarded Headers

If your application relies on forwarded headers, make sure the configuration is explicitly tested.

For example:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor |
        ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

app.UseForwardedHeaders();

app.UseHttpsRedirection();

app.MapControllers();

app.Run();

This matters when application behavior depends on whether the original request was HTTP or HTTPS.

Authentication redirects, generated URLs, logging, and security policies can all be affected.

Test Health Probes

Health checks are especially important during node and pod transitions.

A basic ASP.NET Core setup might expose:

app.MapHealthChecks("/health/live");
app.MapHealthChecks("/health/ready");

Treat the two endpoints differently.

Liveness

Liveness should answer:

Is this process fundamentally alive?

Readiness

Readiness should answer:

Can this instance currently receive application traffic?

A readiness check might include dependencies such as a database or message broker, while liveness generally should not fail merely because an external dependency is temporarily unavailable.

This distinction becomes important during rolling upgrades.

Test Rolling Deployments

Run an actual rolling deployment in the Kubernetes 1.34 environment.

For example:

kubectl rollout status deployment/myapi

Then monitor:

kubectl get pods -w

Validate that:

Old Pod
   |
   v
Traffic continues
   |
   v
New Pod becomes Ready
   |
   v
Traffic moves
   |
   v
Old Pod terminates

The test should verify that there is no unacceptable interruption.

Test Resource Behavior

Kubernetes upgrades can expose resource assumptions.

For a .NET application, test:

  • CPU throttling

  • Memory limits

  • Garbage collection behavior

  • Container startup time

  • OOM termination

  • Pod eviction

  • Horizontal scaling

Inspect resource behavior with:

kubectl top pods
kubectl top nodes

Do not rely only on whether the application remains "Running."

A pod can be technically healthy while experiencing severe CPU throttling or memory pressure.

Test Autoscaling

If the application uses Horizontal Pod Autoscaling, reproduce a realistic workload.

For example:

kubectl get hpa

Then generate controlled traffic and observe:

Traffic
   |
   v
CPU / Memory / Custom Metric
   |
   v
HPA
   |
   v
Replica Count

Measure:

  • Scale-up time

  • Scale-down time

  • Maximum replicas

  • Request latency during scaling

  • Startup time of new .NET containers

The application startup path matters because a slow .NET container can create a larger gap between scaling decisions and usable capacity.

Test Graceful Shutdown

Rolling upgrades depend on applications shutting down correctly.

ASP.NET Core supports graceful application shutdown, but your application code should also handle cancellation appropriately.

For example:

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(5),
                stoppingToken);
        }
    }
}

The cancellation token should flow into long-running operations.

This becomes particularly important for:

  • Background workers

  • Queue consumers

  • Message processors

  • Scheduled jobs

  • Long-running HTTP calls

Test Persistent Storage

If your .NET application uses persistent volumes, include storage in the compatibility test.

Validate:

Pod
 |
 v
PVC
 |
 v
Storage Driver
 |
 v
Storage Backend

Test:

  • Mounting

  • Reading

  • Writing

  • Restarting pods

  • Rescheduling pods

  • Persistent data availability

Do not treat storage as compatible merely because the PVC object still exists.

Test Observability

A Kubernetes upgrade can affect monitoring and logging even when the application works perfectly.

For a .NET application, validate:

  • Application logs

  • Structured logging

  • Metrics

  • Distributed tracing

  • OpenTelemetry exporters

  • Container metadata

  • Pod metadata

  • Node metadata

For example:

ASP.NET Core
     |
     +--> Logs
     |
     +--> Metrics
     |
     +--> Traces
             |
             v
       Observability Stack

Confirm that telemetry still contains the identifiers your operations team relies on.

Test Security Contexts

Check workloads that use:

securityContext:
  runAsNonRoot: true
  allowPrivilegeEscalation: false

Also test:

  • Read-only root filesystem

  • Linux capabilities

  • Service accounts

  • Secret mounts

  • Network policies

  • Pod security policies or their replacements where applicable

  • Admission policies

A .NET application that writes temporary files to an unexpected filesystem location may behave differently when security restrictions are enforced.

Run Application-Level Regression Tests

Infrastructure compatibility is not enough.

Run the application's normal test suite:

dotnet test

Then run integration tests against the Kubernetes 1.34 environment.

For example:

Authentication
      |
      v
API Request
      |
      v
ASP.NET Core
      |
      +--> Database
      |
      +--> Cache
      |
      +--> Message Broker

Test the complete path.

Include:

  • Authentication

  • Authorization

  • CRUD operations

  • Database access

  • Cache access

  • Messaging

  • File operations

  • Background jobs

  • External APIs

  • Error handling

Benchmark Before and After the Upgrade

Compatibility testing should include performance measurements.

Record a baseline from the current cluster:

MetricCurrent ClusterKubernetes 1.34
P50 latencyBaselineMeasure
P95 latencyBaselineMeasure
P99 latencyBaselineMeasure
Requests/secBaselineMeasure
CPU/requestBaselineMeasure
Memory/requestBaselineMeasure
Error rateBaselineMeasure
Startup timeBaselineMeasure

Do not declare compatibility solely because functional tests pass.

A workload that passes functional tests but has significantly worse P95 latency still needs investigation.

Test Failure Scenarios

A useful upgrade test intentionally creates failures.

For example:

Kill Pod
   |
   v
Does traffic continue?

Then:

Restart Node
   |
   v
Does workload recover?

And:

Database unavailable
   |
   v
Does readiness behave correctly?

Also test:

  • Pod eviction

  • Node drain

  • Application restart

  • Dependency timeout

  • Network interruption

  • Failed image pull

  • Secret/configuration errors

These tests reveal whether the application and Kubernetes configuration fail safely.

Validate Deployment Automation

The final test should include the actual deployment pipeline.

For example:

Git Commit
   |
   v
Build
   |
   v
Unit Tests
   |
   v
Container Build
   |
   v
Security Scan
   |
   v
Deploy to Kubernetes 1.34
   |
   v
Integration Tests
   |
   v
Smoke Tests

Do not manually deploy the application to the test cluster and consider the migration validated.

The deployment automation itself must be tested.

Build a Compatibility Matrix

A useful migration artifact is a compatibility matrix.

AreaTestResultRisk
ContainerImage startsPassLow
DeploymentPod rolloutPassLow
IngressHTTPS routingPassMedium
ProbesReadiness/livenessPassLow
HPAScalingPassMedium
StoragePVC operationsPassHigh
MessagingQueue processingPassMedium
ObservabilityTraces/logsPassMedium
SecurityNon-root executionPassLow
PerformanceP95 latencyPassMedium

This gives the upgrade team something more useful than a generic statement that "testing passed."

Common Mistakes

Testing Only Pod Startup

A running container does not prove application compatibility.

Testing Only the .NET Application

Kubernetes manifests, ingress, storage, networking, and observability also need testing.

Ignoring Admission Webhooks

Admission components can affect whether workloads are accepted and how resources are mutated.

Skipping Performance Tests

Functional compatibility does not guarantee performance compatibility.

Testing Only Happy Paths

Upgrade testing should include node failure, pod termination, dependency failures, and rolling deployments.

Using a Different Container Image

If production uses a specific .NET runtime and base image, test that same image.

Ignoring CI/CD

A successful manual deployment does not validate the actual production deployment process.

Best Practices

  1. Inventory the complete production workload before upgrading.

  2. Test the exact .NET container image used in production.

  3. Use a Kubernetes 1.34 environment that resembles production.

  4. Review Kubernetes API versions in manifests and Helm charts.

  5. Test ingress, services, probes, autoscaling, and storage.

  6. Validate .NET graceful shutdown behavior.

  7. Run application integration and regression tests.

  8. Test observability pipelines, not just application functionality.

  9. Include security-context and admission-policy testing.

  10. Measure P50, P95, and P99 latency before and after the upgrade.

  11. Test failure and recovery scenarios.

  12. Run the real CI/CD deployment pipeline against the test cluster.

  13. Document compatibility results in a migration matrix.

  14. Upgrade to the latest patch release of the target minor version rather than testing against an arbitrary early patch.

The Kubernetes project itself recommends ensuring components are on the latest patch of the current minor version before upgrading, and then moving to the latest patch of the target minor version.

A Practical Pre-Upgrade Checklist

Before approving the production migration, verify:

[ ] Current cluster inventory completed
[ ] Kubernetes APIs reviewed
[ ] .NET container image tested
[ ] Deployment manifests validated
[ ] Ingress tested
[ ] Health probes tested
[ ] Rolling deployment tested
[ ] Graceful shutdown tested
[ ] HPA tested
[ ] Storage tested
[ ] Network policies tested
[ ] Secrets/configuration tested
[ ] Observability validated
[ ] Security context validated
[ ] Integration tests passed
[ ] Failure scenarios tested
[ ] Performance baseline compared
[ ] CI/CD pipeline tested
[ ] Rollback procedure tested

A rollback test is particularly important. The team should know not only how to upgrade, but also how to recover if the upgraded environment produces unacceptable behavior.

Frequently Asked Questions

Does Kubernetes 1.34 require .NET application code changes?

Not necessarily. Many .NET applications can continue running without source-code changes, but compatibility depends on the application's Kubernetes integrations, container image, deployment configuration, and surrounding infrastructure.

Should I upgrade .NET and Kubernetes at the same time?

For an infrastructure compatibility test, changing both simultaneously makes troubleshooting harder. Unless there is a specific reason to combine the upgrades, isolate variables where practical.

What should be tested first?

Start with container and deployment compatibility, then validate ingress, probes, scaling, dependencies, observability, security, and performance.

Is a successful kubectl apply enough?

No. A successful deployment only proves that Kubernetes accepted the resource definitions. It does not prove that the application behaves correctly.

Should performance testing be part of the upgrade?

Yes. At minimum, compare application latency, throughput, resource consumption, startup time, and error rates before and after the upgrade.

Is Kubernetes 1.34 still supported?

As of August 19, 2026, Kubernetes 1.34 remains actively supported. Its maintenance mode is scheduled to begin on August 27, 2026, and its end-of-life date is October 27, 2026.

Conclusion

A Kubernetes upgrade should be treated as a compatibility and reliability exercise rather than a simple infrastructure change.

For .NET applications, the most important validation happens across the boundary between the application and the platform: container startup, health probes, graceful shutdown, networking, ingress, storage, autoscaling, security policies, observability, and deployment automation.

Kubernetes 1.34 introduced substantial platform changes and remains supported until October 27, 2026, making a structured migration plan particularly important for teams approaching the end of its support window.

The safest approach is straightforward:

Build a representative Kubernetes 1.34 environment, deploy the real .NET workload, run functional and failure tests, compare performance with the existing cluster, and validate the complete CI/CD path before production migration.

That turns a Kubernetes upgrade from a high-risk event into a measurable engineering exercise.