2026年6月23日

2026年6月23日

Kubernetesのクラスターアップグレード手順|事前確認・kubeadmでの更新・ノードの入れ替え・マネージドサービスの場合

Kubernetesのクラスターは、マイナーバージョンを1つずつ、コントロールプレーン、アドオン、ノードの順に上げていきます。手順そのものは短いのですが、止まる原因の多くは事前確認の不足です。削除されたAPIを使っているマニフェスト、ノードを空けられないPod、取り忘れたetcdのバックアップが典型です。この記事では、アップグレード前に確認すること、kubeadmで構築したクラスターでの手順、ノードを1台ずつ入れ替える方法、EKSなどのマネージドサービスでの流れを説明します。

Kubernetesはおおむね年に3回マイナーバージョンが出て、それぞれのサポート期間は約14か月です(2026年10月現在)。1年ほど放置するとサポート切れが近づくため、定期的な作業として計画しておくのが現実的です。

アップグレード前に確認すること

1. 上げる先のバージョンと順番

コントロールプレーンは、マイナーバージョンを飛ばして上げられません。1.31から1.33にしたいなら、1.32を経由します。パッチバージョン(1.32.3から1.32.8など)は飛ばしてかまいません。

あわせて、構成要素どうしのバージョンの差(バージョンスキュー)の決まりを確認します。

  • kubelet は kube-apiserver より新しくしてはいけない。古い側には一定の範囲(現在の方針では3マイナーバージョンまで)の差が許される。
  • kubectl は kube-apiserver との差が前後1マイナーバージョン以内。

この決まりがあるため、先にコントロールプレーン、後からノードという順番になります。差の許容範囲は過去に変わったことがあるので、上げる先の版の「Version Skew Policy」のページで確認してください。

2. 削除されるAPIを使っていないか

マイナーバージョンが上がると、非推奨だったAPIの版が削除されることがあります。削除されたAPIの版で書かれたマニフェストやHelmチャートは、アップグレード後に apply できなくなります。

確認には、公式の「Deprecated API Migration Guide」で上げる先の版で削除されるAPIを調べたうえで、手元のマニフェストを検査するツールを使うのが効率的です。pluto や kubent(kube-no-trouble)のようなツールは、マニフェストやクラスター内のリソース、Helmのリリースから古いAPIの使用を探してくれます。

# kube-apiserver が記録している「非推奨APIへのリクエスト」を確認
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis

このメトリクスに出てくるものは、クラスター内の何かが実際に古いAPIを呼んでいる証拠です。CI/CDやオペレーター、監視ツールなど、マニフェストのリポジトリ以外から呼ばれていることもあります。

3. ノードを空けられるか

ノードを更新するときは、そのノードのPodを別のノードに移します(drain)。このとき、次のようなPodがあると止まったりサービスが途切れたりします。

  • レプリカが1つしかないDeployment:移動中はサービスが止まる。
  • PodDisruptionBudget(PDB)が厳しすぎる:minAvailable がレプリカ数と同じだと、1つも退避できず drain が進まない。
  • ノードのローカルディスク(emptyDir)にデータを持つPod:退避すると中身は消える。

重要なアプリはレプリカを2つ以上にし、PDBで「同時に止めてよい数」を決めておきます。

4. etcdのバックアップ

コントロールプレーンのダウングレードは基本的にできません。問題が起きたときの最後の手段はetcdのスナップショットからの復元なので、作業直前に取得しておきます。kubeadmで構築したクラスターなら、コントロールプレーンのノードで次のように実行します(証明書のパスはkubeadmの既定のもの)。

sudo ETCDCTL_API=3 etcdctl \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save /var/backups/etcd-$(date +%Y%m%d).db

スナップショットは別のサーバーにもコピーしておきます。あわせて、アプリのデータ(永続ボリュームやデータベース)も別途バックアップします。etcdにはKubernetesのリソースの定義しか入っていません。

5. 検証環境で先に試す

同じ構成の検証用クラスターがあれば、そちらで先に上げてアプリの動作を確認します。アドオン(CNI、Ingressコントローラー、cert-managerなど)が新しい版に対応しているかも、それぞれのリリースノートで確認しておきます。

kubeadmで構築したクラスターの手順

ここではUbuntu/Debianで、パッケージを pkgs.k8s.io のリポジトリから入れている前提で説明します。このリポジトリはマイナーバージョンごとに分かれているため、上げる先の版のリポジトリにURLを書き換えてから更新します。旧来の apt.kubernetes.io のリポジトリは使えなくなっているので、古い手順書のコマンドはそのまま使わないでください。

コントロールプレーン(1台目)

# リポジトリの版を書き換えたあと
sudo apt-get update
sudo apt-mark unhold kubeadm
sudo apt-get install -y kubeadm='1.33.x-*'   # x は利用可能なパッチ番号
sudo apt-mark hold kubeadm

kubeadm version
sudo kubeadm upgrade plan
sudo kubeadm upgrade apply v1.33.x

kubeadm upgrade plan は、今の版から上げられる版と、各コンポーネントがどう変わるかを表示します。ここでエラーや警告が出たら、解決してから apply に進みます。apply は kube-apiserver などの静的Podの更新に加えて、CoreDNS と kube-proxy も新しい版に入れ替えます。

2台目以降のコントロールプレーンでは、apply の代わりに sudo kubeadm upgrade node を実行します。

各ノードの kubelet と kubectl

コントロールプレーンのノードも含め、1台ずつ次の流れで進めます。

# 作業端末から:Podを退避してスケジュール対象から外す
kubectl drain <ノード名> --ignore-daemonsets --delete-emptydir-data

# 対象ノードで:
#(ワーカーノードはここで kubeadm を更新し、sudo kubeadm upgrade node を実行)
sudo apt-mark unhold kubelet kubectl
sudo apt-get install -y kubelet='1.33.x-*' kubectl='1.33.x-*'
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet

# 作業端末から:スケジュール対象に戻す
kubectl uncordon <ノード名>
kubectl get nodes

--delete-emptydir-data を付けると、emptyDir の中身は消えます。消えて困るデータがあるPodがないか、事前に確認してから付けてください。drain が終わらないときは、kubectl get pdb -A で退避を止めているPDBを探します。1台終わって Ready に戻り、アプリが正常なことを確認してから次のノードに進みます。

ノードを入れ替える方式

既存のノードを更新する代わりに、新しい版のノードを追加して古いノードを順に drain・削除する方法もあります。クラウド上のクラスターではこちらが一般的です。OSやコンテナランタイムも新しいイメージにまとめて切り替えられ、失敗したら新しいノードを消して古いノードに戻せます。

さらに慎重に進めるなら、新しい版のクラスターを丸ごと別に作り、アプリを移してからDNSやロードバランサーで切り替える方法(ブルーグリーン)もあります。手間はかかりますが、コントロールプレーンの問題が起きても元のクラスターに戻れます。

マネージドサービスの場合

EKS、GKE、AKSでは、コントロールプレーンの更新はコマンド1つか画面の操作で済みます。ただし、事前確認の考え方とノードを後から上げる順番は同じです。EKSを eksctl で管理している場合の流れは次のとおりです。

eksctl upgrade cluster --name wp-cluster --version 1.33 --approve
eksctl upgrade nodegroup --cluster wp-cluster --name ng-general --kubernetes-version 1.33

コントロールプレーンの後に、vpc-cni や coredns などのアドオンも新しい版に対応したものへ更新します。EKSにはアップグレード前に非推奨APIの使用などを知らせる機能もあるので、管理画面やCLIで確認できます。GKEはリリースチャンネルによって自動で更新される場合があり、AKSは az aks upgrade で更新します。各サービスの機能や既定の動きは変わることがあるため、作業のたびに公式ドキュメントを確認してください。

アップグレード後の確認

  • kubectl get nodes で全ノードが Ready、版が想定どおりか。
  • kubectl get pods -A で CrashLoopBackOff や Pending のPodがないか。
  • Ingress経由でアプリ(WordPressならトップページと管理画面)が開けるか。
  • 監視やログ収集のエージェントがデータを送り続けているか。

問題が出たPodは kubectl describe pod の Events と kubectl logs --previous で原因を探します。

まとめ

  • マイナーバージョンは1つずつ、コントロールプレーン、アドオン、ノードの順に上げる。kubelet を kube-apiserver より新しくしない。
  • 削除されるAPIはガイドとツールで事前に探し、apiserver_requested_deprecated_apis で実際の呼び出し元も確認する。
  • PDBとレプリカ数を見直し、drain でサービスが止まらないようにする。
  • 作業直前にetcdのスナップショットとアプリのデータをバックアップする。ダウングレードは基本的にできない。
  • kubeadmでは pkgs.k8s.io の版ごとのリポジトリを切り替えてから kubeadm upgrade plan / apply を実行する。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲