πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Deployments intermediate ⏱ 30 minutes K8s 1.28+

Kubernetes and OpenShift Upgrade Strategy

Complete upgrade strategy for Kubernetes and OpenShift clusters. Understand patch, minor, and major versions, upgrade paths.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ 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"]
    end

Version Numbering

Kubernetes

ComponentExampleFrequencyRisk Level
Patch (x.y.Z)1.31.1 β†’ 1.31.2Every 1-2 weeks🟒 Low β€” bug/security fixes only
Minor (x.Y.0)1.31 β†’ 1.32Every 4 months🟑 Medium β€” new features, API deprecations
Major (X.0.0)1.x β†’ 2.xNever happened yetπŸ”΄ High β€” breaking changes

OpenShift

ComponentExampleFrequencyRisk Level
Patch (4.x.Z)4.16.10 β†’ 4.16.11Every 2-3 weeks🟒 Low β€” errata/bug fixes
Minor (4.X.0)4.16 β†’ 4.17Every ~4 months🟑 Medium β€” new K8s version, operator updates
EUS-to-EUS4.16 β†’ 4.18Skips 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.17

Pre-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 upgrade

Key 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
#upgrade #openshift #kubernetes #cluster-management #lifecycle
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens