Kubernetes and OpenShift Upgrade Strategy
Complete upgrade strategy for Kubernetes and OpenShift clusters. Understand patch, minor, and major versions, upgrade paths.
π‘ Quick Answer: Kubernetes uses semantic versioning (1.x.y): patch (1.31.1β1.31.2) for bug/security fixes, minor (1.31β1.32) for new features, and major (theoretical 1.xβ2.x). OpenShift follows Kubernetes releases (OCP 4.16 β K8s 1.29). Always upgrade sequentially β never skip minor versions. Pre-flight: check API deprecations, drain nodes, backup etcd, verify PodDisruptionBudgets.
The Problem
Clusters fall behind on versions due to upgrade fear β but running unsupported versions is worse. Kubernetes drops support for old versions after ~14 months. OpenShift EUS (Extended Update Support) extends to 18 months but only for even-numbered releases. You need a clear strategy for when and how to upgrade.
flowchart LR
subgraph KUBERNETES["Kubernetes Versions"]
K131["1.31.x"] -->|"Minor"| K132["1.32.x"]
K132 -->|"Minor"| K133["1.33.x"]
K131 -->|"Patch"| K131P["1.31.1 β 1.31.2"]
end
subgraph OPENSHIFT["OpenShift Versions"]
O416["4.16 (K8s 1.29)<br/>EUS"] -->|"Minor"| O417["4.17 (K8s 1.30)"]
O417 -->|"Minor"| O418["4.18 (K8s 1.31)<br/>EUS"]
O416 -->|"EUS-to-EUS"| O418
O416 -->|"Patch"| O416P["4.16.10 β 4.16.11"]
endVersion Numbering
Kubernetes
| Component | Example | Frequency | Risk Level |
|---|---|---|---|
| Patch (x.y.Z) | 1.31.1 β 1.31.2 | Every 1-2 weeks | π’ Low β bug/security fixes only |
| Minor (x.Y.0) | 1.31 β 1.32 | Every 4 months | π‘ Medium β new features, API deprecations |
| Major (X.0.0) | 1.x β 2.x | Never happened yet | π΄ High β breaking changes |
OpenShift
| Component | Example | Frequency | Risk Level |
|---|---|---|---|
| Patch (4.x.Z) | 4.16.10 β 4.16.11 | Every 2-3 weeks | π’ Low β errata/bug fixes |
| Minor (4.X.0) | 4.16 β 4.17 | Every ~4 months | π‘ Medium β new K8s version, operator updates |
| EUS-to-EUS | 4.16 β 4.18 | Skips odd releases | π‘ Medium β controlled skip |
Upgrade Paths
Kubernetes: Sequential Minor Only
# β
Valid upgrade paths:
# 1.30.x β 1.31.0 β 1.31.x β 1.32.0 β 1.32.x
# (always upgrade to latest patch of current, then next minor)
# β Invalid β cannot skip minor versions:
# 1.30.x β 1.32.x (SKIP 1.31 β NOT ALLOWED)
# β
Patch upgrades within same minor:
# 1.31.0 β 1.31.5 (can skip patches)OpenShift: Channel-Based
# OpenShift uses update channels:
# stable-4.16 β production-ready patches for 4.16
# fast-4.17 β early access to 4.17.x
# stable-4.17 β production-ready patches for 4.17
# eus-4.16 β Extended Update Support for 4.16
# eus-4.18 β Extended Update Support for 4.18
# Check current channel
oc get clusterversion -o jsonpath='{.items[0].spec.channel}'
# Set channel for upgrade
oc adm upgrade channel stable-4.17Pre-Flight Checks (Both Platforms)
#!/bin/bash
# pre-flight-check.sh β run before ANY upgrade
echo "=== 1. Current Version ==="
kubectl version --short 2>/dev/null || oc version
echo -e "\n=== 2. Node Status ==="
kubectl get nodes
# All nodes must be Ready
echo -e "\n=== 3. Component Health ==="
kubectl get cs 2>/dev/null # K8s component status
oc get co 2>/dev/null | grep -v "True.*False.*False" # OCP: unhealthy operators
echo -e "\n=== 4. API Deprecations ==="
# Check for deprecated APIs in use
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis
# Or use kubent (kube-no-trouble):
# kubent
echo -e "\n=== 5. PodDisruptionBudgets ==="
kubectl get pdb -A
# PDBs with maxUnavailable=0 will block node drains!
echo -e "\n=== 6. etcd Health ==="
# K8s:
kubectl -n kube-system exec -it etcd-master-0 -- \
etcdctl endpoint health --cluster
# OCP:
oc get etcd -o jsonpath='{.items[0].status.conditions[?(@.type=="EtcdMembersAvailable")].status}'
echo -e "\n=== 7. Backup etcd ==="
# CRITICAL: Always backup before upgrade
# K8s:
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-pre-upgrade.db
# OCP:
oc debug node/master-0 -- chroot /host /usr/local/bin/cluster-backup.sh /home/core/backup
echo -e "\n=== 8. Storage Health ==="
kubectl get pv | grep -v Bound
# All PVs should be Bound
echo -e "\n=== 9. Pending Pods ==="
kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded | head -20
echo -e "\n=== 10. Resource Headroom ==="
kubectl top nodes
# Need headroom for drained workloads during rolling upgradeKey Takeaways
- Patch upgrades are low-risk β apply them regularly (weekly/biweekly)
- Minor upgrades require planning β check API deprecations, test in staging
- Never skip minor versions β always upgrade sequentially
- OpenShift EUS-to-EUS is the safest path for production β 4.16 β 4.18
- Always backup etcd before any upgrade β your recovery lifeline
- PDBs with maxUnavailable=0 block upgrades β audit before starting
- Drain nodes gracefully β respect PDBs and pod termination grace periods

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
