Introduction
Upgrading Kubernetes is not finished when the cluster reports that every node is running the new version.
The more important question comes afterward:
Are the applications, networking, storage, workloads, and deployment processes still working as expected?
This matters even more for .NET applications running in Kubernetes. A cluster upgrade can complete successfully while an application later exposes problems involving readiness probes, service discovery, ingress, configuration, persistent storage, or deployment behavior.
Kubernetes 1.34 provides a useful opportunity to build a repeatable post-upgrade validation process rather than relying on a few manual checks.
The goal is not to prove that the Kubernetes upgrade itself succeeded.
The goal is to verify that the application platform remains healthy after the upgrade.
What Is Post-Maintenance Validation?
Post-maintenance validation is a collection of automated checks performed after infrastructure maintenance.
For a Kubernetes cluster hosting .NET applications, the workflow can look like this:
Kubernetes Upgrade
|
v
Cluster Health
|
v
Node Health
|
v
Workload Health
|
v
Networking
|
v
Application Tests
|
v
Deployment Validation
|
v
Production ReadyThis is different from checking only:
kubectl get nodesA healthy node does not guarantee that the application running on it is healthy.
Why .NET Applications Need Application-Level Checks
Consider an ASP.NET Core application deployed to Kubernetes:
Internet
|
v
Ingress
|
v
Kubernetes Service
|
v
ASP.NET Core Pods
|
v
DatabaseAfter an infrastructure upgrade, every layer can appear healthy independently while the complete request path is broken.
For example:
Pod -> Running
Service -> Exists
Ingress -> Exists
But:
Client -> API = FailureApplication-level validation catches this type of problem.
Build a Validation Suite Before the Upgrade
The best time to create the validation suite is before maintenance begins.
A basic repository structure could be:
k8s-validation/
cluster/
workloads/
networking/
storage/
application/
deployment/Each directory can contain checks for a different part of the platform.
For example:
cluster/
nodes.sh
workloads/
pods.sh
deployments.sh
networking/
services.sh
ingress.sh
application/
health-check.sh
smoke-test.shThe exact structure is not important.
What matters is that the checks are repeatable.
Step 1: Validate Cluster Nodes
Start with:
kubectl get nodesThen inspect node details:
kubectl get nodes -o wideA basic validation script can check whether all expected nodes are ready.
For example:
kubectl get nodes --no-headers |
awk '$2 != "Ready" {print "Node not ready:", $1; failed=1}
END {exit failed}'The script exits with a non-zero status if a node is not ready.
That makes it suitable for automation.
Step 2: Check System Workloads
Kubernetes system components should also be checked.
For example:
kubectl get pods -n kube-systemLook for:
Pods stuck in
PendingPods repeatedly restarting
Failed containers
Unexpectedly missing components
A useful command is:
kubectl get pods -AThis provides a broader view of workload state across namespaces.
Do not assume that a Running pod means the application inside it is functioning correctly.
Step 3: Check Deployment Status
For an ASP.NET Core application:
kubectl get deployments -n productionThen inspect the deployment:
kubectl describe deployment my-api -n productionThe important values include:
Desired replicas
Available replicas
Updated replicas
Ready replicasA deployment should have the expected number of available replicas.
Step 4: Check Pods
Inspect the application's pods:
kubectl get pods -n production -l app=my-apiA healthy result might look conceptually like:
NAME READY STATUS
my-api-7f8d9f6d7b-a1b2c 1/1 Running
my-api-7f8d9f6d7b-d3e4f 1/1 Running
my-api-7f8d9f6d7b-g5h6j 1/1 RunningThe important part is not simply Running.
Check the READY column and restart counts as well.
For additional information:
kubectl get pods -n production -o wideStep 5: Check Container Restarts
A pod can be running while a container has restarted repeatedly.
Check:
kubectl get pods -n productionThen inspect a suspicious pod:
kubectl describe pod <pod-name> -n productionLook at the container state and restart count.
A post-upgrade validation suite should flag unexpected increases in restarts.
Step 6: Validate ASP.NET Core Health Checks
Kubernetes infrastructure checks are not enough.
ASP.NET Core applications should expose appropriate health endpoints.
For example:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/health");
app.Run();The validation suite can then test:
curl --fail http://api.example.local/healthA successful HTTP response is useful, but the health endpoint should represent meaningful application health rather than merely proving that the process is alive.
Liveness vs Readiness
ASP.NET Core applications commonly use different health concepts.
Liveness
Liveness answers:
Is the application process alive?
A liveness probe can help Kubernetes determine whether a container needs to be restarted.
Readiness
Readiness answers:
Can this application currently receive traffic?
A readiness check is especially important after maintenance.
For example, an application may be running but temporarily unable to connect to a required dependency.
That should not necessarily mean Kubernetes should send it production traffic.
Example Kubernetes Probes
A deployment might use:
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5The actual values should be based on the application's startup and dependency behavior.
Do not copy probe timings blindly into production.
Step 7: Test Service Discovery
Check Kubernetes services:
kubectl get services -n productionThen validate that the expected service exists and exposes the expected ports.
For example:
apiVersion: v1
kind: Service
metadata:
name: my-api
spec:
selector:
app: my-api
ports:
- port: 80
targetPort: 8080A post-maintenance test should verify that the service still routes traffic to the intended pods.
Step 8: Validate Ingress
If the .NET application is exposed through an ingress controller, test the complete path.
Client
|
v
Ingress
|
v
Service
|
v
Pod
|
v
ASP.NET CoreA basic smoke test could be:
curl --fail https://api.example.com/healthThen test an actual API endpoint:
curl --fail https://api.example.com/api/productsThe health endpoint proves that the application is reachable.
The API test provides stronger evidence that routing and application behavior are working.
Step 9: Test Database Connectivity
A .NET API may be healthy while database connectivity is broken.
For example:
API
|
X
DatabaseThe application may still answer a basic liveness request.
Therefore, the validation suite should include a controlled endpoint or application-level health check that verifies the required database dependency.
For example:
builder.Services.AddHealthChecks()
.AddSqlServer(
builder.Configuration.GetConnectionString("Default"));The exact health-check implementation depends on the database provider.
Do not expose sensitive database details through the public response.
Step 10: Test External Dependencies
The same approach applies to important external services.
Examples include:
Redis
Message brokers
Object storage
Internal APIs
Authentication services
A useful validation flow is:
API
|
+--> Database
|
+--> Cache
|
+--> Message Queue
|
+--> External APIOnly test dependencies that are genuinely required for the application's production path.
Otherwise, a temporary non-critical service outage could incorrectly mark the entire application as unavailable.
Step 11: Validate Configuration
Kubernetes configuration can come from:
ConfigMaps
Secrets
Environment variables
Mounted files
Check that expected configuration objects exist:
kubectl get configmaps -n production
kubectl get secrets -n productionDo not print secret values as part of the validation output.
The goal is to confirm that required objects exist and that the application starts successfully with them.
Join the conversation! Your thoughts help the community grow.