GKEクラスターのバージョン管理を便利にする自動アップグレードの戦略


はじめに

GKE(Google Kubernetes Engine)には、クラスタの自動アップグレード機能があります。Kubernetesにおけるマスターのバージョン管理をGoogleに任せることができる機能で、これを使うことで自分たちでクラスターの中身を入れ替える必要がなくなるため、運用コストの削減につながります。NodeのmaxSurge/maxUnavailableと組み合わせるとほぼ全自動でクラスタのバージョン入れ替えが終わりますね!なお、この機能はデフォルトで有効化されており、無効にすることはできません。

Ref: https://cloud.google.com/kubernetes-engine/docs/concepts/cluster-upgrades

今回は、この自動アップグレードにおいて注意すべきポイントや、どのような設定ができるかを見ていきます。

公式ドキュメントが散らばっているのとわかりにくいので、Terraformでどう設定するかも含めてまとめてみました。

GKEのReleaase channelについて

GKEにはリリースチャンネルという概念があり、それぞれのチャンネルに応じて、別々のバージョンライフサイクルがクラスターに提供されます。

チャンネル おおよそのアップグレード サイクル 対象ユーザー 見込み
Rapid 毎週 新しい機能を必要とする早期のテスターとデベロッパー。 認定された最新のコンポーネントで、他すべてのチャンネルより早期に提供されます。他のチャンネルよりも検証が不十分で、既知の解決策のない問題などの、未解決の問題が含まれます。本番環境のワークロードはサポートされません。GKE SLA の対象外です。
Regular 1 か月に複数回 Stable チャンネルで未提供の機能を必要とする本番環境のユーザー これらのバージョンは内部検証に合格しており、本番環境に対応した品質であると見なされていますが、履歴データが不十分なため安定性は保証されません。既知の問題には、通常は既知の解決策があります。
Stable 数か月に 1 回 安定性を何よりも優先し、頻繁なアップグレードによるリスクの大きい本番環境のユーザー これらのバージョンは、標準チャンネルの要件すべてを満たしており、実行中のクラスタのパフォーマンスに基づいて、本番環境レベルの安定性、信頼性があるものであることが判明しています。

※公式ページから引用

例えば、2020年1月頭におけるバージョンはそれぞれRapidが1.16、Regularが1.14、Stableが1.13となっています。

GKEにおけるKubernetesはDigital OceanやAmazon EKSなどと違い、多くの機能がデフォルトで統合化されたものです。より新しいバージョンベースのほうが有効な機能が多い一方で、Stableチャンネルのほうが変更頻度も少なく自動アップグレードなどに悩まされる心配も少ないという側面もあります。

例えば、GKE上でGCLBのIngressを使うためのIngress Controllerにはingress-gceがありますが、こちらはALB Ingressと異なりデフォルトでGKEのクラスターに組み込まれています。ingress-gceのリリースノートをご覧になれば分かる通り、新しいバージョンのIngress Controlelrは新しいバージョンのGKEでないと使えません。

まずは、お使いのクラスターの特性やメンテナンスコストの観点から、どのリリースチャンネルを使うべきかを見定めてみるとよさそうです。

自動アップグレードの適用とメンテナンス時間枠の設定

自動アップグレードは基本的にGoogleが自動的にスケジュールしたタイミングで発生します。そのため、ユーザーが手動でクラスターのバージョンを上げない限り、手元で具体的な時間を制御することはできません。

しかし、メンテナンスの時間枠と除外を設定することで、一定の制限の範囲において「このタイミングでのみアップグレードを行う」という条件を設定できます。

クラスター作成時に実際に設定するときはこのような形で行います。

メンテナンス時間枠における制限事項

GCPのドキュメントには以下のような記述があります。

14日間のローリング ウィンドウ内で少なくとも24時間はメンテナンスが可能な状態にする必要があります。メンテナンスに4時間以上連続する時間を用意してください。

日本語がわかりにくいのですが、これは、要するに

  • 14日間(2週間)の間に少なくとも合計で24時間のメンテナンス時間を作る
  • 1回のメンテナンス時間は最低でも4時間以上確保する

という2つの条件を満たす必要があるという意味になります。

逆算すると、14日間に24時間以上なので、仮に毎日メンテしていいがとにかく最低限の時間に抑えたい場合は24/14で平均して1.71時間以上を設定すればよいが、1回のメンテナンス時間は4時間以上確保する必要があるのでだめ。

このバランスを取ろうと思うと、4(時間)×6(日)=24なので、1週間のうち少なくとも3日、4時間のメンテナンス時間を設ければよい、という計算になります。

結論

以上を踏まえて、うちのチームでは以下のような設定をTerraformに入れました。

cluster.tf
resource "google_container_cluster" "cluster-name" {
  provider                 = google-beta

...

  maintenance_policy {
    recurring_window {
      start_time = "2019-12-04T05:00:00+09:00"
      end_time   = "2019-12-04T09:00:00+09:00"
      recurrence = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH"
    }
  }

}

ドキュメントにもある通り、時刻と日付のフォーマットはRFC-5545準拠なので、このような表記になります。

月曜から木曜の朝5時から9時までメンテ時間として確保しています。

マスターのバージョンアップはワークロード(上に乗ってるアプリ)自体には原則として影響はありません。

ただ、Kuberntes APIを使うようなアプリ(例えばバッチで内部的にKubernetesのPodをプロビジョンするとか)の場合はAPI Serverの応答がなくなるので注意が必要です。