Kubernetes  

Kubernetes 1.34 Maintenance: Testing .NET Deployment Compatibility

Introduction

Kubernetes upgrades are often treated as infrastructure changes, but they can directly affect application deployments.

A .NET application may continue to build successfully while its Kubernetes deployment fails because of changes in APIs, container configuration, probes, networking, storage, security settings, or platform behavior.

Kubernetes 1.34 introduces an important maintenance milestone for teams still running older Kubernetes versions. As a result, teams managing .NET workloads should validate their deployment manifests and application behavior before moving their clusters forward.

The safest approach is not to wait for the production upgrade and discover compatibility problems afterward. Instead, create a repeatable compatibility test that validates the complete path:

.NET Application
      |
      v
Container Image
      |
      v
Kubernetes Manifest
      |
      v
Kubernetes Cluster
      |
      v
Running Application

This article explains how to test .NET application compatibility with Kubernetes 1.34 and identify deployment problems before they reach production.

Why Kubernetes Version Compatibility Matters

A Kubernetes version affects more than the Kubernetes API server.

A production application typically depends on several components:

  • Kubernetes API

  • Container runtime

  • Ingress or Gateway

  • Service networking

  • ConfigMaps

  • Secrets

  • Persistent storage

  • Health probes

  • Service accounts

  • RBAC

  • Autoscaling

  • Jobs and CronJobs

A .NET application can therefore be perfectly valid while its surrounding deployment configuration contains compatibility issues.

For example:

.NET Application
       |
       +-- Deployment
       +-- Service
       +-- ConfigMap
       +-- Secret
       +-- Ingress
       +-- HPA
       +-- PVC
       +-- ServiceAccount

Testing only the application container does not validate the complete deployment.

Start With a Kubernetes Inventory

Before upgrading the cluster, document what the application actually uses.

A simple inventory can look like this:

ResourceUsedCritical
DeploymentYesYes
ServiceYesYes
ConfigMapYesYes
SecretYesYes
IngressYesYes
HPAYesMaybe
PVCYes/NoDepends
CronJobYes/NoDepends
ServiceAccountYesYes

This gives the migration team a concrete list of resources to test.

Do not assume that every application needs every Kubernetes feature.

Check the Current Cluster Version

Before beginning the migration, record the current Kubernetes version.

For example:

kubectl version

Also inspect the nodes:

kubectl get nodes -o wide

And review the workloads:

kubectl get deployments -A

The objective is to understand the starting point.

A useful migration record contains:

Current Kubernetes Version
Target Kubernetes Version
Node Versions
Container Runtime
Ingress Implementation
Storage Provider
Application Image
.NET Runtime Version

Validate the .NET Container Image

The first compatibility layer is the container itself.

A typical .NET application Dockerfile might look like:

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

EXPOSE 8080

COPY ./publish/ .

ENTRYPOINT ["dotnet", "Orders.Api.dll"]

The important part is that the Kubernetes deployment should match how the container actually listens and starts.

For example, if the application listens on port 8080, the Kubernetes configuration should expose the same port.

containers:
  - name: orders-api
    image: orders-api:latest
    ports:
      - containerPort: 8080

A Kubernetes upgrade is a good opportunity to verify that these assumptions are still correct.

Test the Application Locally in a Container

Before testing Kubernetes compatibility, verify the container independently.

Build the image:

docker build -t orders-api:test .

Run it:

docker run --rm -p 8080:8080 orders-api:test

Then test the health endpoint:

curl http://localhost:8080/health

If the container itself does not behave correctly, Kubernetes testing will only make troubleshooting harder.

The validation order should be:

Application
    |
    v
Container
    |
    v
Kubernetes

Validate Deployment Manifests

Review the application's Kubernetes manifests before applying them to the target cluster.

A typical Deployment may look like:

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
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"

Check every field rather than assuming that an existing manifest is still appropriate.

Test Health Probes

Health probes are particularly important for .NET applications.

A simple ASP.NET Core application can expose a health endpoint:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHealthChecks();

var app = builder.Build();

app.MapHealthChecks("/health");

app.Run();

Then Kubernetes can use:

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 10

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

The distinction matters.

Liveness Probe

Determines whether the container should continue running.

Readiness Probe

Determines whether the application should receive traffic.

A deployment upgrade can expose incorrect probe assumptions.

For example, if an application takes longer to initialize after deployment, an overly aggressive liveness probe can cause unnecessary restarts.

Test Startup Behavior

.NET applications can have different startup requirements depending on:

  • Configuration loading

  • Database connections

  • Dependency injection

  • External services

  • Certificate loading

  • Cache initialization

  • Entity Framework Core initialization

Do not assume that the application is ready immediately after the process starts.

A better deployment test is:

Pod Created
    |
    v
Container Started
    |
    v
Application Initialized
    |
    v
Readiness Check
    |
    v
Traffic Enabled

Observe the complete startup sequence.

Validate ConfigMaps and Secrets

Kubernetes configuration is another important compatibility area.

For example:

env:
  - name: ASPNETCORE_ENVIRONMENT
    valueFrom:
      configMapKeyRef:
        name: orders-config
        key: environment

Secrets may be loaded similarly:

env:
  - name: ConnectionStrings__Database
    valueFrom:
      secretKeyRef:
        name: orders-secrets
        key: database

After deployment, verify that the application receives the expected configuration.

Do not print sensitive values into application logs while testing.

Instead, validate configuration indirectly.

For example:

Database Configuration Loaded
      |
      v
Database Connection Successful

rather than logging the actual connection string.

Test Service Connectivity

A .NET application may expose port 8080, while the Kubernetes Service exposes another port.

For example:

apiVersion: v1
kind: Service
metadata:
  name: orders-api
spec:
  selector:
    app: orders-api
  ports:
    - port: 80
      targetPort: 8080

The traffic path becomes:

Client
  |
  v
Service :80
  |
  v
Pod :8080
  |
  v
ASP.NET Core

Test this path after deploying to the target cluster.

A healthy pod does not automatically mean that service routing is correct.

Validate Ingress or Gateway Configuration

If the application is externally accessible, validate its traffic entry point.

Test:

External Request
       |
       v
Ingress / Gateway
       |
       v
Service
       |
       v
Pod
       |
       v
.NET Application

Check:

  • Host routing

  • TLS termination

  • Backend service

  • Port mapping

  • Health checks

  • Authentication integration

  • Timeout configuration

If your environment uses a specific ingress controller or Gateway implementation, test that component independently as part of the cluster upgrade.

Test Resource Requests and Limits

A Kubernetes upgrade is also an opportunity to validate application resource configuration.

For example:

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

These values should be based on actual workload requirements.

Do not copy arbitrary CPU and memory values into production.

For a .NET application, monitor:

  • CPU usage

  • Working set

  • Allocation rate

  • Garbage collection

  • Request latency

  • Container restarts

The objective is to determine whether the application remains stable under its expected resource constraints.

Test Horizontal Pod Autoscaling

If the application uses HPA, verify scaling behavior.

A simplified configuration 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: 8
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

The test should confirm:

Low Load
   |
   v
Minimum Replicas

High Load
   |
   v
Scale Out

Load Decreases
   |
   v
Scale In

Do not test only whether the HPA object exists.

Generate representative load and observe whether the application actually scales as expected.

Test Graceful Shutdown

Container orchestration means applications are frequently started and stopped.

A .NET application should handle shutdown gracefully.

For example:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHostedService<Worker>();

var app = builder.Build();

app.MapGet("/", () => "Orders API");

app.Run();

Background services should correctly respond to cancellation.

A worker might use:

protected override async Task ExecuteAsync(
    CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        await ProcessQueueAsync(stoppingToken);

        await Task.Delay(
            TimeSpan.FromSeconds(10),
            stoppingToken);
    }
}

During Kubernetes testing, terminate a pod and verify that active work is handled according to the application's requirements.

Test Rolling Updates

A Kubernetes deployment should be tested under an actual rolling update.

A simplified strategy is:

Version A
   |
   +-- Pod 1
   +-- Pod 2
   +-- Pod 3
        |
        v
Rolling Update
        |
        v
Version B
   |
   +-- Pod 1
   +-- Pod 2
   +-- Pod 3

During the update, monitor:

  • Request failures

  • Readiness status

  • Pod restarts

  • Response latency

  • Connection errors

  • Background jobs

The application should remain available according to the deployment's availability requirements.

Test Database Connectivity During Pod Replacement

This is particularly important for EF Core applications.

During a rolling deployment:

Old Pod
   |
   +-- Database Connections

New Pod
   |
   +-- Database Connections

Verify that:

  • New pods can establish connections.

  • Old pods release connections correctly.

  • Connection pools recover after termination.

  • Database connection limits are not exceeded.

A cluster upgrade can expose connection-management assumptions that were not visible during single-pod testing.

Validate Persistent Storage

Applications that use persistent volumes require additional testing.

For example:

Pod
 |
 v
PersistentVolumeClaim
 |
 v
PersistentVolume
 |
 v
Storage Backend

A test should verify:

  1. The volume can be mounted.

  2. The application can write data.

  3. The pod can be restarted.

  4. The volume can be remounted.

  5. Previously written data remains available.

For example:

kubectl get pvc

Then inspect the pod:

kubectl describe pod <pod-name>

Storage behavior should be tested independently from application deployment.

Test CronJobs and Background Processing

Scheduled workloads can be overlooked during cluster upgrades.

For example:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: orders-cleanup
spec:
  schedule: "0 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: cleanup
              image: orders-cleanup:latest

Verify that:

  • The CronJob is scheduled.

  • Jobs are created.

  • The container starts.

  • Database operations succeed.

  • Failed jobs behave as expected.

Do not limit compatibility testing to long-running Deployments.

Validate RBAC

Kubernetes permissions can affect whether applications start correctly.

A service account might be associated with:

serviceAccountName: orders-api

Test the permissions required by the application.

Do not solve permission failures by simply granting broad cluster-level access.

Use the smallest permission set required.

A good validation process is:

Application
   |
   v
Requested Resource
   |
   v
RBAC Check
   |
   +-- Allowed -> Continue
   |
   +-- Denied -> Controlled Failure

Check Deprecated APIs

One of the most important upgrade checks is identifying manifests that rely on APIs that are no longer appropriate for the target Kubernetes version.

Inspect the application's manifests and deployment tooling.

Look for:

  • Deprecated API versions

  • Removed API versions

  • Old resource definitions

  • Outdated admission configurations

  • Legacy ingress resources

  • Deprecated autoscaling configurations

The exact API compatibility requirements should be validated against the Kubernetes version used by your cluster.

Do not assume that a manifest created several years ago is automatically safe for a current cluster.

Run a Staging Upgrade First

The safest migration sequence is:

Production
    |
    v
Clone Relevant Configuration
    |
    v
Staging Cluster
    |
    v
Upgrade Kubernetes
    |
    v
Deploy .NET Application
    |
    v
Run Tests
    |
    v
Observe
    |
    v
Production

Staging should reproduce the important production characteristics.

This includes:

  • Kubernetes configuration

  • Node characteristics

  • Networking

  • Storage

  • Ingress

  • Secrets

  • Application image

  • Database connectivity

The objective is not to perfectly reproduce every production detail. It is to reproduce the parts that could affect compatibility.

Common Mistakes

Testing Only Pod Startup

A pod can be running while the application is inaccessible.

Ignoring Readiness Probes

Incorrect readiness configuration can cause traffic to reach an application before it is ready.

Testing Only the .NET Container

The Kubernetes platform includes services, ingress, storage, RBAC, and other components.

Ignoring Background Jobs

CronJobs and workers may use different deployment paths.

Using Excessive RBAC Permissions

Granting broad permissions can hide the real permission requirements of the application.

Skipping Rolling Updates

A deployment that works from zero replicas does not necessarily behave correctly during an upgrade.

Ignoring Storage

Persistent workloads require restart and remount testing.

Troubleshooting

Pod Is Running but Application Is Unavailable

Check:

Pod
 |
 +-- Container Port
 +-- Readiness Probe
 +-- Service
 +-- Target Port
 +-- Ingress

Determine where traffic stops.

Pod Keeps Restarting

Inspect:

kubectl describe pod <pod-name>

Then review container logs:

kubectl logs <pod-name>

Look for:

  • Startup failures

  • Configuration errors

  • Failed health probes

  • Missing secrets

  • Database connection errors

Readiness Probe Fails

Verify:

  • Correct endpoint

  • Correct port

  • Application startup time

  • Required dependencies

  • Probe timing

Do not simply increase probe delays without understanding why readiness is failing.

Application Cannot Connect to PostgreSQL

Verify:

  • Service name

  • DNS resolution

  • Connection string

  • Secret configuration

  • Network policies

  • Database availability

  • Connection pool behavior

HPA Does Not Scale

Check:

  • Metrics availability

  • Resource requests

  • HPA configuration

  • Current utilization

  • Deployment reference

An HPA cannot make meaningful CPU-utilization decisions if the required resource configuration is missing or unsuitable.

Best Practices

  1. Record the current Kubernetes and node versions.

  2. Inventory all Kubernetes resources used by the application.

  3. Validate the .NET container independently.

  4. Review deployment manifests for deprecated APIs.

  5. Test readiness and liveness probes.

  6. Validate ConfigMaps and Secrets without exposing sensitive values.

  7. Test Service and ingress routing.

  8. Test resource requests and limits.

  9. Test HPA behavior where applicable.

  10. Test rolling updates.

  11. Test graceful shutdown.

  12. Test persistent volumes for stateful applications.

  13. Test CronJobs and background workers.

  14. Validate RBAC permissions.

  15. Perform the upgrade in staging first.

  16. Monitor application and cluster logs during the upgrade.

  17. Keep a rollback strategy available.

  18. Record the results of every compatibility test.

Advantages

  • Detects deployment problems before production.

  • Reduces risk during Kubernetes upgrades.

  • Provides a repeatable validation process for .NET workloads.

  • Helps identify problems outside the application code.

  • Improves confidence in rolling deployments.

  • Makes infrastructure compatibility testing more systematic.

Disadvantages

  • Requires a representative staging environment.

  • Kubernetes upgrades can involve many infrastructure components.

  • Testing storage and networking may require additional environments.

  • Some failures depend on cluster-specific configurations.

  • Maintaining compatibility tests adds operational work.

A Practical Kubernetes Compatibility Test

A complete validation process can be organized into these stages:

                 Kubernetes Upgrade
                         |
                         v
                Environment Inventory
                         |
                         v
                .NET Container Test
                         |
                         v
              Manifest Compatibility
                         |
                         v
                 Staging Deployment
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
       Networking      Storage         Security
          |              |              |
          +--------------+--------------+
                         |
                         v
                  Application Tests
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
        API            Worker         CronJob
          |              |              |
          +--------------+--------------+
                         |
                         v
                  Rolling Update
                         |
                         v
                     Monitoring
                         |
                         v
                Production Upgrade

This approach makes the upgrade a controlled engineering process rather than a single infrastructure event.

Conclusion

Kubernetes upgrades can affect .NET applications even when the application code itself has not changed. Deployment manifests, health probes, networking, storage, RBAC, autoscaling, background jobs, and container behavior all contribute to whether an application continues operating correctly after a cluster upgrade.

For teams preparing a Kubernetes 1.34 upgrade, the most useful preparation is to establish a staging environment, inventory the application's Kubernetes dependencies, validate the .NET container, test deployment resources, and perform realistic rolling-update scenarios.

The key is to test the complete application path rather than checking only whether pods become Running. A successful compatibility test should demonstrate that the .NET application starts correctly, receives traffic, connects to its dependencies, scales when required, handles shutdown correctly, and continues processing workloads throughout the Kubernetes upgrade process.