Da Vinci Studio インフラ基盤部 SRE チームの林田です。
今回は Amazon Elastic Kubernetes Service(※以下EKS)素人の私が、DL 数1,000万以上のサービス Zaim のクラスターの Kubernetes(※以下k8s)バージョンアップという大役を仰せつかり、またどのようにそのミッションをクリアしていったかについて執筆していこうと思います。
EKS クラスターの k8s バージョンアップとは?
まずバージョンアップを行う対象は以下の2つです。
EKS クラスターの k8s バージョンを上げる
ワーカーノード(※弊社の場合は EC2 インスタンス)の k8s バージョンを上げる
弊社の場合、構成管理ツールである terraform を使っているのでバージョンアップ作業自体は、terraform のコードを数行変更するだけで終わります。
それの何がつらいの?
前述の通りバージョンアップ自体は構成管理ツールを使っている場合は
コードや設定ファイルを数行変更するだけで良いですし
構成管理ツールを使っていない場合でも AWS のコンソールからボタンを押すだけでバージョンアップ出来ます。
しかしそこには落とし穴がありまして
k8s を使ったことがある方ならご存じだと思いますが
k8s はクラスター上で動くリソースをマニフェストと言う設定ファイル(※ yaml ファイル)で管理します。
そして非常にざっくりした言い方になりますが
そのマニフェストの有効な書き方が k8s バージョンごとに変わる
のです。
仮にマニフェストを有効な状態に書き換える前にバージョンアップを行ってしまうと途端にサービスにアクセス出来なくなり恐怖の「502 Bad Gateway」が発生します。
またマニフェスト以外でも、アドオンをインストールしている場合はそのアップデートも必要になります。
弊社では以下のアドオンをインストールしていますので
それぞれアップデートの必要があるか調査する必要があります。
metrics-server
cluster-autoscaler
vpc-cni
load-balancer-controller
etc ...
このアドオンに関しても、k8s バージョンごとに更新すべきものが変わります。
ちなみに、k8s のバージョンは約3カ月に1回公開されまして
弊社のように EKS を利用している場合
AWS が1つのバージョンにつき約12ヶ月間サポートしてくれます。
しかしアップデートは1バージョンずつ行う必要があるため
(※ 例えば現在のバージョンが v1.21 の場合、最新の v1.26 に一気に上げることは出来ない)
サボっていると後が苦しくなります。
従って3カ月と言わなくとも1年に何回かはアップデートを行って追従して行く必要があります。
う~~んこりゃ大変だ~~ (+_+)
※ EKS の各 k8s バージョンのサポート期限は Amazon EKS Kubernetes リリースカレンダーをご参照ください。
※ このブログは2022年12月に執筆されたものです。
ではどのように書き換えていけば良いか
EKS と k8s の公式ドキュメントを確認します。
ググってると色んな方々が所謂「俺なりの EKS アップデート」についてブログなどで書かれていますが
まずは公式を読むのが大事です。
今回は v1.22 にアップデートするのでそれ用のドキュメントを読んできます。
ドキュメント | URL |
---|---|
Kubernetes 1.22(AWS 公式) | https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/kubernetes-versions.html#kubernetes-1.22 |
Kubernetes バージョン 1.22 の前提条件(AWS 公式) | https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/update-cluster.html#update-1.22 |
Deprecated API Migration Guide(k8s 公式) | https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-22 |
例えば ↑ のキャプチャは、k8s 公式のドキュメントですがこれを例に要訳すると
- 「Ingress というリソース書き方が変わるから変更してね」
ということが書かれています。
この Ingress 以外にも今回は例えば APIService など全10以上のリソースが変更対象になっております。
そして弊社では500以上のマニフェストを定義しておりますので
全マニュフェストをチェックして、その内部で該当リソースが定義されていないか調べる必要があります。
クラスターとワーカーノードのアップデート戦略を探る
マニュフェストやアドオンの修正が完了して、準備万端!!
っとなったとしても、人間ですから何か見落としがあることも考慮しておかなければいけません。
アップデートは、ロールバックをすぐに行える形で実施する必要があるのでどのような戦略を取ればそれを実現出来るか調査します。
色々調べていると、クラスターとワーカーノードのアップデート戦略は、下記の3方法が取られることが多いようです。
zenn.dev
今回は、部分的とは言えロールバックも出来て安全性とコスト面で塩梅の良い3つ目の
- control plane(クラスタ) は in-place 方式、worker node は migration 方式
という方法を取ることにしました。
タスクを細かくリスト化する
前述のドキュメントの内容を隅々まで読み漁り
細かいタスクに分けリスト化すると作業し易くなります。
私の場合はさらに GitHub で Issue 化しましたが
ちょっと GitHub の Issue はプライベートリポジトリのためリンクを張っても見て頂けないので
ここではテキストでリスト化した内容を記述します。
[マニュフェスト更新] CustomResourceDefinition の更新
[マニュフェスト更新] APIService の更新
[マニュフェスト更新] Ingress の更新
[アドオン更新] metrics-server の更新
[アドオン更新] cluster-autoscaler の更新
[アドオン更新] vpc-cni の更新
[アドオン更新] load-balancer-controller の更新
[terraform ソース更新] クラスタの更新
[terraform ソース更新] ワーカーノードの更新
[アドオン更新] kube-proxy の更新
[アドオン更新] coredns の更新
ドキュメントを読むと分かりますがクラスタの更新の前に事前アップデートが推奨されているアドオンとそうではないものがあります。
今回は metrics-server
cluster-autoscaler
vpc-cni
load-balancer-controller
の4つを事前アップデートする必要があることがわかりました。
ここらへんも k8s バージョンによって変わるので事前調査が大変なポイントであります (;^_^A
またマニュフェストの更新に関しては
普通なら GitHub などにコミットしているマニフェスト群を grep してそのリソースを使っているかどうかチェックするだけに留まると思います。(※実際私もそうでした、、)
しかし実はそれだけでは不十分で、サードパーティーツールやアドオン(※つまり自分が書いたマニフェスト以外)が隠れてリソースを参照している場合があります。
Amazon EKS クラスターの Kubernetes バージョンの更新 - Amazon EKSにも書かれている通り
クラスターで非推奨の API が使用されているかどうかを確認するには コントロールプレーンの監査ログを有効にし イベントフィルターとして v1beta を指定します。
「監査ログ」を有効にしチェックを行います。
Amazon EKS コントロールプレーンのログ記録 - Amazon EKS
「監査ログ」は EKS のコンソールから有効化できます。
ログは CloudWatch Logs に "kube-apiserver-audit" というプレフィックスで出力されるので、それを "v1beta" のキーワードでフィルタリングしてみます。
すると出るわ出るわ...
試しに1件内容を確認してみますと、どうやら廃止される予定の "authorization.k8s.io/v1beta1/subjectaccessreviews" がアドオン metrics-server
から参照されていることが解ります。
というわけで、metrics-server
の更新も行います。
公式ドキュメントにてアップデートが推奨されているアドオンの中には metrics-server
は書かれていなかったので
見落とさないためにも、この「監査ログ」をチェックすることも必須事項となります。
バッチ処理の存在確認
マニフェストの変更やアドオンの更新以外でも注意すべき事項があります。
それはどのようなバッチ処理がスケジューリングされているかです。
というのも冒頭列挙した作業の中の1つ「ワーカーノードの更新」ですが
これをやる時は旧ワーカーノードで動いている Pod を
新ワーカーノードに移動させないといけません。
※ Pod とは?Podの概観 | Kubernetes
これは kubectl drain というコマンドで行うのですが
※ kubectl drain とは? Kubectl Reference Docs
このコマンド何か処理が実行されている Pod があればそれを終了させてくれます。
そこで考慮すべきがバッチ処理で k8s ではバッチ処理を CronJob というリソースとして定義出来て、その CronJob は Pod 上で処理されます。
なのでバッチ処理の開発者と連絡を取り、その処理が途中で中断されても良い処理かを確認する必要がります。
中断してはいけない処理の場合、その処理が動く日時に作業するのを控える方がベターです。
バッチ処理の一覧は kubectl get cronjob コマンドで取得出来るので各バッチがどのようにスケジュールされているか確認してみます。
お、多いな~~~(;^ω^)
今回は万が一ダウンタイムが発生することを考慮して
サービスへのアクセスが少ない早朝に作業する予定ですが
その時間帯にスケジュールされているバッチ処理をリストアップし
バッチの開発者に問い合わせる必要があるというわけです。
他チームと連絡をとり日程調整をする
例えばもしも作業日の前日に
たまたまサービスが TV 番組で宣伝されたり CM がスタートしたりしたとしましょう。
前述したように今回の作業は多少のダウンタイムが発生する可能性のある作業です。
TV や CM の効果でせっかくたくさんのユーザーがアクセスしてくれたのに
万が一ダウンタイムを発生させてしまうと悲しいことになります。
従って開発チームや広報など他チームに連絡を取り
近日のメディア露出や CM スタートのスケジュールがないかを確認します。
今回は開発チームから
「ある重要な機能のアップデートをする予定だからその時期は障害発生時などの原因の切り分けのために避けてほしい」
という連絡を受けました。
リリースカレンダーを作る
さて必要な情報が得られたところでリリースカレンダーを作っていきます。
こうやって具体的な日程を予め立てておいて
他の方にレビューしてもらうなどすればよりミスなく作業が進められると思います。
※ このブログは2022年12月に執筆されたものです。
いざ!
この度は 「EKS 素人が DL 数1,000万以上のサービスのクラスターの k8s バージョンアップをやった話【前編】」をお送り致しました。
果たして無事サービスにダウンタイムを発生させることなくアップデート出来たのか!?続きは【後編】に書こうと思います~ 。
Da Vinci Studioでは、働く仲間を募集しています!
興味のある方は こちら か recruit@da-vinci-studio.net までご連絡ください。