Kubeadm upgrade nodes
Jump to navigation
Jump to search
New
- https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/
- Drain node
- On primary update_kubeadm_version then kubeadm_upgrade
- uncordon node
- update_kubeadm_version on all other nodes starting with controllers first
Alternate version WIP
#!/usr/bin/env bash set -euo pipefail # ====== Config via ENV ====== K8S_MINOR="${K8S_MINOR:-1.32}" # e.g. 1.31 or 1.32 DRAIN="${DRAIN:-false}" # true to drain before upgrade (default: false) ALLOW_FORCE="${ALLOW_FORCE:-false}" # true to allow drain of bare pods DRAIN_TIMEOUT="${DRAIN_TIMEOUT:-15m}" KERNEL_UPGRADE="${KERNEL_UPGRADE:-false}" # true to apt upgrade kernel/system KERNEL_REBOOT="${KERNEL_REBOOT:-auto}" # auto|true|false # auto = reboot only if /var/run/reboot-required exists after upgrade PAUSE_IMAGE="${PAUSE_IMAGE:-registry.k8s.io/pause:3.10}" BUMP_PAUSE_IMAGE="${DRAIN:-false}" # true to drain before upgrade (default: false) # ====== Helpers ====== node_name() { hostname -s; } wait_apiserver_ready() { local timeout="${1:-300}"; local end=$(( $(date +%s) + timeout )) echo "[health] Waiting for apiserver readyz..." until kubectl get --raw='/readyz' 2>/dev/null | grep -q '^ok$'; do [[ $(date +%s) -ge $end ]] && { echo "[health] apiserver not ready"; return 1; } sleep 5 done } retry() { # retry <attempts> <sleep_initial> <cmd...> local attempts="$1"; shift; local sleep_s="$1"; shift; local i=1 while :; do "$@" && return 0 [[ $i -ge $attempts ]] && { echo "Retry failed: $*"; return 1; } echo "Retry $i/$attempts -> sleeping ${sleep_s}s" sleep "$sleep_s"; sleep_s=$(( sleep_s * 2 )); i=$(( i + 1 )) done } drain_node() { local n; n="$(node_name)" if [[ "$DRAIN" != "true" ]]; then echo "[drain] Skipping drain for $n (DRAIN=false)" return 0 fi echo "[drain] Draining $n" local args=(--ignore-daemonsets --delete-emptydir-data --grace-period=60 "--timeout=${DRAIN_TIMEOUT}") [[ "$ALLOW_FORCE" == "true" ]] && args+=(--force) kubectl drain "$n" "${args[@]}" } uncordon_node() { local n; n="$(node_name)" if [[ "$DRAIN" != "true" ]]; then echo "[drain] Skipping uncordon for $n (DRAIN=false)" return 0 fi echo "[uncordon] Uncordoning $n" kubectl uncordon "$n" || true } bump_pause_image() { if [[ "$BUMP_PAUSE_IMAGE" != "true" ]]; then echo "[bump] Skipping bump_pause_iamge (BUMP_PAUSE_IMAGE=false)" return 0 fi echo "[pause] Setting sandbox image to ${PAUSE_IMAGE}" if command -v containerd >/dev/null 2>&1; then local cfg=/etc/containerd/config.toml sudo mkdir -p "$(dirname "$cfg")" [[ -f "$cfg" ]] || sudo containerd config default | sudo tee "$cfg" >/dev/null sudo sed -i "s|^\(\s*sandbox_image\s*=\s*\).*$|\1\"${PAUSE_IMAGE}\"|" "$cfg" sudo systemctl restart containerd elif command -v crio >/dev/null 2>&1; then local cfg=/etc/crio/crio.conf sudo mkdir -p "$(dirname "$cfg")" sudo sed -i "s|^\(pause_image\s*=\s*\).*$|\1\"${PAUSE_IMAGE}\"|" "$cfg" || true sudo systemctl restart crio else echo "[pause] No containerd or CRI-O found; skipping pause image bump" >&2 fi } add_k8s_repo_and_update_pkgs() { echo "[k8s] Configuring repo for ${K8S_MINOR} and installing kubeadm/kubelet/kubectl" sudo mkdir -p /etc/apt/keyrings local keyr=/etc/apt/keyrings/kubernetes-apt-keyring.gpg if [[ ! -f "$keyr" ]]; then curl -fsSL "https://pkgs.k8s.io/core:/stable:/v${K8S_MINOR}/deb/Release.key" | sudo gpg --dearmor -o "$keyr" fi echo "deb [signed-by=${keyr}] https://pkgs.k8s.io/core:/stable:/v${K8S_MINOR}/deb/ /" | \ sudo tee /etc/apt/sources.list.d/kubernetes.list >/dev/null sudo apt-get update sudo apt-mark unhold kubeadm kubectl kubelet || true sudo apt-get install -y "kubeadm=${K8S_MINOR}."* "kubelet=${K8S_MINOR}."* "kubectl=${K8S_MINOR}."* sudo apt-mark hold kubeadm kubectl kubelet # Optional: pre-pull control-plane images for this version (harmless on workers) # ver="$(kubeadm version -o short)"; sudo kubeadm config images pull --kubernetes-version "$ver" || true } apply_kubeadm_node_upgrade() { echo "[k8s] Running 'kubeadm upgrade node'" sudo kubeadm upgrade node # wait_apiserver_ready 600 # echo "[k8s] Running 'kubeadm upgrade node' with retries" # retry 6 2 sudo kubeadm upgrade node retry 3 300 sudo kubeadm upgrade node # retries 3 times every 5 minutes as kubectl is not configured for node access echo "[k8s] Restarting kubelet" sudo systemctl daemon-reload sudo systemctl restart kubelet } kernel_and_system_upgrade() { if [[ "$KERNEL_UPGRADE" != "true" ]]; then echo "[kernel] Skipping kernel/system upgrade (KERNEL_UPGRADE=false)" return 0 fi echo "[kernel] Upgrading kernel & system packages" # Generic + safe: full dist-upgrade (includes kernel/hwe if enabled) sudo DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade # If you want to force the meta-packages explicitly, uncomment: # sudo apt-get install -y linux-image-generic linux-headers-generic || true # On HWE stacks (Ubuntu LTS), you might prefer: # sudo apt-get install -y linux-generic-hwe-24.04 || true if [[ "$KERNEL_REBOOT" == "true" ]]; then echo "[kernel] Reboot requested (KERNEL_REBOOT=true)" sudo reboot elif [[ "$KERNEL_REBOOT" == "auto" ]]; then if [[ -f /var/run/reboot-required ]]; then echo "[kernel] Reboot required and auto-approved (KERNEL_REBOOT=auto)" sudo reboot else echo "[kernel] No reboot required (KERNEL_REBOOT=auto)" fi else echo "[kernel] Reboot suppressed (KERNEL_REBOOT=false)" fi } print_versions() { echo "[versions]" echo -n " kubeadm: "; kubeadm version -o short echo -n " kubelet: "; kubelet --version echo -n " kubectl (client): "; kubectl version --client } # ====== Main ====== NODE="$(node_name)" echo "[start] Worker upgrade on ${NODE} (K8S_MINOR=${K8S_MINOR}, DRAIN=${DRAIN}, KERNEL_UPGRADE=${KERNEL_UPGRADE}, KERNEL_REBOOT=${KERNEL_REBOOT})" drain_node add_k8s_repo_and_update_pkgs bump_pause_image apply_kubeadm_node_upgrade uncordon_node print_versions kernel_and_system_upgrade # may reboot here if configured echo "[done] Node ${NODE} upgrade complete"
Almost but doesn't do the kubeadm upgrade
update.sh
#!/bin/bash set -eu update_kubeadm_version(){ k8s_minor_version=1.31 k8s_keyring_file="/etc/apt/keyrings/kubernetes-apt-keyring.gpg" if [ ! -f "${k8s_keyring_file}" ]; then curl -fsSL https://pkgs.k8s.io/core:/stable:/v${k8s_minor_version}/deb/Release.key 2>/dev/null | sudo gpg --dearmor -o ${k8s_keyring_file} fi echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v${k8s_minor_version}/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-mark unhold kubeadm kubectl kubelet && \ sudo apt-get install -y kubelet=${k8s_minor_version}.* kubeadm=${k8s_minor_version}.* kubectl=${k8s_minor_version}.* && \ sudo apt-mark hold kubeadm kubectl kubelet && \ sudo systemctl restart kubelet sudo kubeadm upgrade node sudo apt-get -y dist-upgrade kubeadm version -o short echo "Reboot in 10 seconds"; sleep 10 sudo reboot } kubeadm_upgrade_primary_controller(){ k8s_patch_version=$(kubeadm version -o short) echo "Updating to version ${k8s_patch_version} in 10 seconds."; sleep 10 sudo kubeadm upgrade plan sudo killall -s SIGTERM kube-apiserver # trigger a graceful kube-apiserver shutdown sleep 20 # wait a little bit to permit completing in-flight requests kubeadm upgrade apply -y ${k8s_patch_version} }
Old
#!/bin/bash # Update the package lists sudo apt update # Install the Kubernetes packages, specifying the desired version sudo apt install -y kubelet=1.31.* kubeadm=1.31.* kubectl=1.31.* # Restart kubelet service sudo systemctl restart kubelet apt-get upgrade # Verify node status kubectl get nodes -o wide # Optional: Drain the node before upgrading to avoid disruptions # kubectl drain <node-name> --ignore-daemon-sets --force --delete-local-data # Optional: Upgrade other node components (e.g., containerd, Docker) # - Follow the specific upgrade instructions for your container runtime # Note: # - This script assumes you have the Kubernetes repository configured in your system. # - This script uses wildcards to install the latest patch version within the 1.31 series. # - This script performs a rolling update. Consider draining nodes for zero-downtime upgrades. # - Always back up critical data before performing any upgrades. # - Refer to the official Kubernetes documentation for the most up-to-date instructions.