[GKE] Kubernetes を 1.18から1.22までアップグレードした記録

保有する一部のGKEクラスタが古いバージョンで動いていたので、一気にアップグレードしていくことにしました。一気にとは言っても、 Kubernetes v1.22 で非互換のAPI あったことから、何日かかけながら実施しています。

目指すところ

  • Kubernetes 環境を 1.18 から 1.22 までアップグレードしたい
  • 非互換APIの対応をしたい
  • 古くなっているリソースもアップグレードしたい
    • CertManager
    • Ingress Nginx
  • ダウンタイムの制限がそこまで厳しくないサービス環境であるため、若干のダウンタイムは許容できる
    • そのため24時間365日のサービス提供が前提となる環境ではもう少し丁寧に考える必要があります
    • 一方で、Pod の AntiAffinity や Probe などの基本的な可用性考慮をしていたため、結果的にはダウンタイムが発生せずに作業が完了しました

非互換APIの警告

GKEでは、以下の通り非推奨APIの呼び出しを分析してレポートしてくれる機能があったため、状態の把握がとてもやりやすかったです。クラスタやリソースをアップグレードしながら、非推奨APIの呼び出しが少しずつ減っていくことを確認しながら作業を勧めました。

GKE 非互換APIの警告

GKEアップグレードの注意点

この手の作業はやる気がある時に一気に終わらせてしまいたい気持ちになりますが、様々な構成要素のアップグレードが行われるため、いざ問題が起きた時に何が原因で不具合が発生したのかわからなくなってしまいます。そのため、できるだけ分解しながら少しずつ実施していくのが望ましいです。

コントロールプレーン(マスター)のアップグレード

  • GKEのドキュメントにある通り、リージョンクラスタ+複数ノードの構成をとり、適切なKubernetesのマニフェストを利用することで、サービスに影響を与えずにアップグレードをGKEにまかせる運用をとることができます。
  • 手動で GKE のマスターをアップグレードしたい場合、以下のコマンドでアップグレードすることができます。
# サポート可能なバージョンを取得(東京リージョンを指定した例)
$ gcloud container get-server-config --region=asia-northeast1
$ gcloud container clusters upgrade [CLUSTER_NAME] --master --cluster-version [CLUSTER_VERSION]

ノードのアップグレード

手動アップグレード戦略3つ

  • 現在のノードプールをアップグレード
  • 新しいバージョンのノードプールを作成し、ワークロードを移行
    • 新しいバージョンのノードプールを追加し、ワークロードを移行する方法。新しいバージョンのノードにワークロードを徐々に移行していく場合や、サービス全体のキャパシティを落とさずにアップグレードを実施したい場合に選択する
    • ワークロードを他のマシンタイプに移行する | Kubernetes Engine | Google Cloud
      1. 既存のノードプールをスケジュール不可に設定
      2. 既存のノードプールで実行されているワークロードをドレイン
      3. 既存のノードプールを削除
  • クラスタを再作成
    • クラスタの設定変更など、ノードのアップグレード以外の用途も含めて、クラスタ自体を再作成したい場合
    • GKE の手前にトラフィックを分散するコンポーネントが必要となる

Cert Manager のアップグレード

GKEのサービスとは異なりますが Kubernetes のバージョンアップにあたり、Let’s Encrypt によるSSL証明書を自動生成している場合、Cert Manager を利用しているケースが多いでしょう。この Cert Manager も放っておくとバージョンが古いままです。

Cert Manager 1.7 からは完全に削除されるため、Kubernetes との互換性を丁寧に見ながら1個ずつ確認していくべきでしょう。

Migrating Deprecated API Resources

The following cert-manager APIs were deprecated in cert-manager v1.4:

  • cert-manager.io/v1alpha2
  • cert-manager.io/v1alpha3
  • cert-manager.io/v1beta1
  • acme.cert-manager.io/v1alpha2
  • acme.cert-manager.io/v1alpha3
  • acme.cert-manager.io/v1beta1

These APIs are no longer served in cert-manager 1.6 and are fully removed in cert-manager 1.7. If you have a cert-manager installation that is using or has previously used these deprecated APIs you might need to upgrade your cert-manager custom resources and CRDs. This should be done before upgrading to cert-manager 1.6 or later.

Cert Manager のアップグレードは、互換性情報の整理だけでも膨大なので別の記事に整理します。

Ingress のアップグレード

Ingress は Kubernetes での L7 ロードバランサーとしての概念(リソース)ですが、Ingress Controller としての実装は多数ありますね。そんななか、代表的なもので紛らわしいのが Ingress Nginx と Nginx Ingress です。後者の Nginx Ingress は NGINX, Inc がホストしています。有償サポートがあるので、自組織での運営に自信のない企業で利用するときには Nginx Ingres を利用するのも一案でしょう。

一般的 Ingress の文脈で語られるときには、前者の kubernetes/ingress-nginx を指すことが多い印象です。

GitHub - kubernetes/ingress-nginx: Ingress-NGINX Controller for Kubernetes

GitHub - kubernetes/ingress-nginx: Ingress-NGINX Controller for Kubernetes

Ingress-NGINX Controller for Kubernetes. Contribute to kubernetes/ingress-nginx development by creating an account on GitHub.

GitHub - nginxinc/kubernetes-ingress: NGINX and  NGINX Plus Ingress Controllers for Kubernetes

GitHub - nginxinc/kubernetes-ingress: NGINX and NGINX Plus Ingress Controllers for Kubernetes

NGINX and NGINX Plus Ingress Controllers for Kubernetes - nginxinc/kubernetes-ingress

なお、GKE環境においては Ingress GCE (GCE L7 load balancer controller) も存在します。AWS の ALB (Application Load Balancer) のように、LBで証明書を利用してSSL終端する形式です。こちらで目的が達成できる場合は Ingress Nginx のアップグレードといった余計な構成要素の管理が不要になるので効率的ですが、今回のケースでは Let’s Encrypt (Cert Manager) 証明書の自動更新をしている都合で Nginx の方が都合が良かったため採用していません(Ingress GCE で同じことをしようとすると DNS によるドメイン検証をすればで実現はできるようですが)。参考まで。

GitHub - kubernetes/ingress-gce: Ingress controller for Google Cloud

GitHub - kubernetes/ingress-gce: Ingress controller for Google Cloud

Ingress controller for Google Cloud. Contribute to kubernetes/ingress-gce development by creating an account on GitHub.

互換性

この Ingress リソース、Kubernets 1.19 から書式が異なるので注意が必要です。

source: https://opensource.googleblog.com/2020/09/kubernetes-ingress-goes-ga.html

apiVersion の変遷は以下の通りです。

リリース時期 Kubernetes のサポート開始 Ingress バージョン
2016年3月 Kubernetes v1.2.0 extensions/v1beta1
2019年5月 Kubernetes v1.14.0 networking.k8s.io/v1beta1
2020年8月 Kubernetes v1.19.0 networking.k8s.io/v1

Ingress のアップグレード戦略

現用で動作させている Nginx (Ingress Controller) をアップグレードすると、いざ不具合が生じた時にダウンタイムが生じたり、ロールバックが困難になるなどのリスクがあります。そこで IngressClass を利用して複数の Ingress Controller の併存の戦略を採用します。これには以下のメリットがあります。

  • サービス(アプリケーション)を1つずつ安全にトラフィックを移し替えることができる
  • 現用の Ingress Controller には変更を加えないため、バージョンごとの互換性やアップグレード単位の検討をすることなく、使いたいバージョンの Ingress Nginx まで一気にアップグレードできる(正確には、新規に構築できるの意味)

IngressClass の詳細配下を参照してください。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

source: https://kubernetes.io/ja/docs/concepts/services-networking/ingress/#ingress-class

GKE クラスタアップグレードコマンド

GKEアップグレード作業で利用したコマンドは以下の通りです。

マスターアップグレード

# クラスタのコントロール プレーンで使用可能なバージョンを確認するには、次のコマンドを実行します。
gcloud container get-server-config

# デフォルトのクラス タバージョンにアップグレードするには、次のコマンドを実行します。
gcloud container clusters upgrade CLUSTER_NAME --master

# デフォルト以外の特定のバージョンにアップグレードするには、--cluster-version フラグを指定します。次に例を示します。
gcloud container clusters upgrade CLUSTER_NAME --master \
    --cluster-version VERSION

ノードアップグレード

# 1.11 から 1.18 まで一気にアップグレード
$ gcloud container clusters upgrade CLUSTER_NAME --node-pool NODE_POOL_NAME
All nodes in node pool [NODE_POOL_NAME] of cluster [CLUSTER_NAME] will be upgraded from version [1.11.5-gke.5] to version [1.18.20-gke.901]. This operation is long-running and will 
block other operations on the cluster (including delete) until it has run to completion.

Do you want to continue (Y/n)?

実行時間は台数によりますが十数分かかるため、実行状況は別のコマンドで確認できます。

$ gcloud container operations list

$ gcloud container operations describe operation-1655762670000-abcd1234
endTime: '2022-06-22T22:04:36.64991075Z'
name: operation-1655762670000-abcd1234
operationType: UPDATE_CLUSTER
selfLink: https://container.googleapis.com/v1beta1/projects/123456789012/zones/us-xxxx1-a/operations/operation-1655762670000-abcd1234
startTime: '2022-06-22T22:04:36.26058939Z'
status: DONE
targetLink: https://container.googleapis.com/v1beta1/projects/123456789012/zones/us-xxxx1-a/clusters/CLUSTER_NAME

なお可用性の担保のためアップグレード作業の同時実行数を制御するためのパラメタがありますが(サージ アップグレード)、Spod VMでは無視されるようです。

警告: Spot VM を使用するノードの場合は、可用性が保証されないため、サージ アップグレードの値は無視されます。アップグレード中は、Spot VM を使用するサージノードの準備が完了するのを待たずに古いノードが直接ドレインされます。

まとめ

GKE クラスタのアップグレードにおいて気をつけるべき情報や、アップグレード作業の概要を記載しました。最初は非互換APIの利用量(レポート)が多くで億劫になっていましたが、Cert Manager や Nginx (Ingress Controller)、および GKE (Kubernetes) のマスターとノードそれぞれ少しずつアップグレードしていくことで、日に日に非互換APIへのアクセスも減っていくことが確認でき、だいぶ助かりました。

Kubernets のアップグレードを溜め込んでいる方、あるいは普段EKSを利用していてGKEだとどうなのだろう、という関心のある方の参考になればと思います。