Kubernetes minor-version upgrades are often treated as infrastructure maintenance.

For a .NET team, that can be misleading.

A Kubernetes upgrade can change the environment in which an ASP.NET Core application runs:

Kubernetes
    ↓
Kubelet
    ↓
Container Runtime
    ↓
Linux
    ↓
.NET Runtime
    ↓
ASP.NET Core
    ↓
Application

A change at any layer can appear as an application problem.

The Kubernetes 1.37 release is currently scheduled for August 26, 2026. The release candidate was published on August 5, and the project is currently in the final stages of the release cycle.

That makes the period before the release a good time to validate production clusters.

For .NET services, the biggest upgrade risks are not necessarily changes to C# code. They are operational issues involving node compatibility, container runtimes, cgroup configuration, pod lifecycle, health probes, resource behavior, and workload disruption.

What Changes During a Kubernetes Upgrade?

A Kubernetes minor upgrade can involve several components:

Control Plane
    ↓
API Server
Controller Manager
Scheduler
    ↓
Worker Nodes
    ↓
Kubelet
Container Runtime

For a kubeadm-managed cluster, Kubernetes explicitly recommends upgrading one minor version at a time rather than skipping minor versions. The documented upgrade procedure also notes that containers are restarted during an upgrade because the container specification hash changes.

That restart behavior matters for .NET services.

Even if the application image itself does not change, your application processes can still restart as nodes and cluster components are upgraded.

First Risk: Kubernetes 1.37 Is a Pre-Release Planning Target

As of this writing, Kubernetes 1.37 has not reached general availability.

The official schedule lists:

1.37.0-rc.0
    ↓
August 5, 2026

1.37.0-rc.1
    ↓
August 19, 2026

1.37.0
    ↓
August 26, 2026

These dates come from the Kubernetes release schedule and can change if the release process changes.

Therefore, production teams should distinguish between:

Testing against 1.37 RC

and:

Production upgrade to 1.37.0

Do not automatically promote a release candidate to production simply because application tests pass.

Risk 1: Container Runtime and cgroup Compatibility

One of the most important node-level checks is the relationship between:

Kubelet
+
Container Runtime
+
cgroup Driver

Kubernetes documents that the kubelet and container runtime must use compatible cgroup-driver configuration. The systemd driver is recommended when using cgroup v2.

Check the node:

stat -fc %T /sys/fs/cgroup/

For cgroup v2, Kubernetes documents:

cgroup2fs

For cgroup v1:

tmpfs

Kubernetes has deprecated cgroup v1, and kubelet does not start on cgroup-v1 nodes by default unless the administrator explicitly changes the failCgroupV1 setting.

For an upgrade, this should be a node-inventory check rather than something discovered after a reboot.

Check the Container Runtime Before Upgrading

Inspect the runtime:

kubectl get nodes \
  -o custom-columns=NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion,RUNTIME:.status.nodeInfo.containerRuntimeVersion

For containerd, inspect:

containerd --version

and:

sudo grep -n "SystemdCgroup" \
  /etc/containerd/config.toml

Kubernetes documentation distinguishes the configuration structure for containerd 1.x and 2.x and recommends matching the runtime and kubelet cgroup-driver configuration.

Do not assume that every node in the cluster has identical runtime configuration.

Mixed node pools are common in long-lived clusters.

Risk 2: cgroup v1 Nodes

A cluster can appear healthy while containing old nodes.

That becomes dangerous during an upgrade.

Suppose:

Node A → cgroup v2
Node B → cgroup v2
Node C → cgroup v1

The cluster may operate normally until Node C is rebooted or replaced.

A Kubernetes upgrade is exactly the kind of event that can expose this configuration drift.

Find affected nodes before upgrading:

kubectl get nodes -o wide

Then inspect each Linux node:

stat -fc %T /sys/fs/cgroup/

Do not rely only on the control-plane version.

Risk 3: .NET Pods Will Restart

A Kubernetes node upgrade normally involves draining and rescheduling workloads.

For kubeadm upgrades, Kubernetes documents that containers are restarted after an upgrade because the container specification hash changes.

For an ASP.NET Core application:

Pod
 ↓
SIGTERM / shutdown
 ↓
Application stops
 ↓
Pod terminates
 ↓
New Pod starts
 ↓
Readiness probe passes
 ↓
Traffic resumes

Your application therefore needs to handle startup and shutdown correctly.

Risk 4: ASP.NET Core Graceful Shutdown

ASP.NET Core provides host lifecycle mechanisms for graceful shutdown.

The .NET Generic Host listens for termination signals through ConsoleLifetime, allowing the application to begin a graceful shutdown. During shutdown, the host stops accepting new connections and allows existing requests to complete within the configured shutdown period.

This matters when Kubernetes drains a node.

A service should not assume that:

Pod termination
=
instant process termination

Instead, test the complete lifecycle.

For example:

Request in progress
        ↓
Pod receives termination
        ↓
Application begins shutdown
        ↓
Existing request completes
        ↓
Process exits

.NET 10 Adds Another Shutdown Consideration

.NET 10 changed the default runtime behavior around Unix termination signals. The runtime itself no longer installs the previous default SIGTERM handler.

Microsoft notes that typical ASP.NET Core applications do not require action because higher-level hosting APIs such as ConsoleLifetime handle application-model-specific termination behavior.

This creates an important upgrade-testing rule:

Test the actual application entry point, not an isolated console process.

If your service uses custom process-level signal handling, verify that behavior explicitly.

Risk 5: Readiness and Liveness Probes

A Kubernetes upgrade can restart pods faster than a poorly configured application can become ready.

Consider:

readinessProbe:
  httpGet:
    path: /health/ready
    port: 8080

and:

livenessProbe:
  httpGet:
    path: /health/live
    port: 8080

These should not necessarily perform the same checks.

Microsoft recommends separating readiness and liveness semantics in ASP.NET Core. Readiness indicates whether the application can receive requests, while liveness indicates whether the application is functioning sufficiently to avoid being restarted.

A useful model is:

/health/live
    ↓
"Is the process functioning?"

/health/ready
    ↓
"Can this instance receive traffic?"

Avoid Using Database Health for Liveness

A common configuration is:

Liveness
    ↓
Database check
    ↓
Database unavailable
    ↓
Restart application

This can create a restart loop.

If the database is temporarily unavailable, restarting every application replica can make the incident worse.

Instead:

Liveness
    ↓
Process/application health

Readiness
    ↓
Can this instance serve requests?

The exact dependency checks should be based on your architecture.

Risk 6: Startup Time

.NET services may perform significant startup work:

Configuration
Database migration checks
Cache initialization
Certificate loading
Dependency discovery
Message-broker connection

If the readiness probe starts too early:

Pod starts
 ↓
Readiness fails
 ↓
Traffic delayed

That may be acceptable.

But if liveness is also configured too aggressively:

Pod starts
 ↓
Liveness fails
 ↓
Pod restarts
 ↓
Startup repeats

you can create a restart loop.

ASP.NET Core documentation demonstrates using separate readiness and liveness checks specifically for applications with long-running startup work.

Risk 7: Pod Disruption During Node Upgrades

Before upgrading nodes, inspect:

kubectl get pods -A

and:

kubectl get pdb -A

PodDisruptionBudgets can limit how many replicas are voluntarily disrupted at once.

For a .NET API with:

3 replicas

a sensible disruption policy may allow one replica to be unavailable while the others continue serving traffic.

The exact configuration depends on your availability requirements.

The important point is to verify that:

Node drain
+
PDB
+
Replica count

do not create an impossible scheduling situation.

Risk 8: Single-Replica .NET Services

A deployment such as:

replicas: 1

is especially sensitive to node upgrades.

During a node drain:

Replica
   ↓
Terminated
   ↓
Rescheduled
   ↓
Startup

There can be a period with no available instance.

For critical services, evaluate whether multiple replicas are required.

Do not confuse Kubernetes availability with application availability.

A Kubernetes deployment can be healthy while the application has zero ready replicas.

Risk 9: Resource Requests and Limits

Node upgrades change scheduling conditions.

Suppose your application requests:

resources:
  requests:
    cpu: "500m"
    memory: "512Mi"

and limits:

resources:
  limits:
    cpu: "1"
    memory: "1Gi"

During a rolling node upgrade, replacement capacity must exist for these requests.

If the remaining nodes do not have sufficient allocatable capacity:

Drain node
   ↓
Pod pending
   ↓
No capacity

The application may become unavailable.

Check:

kubectl describe nodes

and inspect:

Allocatable
Requested
Allocated

before starting the upgrade.

Risk 10: .NET Memory Behavior

.NET applications can be sensitive to container memory limits.

A service may appear healthy under normal traffic but fail after rescheduling onto a node with different resource pressure.

Monitor:

Working set
GC heap
GC pauses
Container memory
OOMKilled events

Check recent events:

kubectl get events \
  --sort-by=.lastTimestamp

Also inspect pod status:

kubectl describe pod <pod-name>

Look for:

OOMKilled
Evicted
BackOff
Unhealthy
FailedScheduling

Do not increase memory limits automatically after an upgrade without identifying the actual cause.

Risk 11: ASP.NET Core Container Port Changes

Containerized ASP.NET Core applications should have explicit port configuration.

.NET 8 changed the default ASP.NET Core container port from 80 to 8080. Microsoft documents that Kubernetes manifests and other container configurations may need to account for this change.

For example:

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

A Kubernetes upgrade is not itself responsible for this .NET change, but upgrade testing is a good opportunity to detect stale manifests.

Verify:

Container port
Service targetPort
Probe port
Ingress/backend port
Application listening address

all agree.

Risk 12: API Deprecations and Removed APIs

Minor Kubernetes releases can deprecate APIs and remove functionality.

Kubernetes documents that deprecated APIs continue to function until their planned removal, while removed APIs are no longer available in the newer version.

This is particularly important for:

Helm charts
Operators
Admission controllers
Ingress controllers
Monitoring agents
CI/CD tools
Custom controllers

The .NET application may be completely correct while its deployment tooling is incompatible.

Audit Manifests Before the Upgrade

Search your repositories:

grep -R \
  "apiVersion:" \
  ./k8s

Also inspect Helm templates:

helm template ./chart

Then validate the generated manifests against the target cluster.

Do not inspect only the application's Deployment.

Check:

Deployment
Service
Ingress
ConfigMap
Secret
HPA
PDB
NetworkPolicy
ServiceAccount
RBAC
CronJob

Risk 13: Ingress and Gateway Dependencies

A .NET API may be healthy while external traffic fails because the ingress or gateway layer is incompatible.

Test:

Internet
   ↓
Load Balancer
   ↓
Ingress / Gateway
   ↓
Service
   ↓
Pod
   ↓
ASP.NET Core

After the upgrade, verify:

kubectl get ingress -A

and:

kubectl get svc -A

For modern deployments, also inspect Gateway API resources where applicable.

Do not test only:

curl localhost:8080

That verifies the application but not the production traffic path.

Risk 14: DNS and Service Discovery

A distributed .NET application may depend heavily on Kubernetes DNS:

orders-api
payments-api
identity-api

Test internal connectivity after node upgrades:

kubectl exec \
  <pod-name> \
  -- getent hosts orders-api

Then test the actual service endpoint.

A healthy pod does not guarantee that:

DNS
+
Service
+
Network Policy

are functioning correctly.

Risk 15: Network Policies

If your .NET services use NetworkPolicies, test both:

Allowed traffic

and:

Denied traffic

For example:

API
 ↓
Database

should remain allowed.

But:

Unknown namespace
 ↓
Database

should remain blocked.

Upgrade validation should confirm that security boundaries did not change unintentionally.

Build an Upgrade Test Environment

A practical sequence is:

Development
    ↓
Upgrade test cluster
    ↓
Staging
    ↓
Canary production nodes
    ↓
Full production rollout

Do not use production as the first place where the cluster encounters Kubernetes 1.37.

A representative staging cluster should include:

Same .NET runtime
Same container image
Same probes
Same ingress
Same runtime configuration
Same monitoring
Same policies

as production.

Test a Real .NET Workload

A basic smoke test is:

curl https://api.example.com/health/ready

Then exercise:

GET
POST
Authentication
Database access
External API calls
Background jobs
Message queues
File/storage operations

The exact tests should match your service.

Test Rolling Restarts

Before upgrading Kubernetes, simulate the event:

kubectl rollout restart deployment my-api

Observe:

kubectl rollout status deployment my-api

Then inspect:

kubectl get pods -w

You want to confirm:

Old pod
   ↓
Not ready
   ↓
New pod ready
   ↓
Old pod terminated

without unacceptable request failures.

Test Node Drain

A more realistic test is:

kubectl drain <node-name> \
  --ignore-daemonsets \
  --delete-emptydir-data

Do this only in an appropriate test environment and according to your cluster's operational procedures.

Observe:

Pod eviction
Rescheduling
Readiness
Application startup
Request failures
PDB behavior

This closely approximates what happens during node maintenance.

Monitor the .NET Application During the Test

Watch:

kubectl top pods

and:

kubectl get pods -w

Also inspect application telemetry:

Request rate
Error rate
P95 latency
P99 latency
GC behavior
Database latency
Dependency failures

The goal is not merely:

kubectl get nodes
→ Ready

A cluster can be green while the application is experiencing elevated latency.

Validate Graceful Shutdown

Create a long-running test endpoint:

app.MapGet(
    "/test/slow",
    async (CancellationToken cancellationToken) =>
    {
        await Task.Delay(
            TimeSpan.FromSeconds(10),
            cancellationToken);

        return Results.Ok();
    });

Then send a request while terminating the pod.

Observe whether the request:

Completes gracefully

or:

Gets terminated unexpectedly

Do not use an artificial endpoint in production. This is strictly for controlled testing.

Validate Background Services

If the .NET application uses:

BackgroundService

test shutdown behavior separately.

ASP.NET Core invokes StopAsync during graceful host shutdown and provides a cancellation token to allow background operations to stop. Microsoft documents a default shutdown timeout and recommends that remaining operations respond promptly when cancellation is requested.

A node upgrade is therefore also a test of:

Queue consumers
Schedulers
Background workers
Message processing

Protect Against Duplicate Processing

Suppose a background worker receives:

Message 123

and the pod is terminated during processing.

Your system should have an explicit delivery strategy:

At-most-once
At-least-once
Exactly-once semantics where actually supported

Do not assume Kubernetes termination automatically prevents duplicate processing.

For critical workloads, design application-level idempotency.

Upgrade One Node Pool at a Time

For production clusters with multiple node pools:

Pool A
Pool B
Pool C

do not upgrade everything simultaneously.

A safer operational sequence is:

Pool A
   ↓
Validate
   ↓
Pool B
   ↓
Validate
   ↓
Pool C

The exact sequence depends on the cluster architecture and managed-Kubernetes provider.

Maintain a Rollback Strategy

Before upgrading, define:

What happens if node upgrade fails?
What happens if pods cannot schedule?
What happens if ingress breaks?
What happens if the .NET service fails?
How will traffic be shifted?
How will nodes be replaced?

Do not assume "rollback" means simply changing:

1.37 → 1.36

Kubernetes version rollback procedures can have constraints depending on the upgrade stage and cluster management platform.

For node-level problems, replacing unhealthy nodes with known-good images may be safer than attempting an ad-hoc downgrade.

Kubernetes 1.36 to 1.37 Preflight Checklist

Use this checklist before production rollout:

AreaCheck
KubernetesCurrent patch release
Target1.37 release status
NodesAll Ready
cgroupscgroup v2 where required
RuntimeSupported and consistent
KubeletVersion compatibility
CNISupported configuration
CSISupported configuration
IngressSupported controller/version
APIsDeprecated/removed API audit
PDBDisruption behavior
ReplicasSufficient capacity
ProbesReadiness/liveness validated
ShutdownGraceful termination tested
ResourcesScheduling capacity verified
.NETRuntime/container compatibility
ObservabilityMetrics/logs/traces working
Backupetcd/data backups verified
RollbackOperational plan documented

Common Mistakes

Upgrading the Control Plane First and Ignoring Nodes

The entire cluster lifecycle needs to be planned.

Checking Only Kubernetes Version

A healthy control plane does not prove that every node is ready.

Ignoring cgroup Configuration

Old node images can become upgrade blockers.

Treating Readiness and Liveness as the Same Thing

They serve different purposes in ASP.NET Core and Kubernetes.

Using a Database Check for Liveness

A dependency outage can turn into application restart loops.

Running One Replica

Node maintenance can temporarily eliminate service capacity.

Ignoring PDB Configuration

Disruption policies can prevent or complicate node drains.

Forgetting Background Workers

A restarted pod can interrupt message processing.

Testing Only /health

Health checks do not validate the complete application path.

Assuming Ready Means Production Is Healthy

Check application-level telemetry after the upgrade.

Troubleshooting

Pod Stays Pending After Node Upgrade

Check:

kubectl describe pod <pod-name>

Look for:

Insufficient CPU
Insufficient memory
Taints
Affinity
Node selectors
PDB constraints

Node Becomes NotReady

Inspect:

kubectl describe node <node-name>

Then check:

journalctl -u kubelet

and:

systemctl status containerd

for containerd-based nodes.

.NET Pod Keeps Restarting

Check:

kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl logs <pod-name> --previous

Look for:

OOMKilled
Probe failures
Startup exceptions
Configuration errors
Port mismatch
Dependency failures

Readiness Probe Fails After Upgrade

Verify:

Application listening port
Service targetPort
Probe port
Health endpoint
Network policy
Startup duration

For .NET 8+ container images, remember that the default ASP.NET Core container port changed to 8080 unless explicitly configured otherwise.

Application Receives Traffic Before It Is Ready

Review the readiness probe.

ASP.NET Core supports separate readiness and liveness checks specifically so Kubernetes can avoid sending traffic to an application that is running but not yet ready.

Best Practices

  1. Treat Kubernetes 1.37 as an infrastructure change, not merely a version change.

  2. Upgrade one minor version at a time.

  3. Use the latest supported patch release before upgrading.

  4. Audit every worker node before the upgrade.

  5. Verify cgroup configuration.

  6. Verify container runtime compatibility.

  7. Keep kubelet and kubeadm versions within supported skew.

  8. Test node drains before production.

  9. Maintain sufficient replica capacity.

  10. Review PodDisruptionBudgets.

  11. Separate readiness and liveness checks.

  12. Test ASP.NET Core graceful shutdown.

  13. Test background worker shutdown.

  14. Validate database and message-processing behavior.

  15. Audit Kubernetes API deprecations.

  16. Test ingress and Gateway traffic.

  17. Test NetworkPolicies.

  18. Verify resource capacity for rescheduling.

  19. Monitor application-level SLOs during rollout.

  20. Use staged or canary node upgrades where possible.

Frequently Asked Questions

Is Kubernetes 1.37 released?

Not yet at the time of writing. The official Kubernetes release schedule currently targets August 26, 2026 for Kubernetes 1.37.0.

Can I skip Kubernetes 1.36 and upgrade directly to 1.37?

For kubeadm upgrades, skipping minor versions is unsupported. The official upgrade documentation recommends upgrading one minor version at a time.

Will my .NET application need code changes?

Not necessarily.

Many upgrade risks are operational rather than C#-level changes. However, applications with custom signal handling, fragile probes, single replicas, background workers, or strict runtime assumptions should be tested carefully.

Why are cgroups important?

Kubernetes and the container runtime use cgroups for resource management. Kubernetes has deprecated cgroup v1, and kubelet behavior requires particular attention on older nodes.

Should I upgrade containerd separately?

That depends on your Kubernetes distribution and supported runtime versions. Check the runtime requirements for the exact Kubernetes version and distribution you operate rather than assuming a runtime upgrade is automatically required.

What should my ASP.NET Core readiness probe check?

It should answer whether the application is ready to receive traffic.

For example:

Application initialized
Required configuration loaded
Critical dependencies available

The exact checks depend on the service.

Should liveness check the database?

Usually, avoid making liveness dependent on a database or other external dependency unless there is a specific architectural reason.

A temporary dependency outage should not automatically cause Kubernetes to restart every application instance.

How do I test whether a .NET service survives node upgrades?

Start with:

Pod restart
    ↓
Node drain
    ↓
Staged node upgrade
    ↓
Application telemetry

Verify request continuity, startup, readiness, graceful shutdown, background processing, and dependency connectivity.

What is the biggest upgrade risk?

There is no universal single risk.

For older self-managed clusters, node/runtime and cgroup compatibility can be critical. For .NET workloads, application lifecycle behavior—especially probes, shutdown, startup, and resource capacity—can determine whether a technically successful cluster upgrade becomes a successful application upgrade.

Conclusion

A Kubernetes minor upgrade is successful only when both the platform and its workloads remain healthy.

For a .NET service, the relevant upgrade path is:

Kubernetes 1.36
      ↓
Node/runtime validation
      ↓
Kubernetes 1.37 testing
      ↓
.NET lifecycle testing
      ↓
Node drain testing
      ↓
Staged rollout
      ↓
Application validation
      ↓
Production

The most important preparation is not changing the Kubernetes version in a configuration file.

It is identifying what your application assumes about its environment.

Check:

cgroups
container runtime
kubelet
resource capacity
probes
shutdown
startup
PDBs
replicas
ingress
network policies
background workers
API compatibility

Kubernetes 1.37 is currently scheduled for August 26, 2026, giving teams a useful pre-release window to test representative workloads before production adoption.

For .NET services, the upgrade should ultimately be evaluated at two levels:

Platform health
+
Application health

A cluster showing:

Nodes = Ready

is necessary, but it is not sufficient.

The real success criteria are:

Requests continue
Pods become Ready
Existing requests drain correctly
Background work behaves correctly
Dependencies remain reachable
No unexpected OOMs occur
Latency remains within SLO
Error rate remains acceptable

The key principle is:

Do not upgrade Kubernetes first and discover application compatibility afterward. Validate the infrastructure assumptions of your .NET services before the upgrade.

That approach turns Kubernetes 1.37 from a risky version change into a controlled infrastructure migration.