クラスタの引っ越しによる無停止アップグレードの話

田中篤志氏:よろしくお願いします。「Kubernetes Cluster Migration」ということで、クラスタの引っ越しによる無停止アップグレードの話をしたいと思います。ちなみにこの中で……って言っても(オンラインなので)この会場(にいる登壇する人)しか見えないんですけど。

(会場笑)

アップグレードをしたことがあるよという人。たぶんみなさんしたことがあると思うんですけど、そうですよね。全員手が挙がっている。

(会場笑)

さすが。ちなみにもう1つ質問なんですけど、クラスタの引っ越し、クラスタのマイグレーションをやったことがあるという人はいらっしゃいますか?

(会場挙手)

半分ぐらいですかね。思ったより少ないな。登壇する人はもうちょっと多いかなと思ったんですけど、そんな感じですね。はい、よろしくお願いします。

今日は2つに分けて、まずはクラスタマイグレーションの必要性を話したあとに、実際にどうやってクラスタマイグレーションをやっているのかを話していきたいなと思っています。

まず「誰なの?」という話なんですけど、田中と言います。IDはbgpatでTwitterとかGitHubをやっています。今はWantedlyでインフラエンジニアをやっていて、入って2年目になります。Kubernetesは、学生時代にインターンで触って、それから3年半以上経っている状態です。

Wantedlyは何をやっているところなのか簡単に説明すると、この2つだけなんですけど紹介しておくと「Wantedly Visit」と「Wantedly People」というサービスをやっています。この2つのサービスはマイクロサービス化されていて、裏に70個ぐらいサービスが動いているんですけど、これらのサービスはすべて1つのKubernetesクラスタ上で運用しています。

クラウドマネージドなサービスを使わずに、AWSのEC2上に自分たちでkopsというツールを使ってクラスタを構築している感じになります。クラスタを使ってもうすぐ4年経つという感じなんですけど、2016年の4月にv1.2から使っていたみたいです。僕はまだこの時代は知らないんですけど、もう4年ぐらい経つということですね。

その時代からKubernetesを使って本番運用をやっていった歴史になっています。v1.2ということは、今日(発表日当時)の朝に1.18がリリースされてたので、もうかなり経っていると思います。

インプレースアップグレードとクラスタマイグレーションの違いとは

Wantedlyは、クラスタのアップグレードをもちろんやっています。どうやってアップグレードしているの? という戦略なんですけど、まずインプレース・アップグレードを試しています。これで問題なく上がったら、それでよかったねという話なんですけど、これでうまくいかなかった、サービスダウンする可能性があったり、実際にサービスダウンしてしまったらどうするか。ここでクラスタマイグレーションという手法がでてきます。

どういうものなのかを簡単に並べてみると、インプレースアップグレードは、たぶんこのあとのセッションで詳しく説明があると思うんですけど、既存のクラスタをそのまま使ってノードを順番に入れ替えていく。いわゆるローリングアップデートみたいな方法になっています。

それに対して、クラスタマイグレーションというのは、既存のクラスタは使わずに新しくクラスタをもう1個立てて、古いクラスタにあるリソースを新しいクラスタにもっていって、中身をコピーする。そして移動させて、終わったら古いクラスタを捨てる感じになります。いわゆるブルーグリーンデプロイがこれにあたるかなと思います。

簡単にインプレースの動作を説明していくと、ノードを順番に入れ替えていってバージョンを上げていく感じです。

クラスタマイグレーションは、新しいバージョンが適用されている状態で、新しくクラスタを作って、中身をどんどん移していく。移し終わったら古いクラスタは全部消してしまう方法をとります。

ダウンタイムなしでサービスを動かしたままアップグレード

もう1回比較なんですけど、今度はそれぞれどういう特徴があるのかをここで見ていけたらなと思います。インプレースアップグレードは、一言で言ってしまえば簡単な方法です。一番スタンダードな方法になっています。これはGKEとかEKSだったら、各クラウドベンダーがアップグレード用のAPIを用意しています。コンソールからポチポチ何クリックかするだけでアップグレードが終わってしまうものになってます。

あとはオンプレでも、Wantedlyで使っているようなkopsだったり、ツールを使えば同様のアップグレード用機能が付いているので、それを使ってわりと簡単にアップグレードができます。

それに対してクラスタマイグレーションはどうかというと、アップグレード用のツールみたいなのは自分は知らないんですけど、たぶんないので、そもそもクラウドとかツールとかの恩恵はぜんぜん受けられません。アップグレードの機能は、実はバージョンの差分を埋めるためにバッチみたいなのが当たっている場合があるんですけど、このあたりのバッチというのは、自分で同じような動作をマイグレーションの中でしていく必要があります。

あとは、これが一番大変かなと思うんですけど、複数クラスタを作って中身を入れ替えるということで、複数クラスタで運用をすることを考えてクラスタの運用をしないといけないということがあります。

クラスタマイグレーションの何がいいの? と言うと、互換性の話なんですけど、例えばインプレースアップグレードだと互換性が1バージョン分しかないので、1個ずつバージョンを上げていくしかない感じになっています。

例えば、今1.15とかを使ったら1.18まで上げるのに1回1.16にあげて、その次に1.17に上げて、やっと1.18みたいな感じになります。クラスタマイグレーションだと一気に1.10から1.18に飛ばしてアップグレードができるので、ここはかなりメリットかなと思います。

最後のこの互換性のない変更は、ダウンタイムが発生するところが一番のミソになってくるんですけど、インプレースアップグレードで対応できないものがあります。正確にはダウンタイムが発生してもいいなら、だいたいアップグレードはできるんですが、今回はダウンタイムなしでサービスを動かしたままアップグレードしたいということなので、この方法は取れないことがあります。

このときに、クラスタマイグレーションという方法を使ってアップグレードをしていくことになります。あとは、クラスタマイグレーションを使うとコアコンポーネントを入れ替えることができます。あとでちょっと説明するんですけど、etcdとかネットワークプラグインみたいなものを入れ替えたりもできます。

Kubernetesのバグとetcdのバージョン上げの同時対応でクラスタマイグレーションが必要に

実際にWantedlyでクラスタマイグレーションが必要になったケースを紹介していけたらなと思います。実は過去に2回のクラスタマイグレーションをしていて、2つ要因があるのでこれを紹介したいと思います。

1つ目はKubernetesのバグに遭遇して、これのせいでインプレースアップグレードができなかったという問題。何が起きたかというと、普通workerノードとかmasterノードとかリーダーじゃないmasterノードがリーダーにヘルスチェックを送っているんですが、masterノードを入れ替えたときに、入れ替えというかmasterノードを1回消すんですけど、消したときにまだ古いmasterノードに向き続けているノードがけっこういました。

一部は新しいリーダーに移ったんですけど古いリーダーを見ている人がまだいて……ちょっとこれ間違ってますね。一番下のやつは本当はNotReadyじゃないんですけど、古いmasterのデータをしているやつは、NotReadyというステータスになって、どうなるかというとNotReadyの状態が続くと中のpodを殺してしまいます。これによってpodが足りなくなってサービスが継続できなくなっていって、サービスダウンにつながったという事象がありました。

これで問題なのが、次のパッチバージョンでバックポートされたので、バージョンを上げれば直るという問題だったんですけど、そもそもバージョンを上げるためにはインプレースアップグレードの場合、masterノードを入れ替える必要があります。入れ替えるときに、またこのバグによってサービスがダウンしてしまうのは避けたかったというところで、クラスタマイグレーションが必要になりました。これが1つです。

もう1つがetcdです。これはKubernetesのメタデータを保存しているデータストアなんですけど、これのバージョンを上げるときに必要になってきました。

実はさっきのKubernetesのバグと同じタイミングで、バージョン2からバージョン3へアップグレードのほうは対応したんですけど、そもそもKubernetesはetcdのアップデート、バージョン2からバージョン3に上げるというところは対応していないので、絶対にダウンタイムが発生してしまうということがあり、まだ対応しないといけないタイムミリットではありませんでしたが、どうせならということで、このタイミングで一緒に対応した感じになります。

対応して、晴れてv3を使うことになりました。Wantedlyが使っているkopsというクラスタを作るツールなんですけど、これが用意したマイグレーションパスですね。etcdをスムーズにバージョン2からバージョン3に、まだ出てないですけど、バージョン3のその先に、将来的に上げるために用意したマイグレーションパスが、うまく動きませんでした。

かなりいろんな人たちに必死に報告したんですけど、結局対応されず、がんばってあげるしかないという状態になってしまいました。いっぱいインプレースのアップグレードを試してみましたが、コアコンポーネントのkube-dnsが不安定になって、再起動を繰り返してしまって、そのときはサービスは継続していたんですけど、もし全部落ちてしまったらネットワークが全部使えないということになるので、これはちょっと危ないから他の方法を考えるということで、クラスタマイグレーションを取らせてもらいました。