kopsの問題点とEKSへの移行
By kkoudev
kopsはAWSのEC2インスタンス等にKubernetesクラスタを簡単に構築できるプロビジョニングツールです。
(正式表記はいつからか kOps
とOが大文字になったようですが、記述しづらいのでこのブログでは全部小文字表記にしてます)
まだAWSのEKSが登場したての頃はワーカーノードの管理も設定も大変で東京リージョンでも使えなかったということもあり
kopsを使ってKubernetesクラスタの構築を行っていたのですが、
数年運用していくつかの問題点が上がってきたため
近年ある程度運用事例も増えてきたEKSへ移行を行いました。
今回はその内容について紹介させていただきたいと思います。
kopsの問題点
kopsはEC2インスタンス上にコマンド1つでVPCやセキュリティーグループ、IAM Roleなど
一通り必要なものを構築してくれます。
踏み台サーバーまで作成してくれるので、至れり尽くせりです。
初期の導入としては非常に便利だったのですが、運用するにつれて以下の課題が上がってきました。
1. バージョンによってKubernetesのアップグレードに失敗する
kopsはバージョンによってアップグレード中に問題が発生してアップグレードができないことがあります。
理由も様々で、例えばネットワークプラグインとしてcalicoを使っているときにのみ問題になるとか、 kopsのとあるバージョンで証明書の期限が短くなっていたとか、 あるバージョンAからあるバージョンBへ上がる時のみおかしくなるとか、とにかくいっぱいありました。
そしてこの問題は、kopsの運用期間が長ければ長いほど顕著になります。
私がkopsでKubernetesクラスタを構築し始めたのが kops が 1.11系のバージョンの時だったのですが、
そこから段階的(1.11, 1.12…)にバージョンアップしていき、最終的には 1.17 へアップグレードしようとしたときに
ワーカーノードがReadyにならないという状態に陥り、kopsのバージョンを変えるなど色々試行錯誤したものの
結局アップグレードすることが出来ない状態に陥ってしまいました。
こうなると新規にクラスタ構築する以外で解決する方法がありません。
2. kopsの最新バージョンを使うことが推奨されているが、逆に最新バージョンを使うとアップグレードに失敗する
1と同じ内容ですがもう少し具体的な内容を説明すると、
公式では kops を使う場合は最新バージョンを使うことが推奨されています。
しかし自分のケースでは逆にアップグレードに失敗することが多々あり、
結局Kubernetesのマイナーバージョンに合わせた kops のバージョンを使うようにしていました。
例えば Kubernetes のバージョンを 1.17系にしたい場合は kops も1.17系を利用するという感じです。
以前kopsの1.20を使って1.16から1.17へアップグレードしたときにワーカーノードのラベルが外れて nodeSelectorに失敗してしまうという問題が起きたり、 ノードが正常に起動できてReadyになっていると思いきや、セキュリティグループの設定がおかしいのかワーカーノードからRDSやElastiCacheへ接続できなくなったり等々の問題が起きました。 前者の問題は手動でラベルを付与することで解決し、後者についてはバージョンを戻すことでなんとか乗り切ったという苦い思い出があります。
ただこれは必ずこのバージョンで起きるという話ではなく、
新規にクラスタを構築したときは問題が起きません。
つまり、今までアップグレードを積み上げてきた結果、どこかの変更が上手く適用されていないのか、そのときのkopsバージョンの不具合だったのかで
知らず知らずのうちに問題を抱えてしまっている状態であると推測されます。
3. マルチAZでクラスタを作成すると、最初に作成したノードグループのノード数がAZ数より少ないと通信できないことがある
これは利用初期の頃から発生しており、1.16で新規にクラスタを作った際も再現した不具合?です。
kopsでマルチAZでクラスタを作成する場合、AZの数を奇数にする必要があります。
そこで 3 つのAZを指定してクラスタを作成するのですが、そうすると初回に作成したノードグループのノード数が
3つよりも少ない数の場合、どういうわけかまれに通信できないことがあります。
ただ、ノード数を3つ以上にしていれば問題なく通信ができるため致命的な問題ではないかもしれませんが、
ステージング環境などでサーバー台数を少なくしたいというケースに置いては余計な料金がかかることになりそうです。
同様の現象はEKSでは起きないので、これもkops特有の問題点ということになります。
4. マスターノードだけを更新してもDNS Controllerの更新が入るとワーカーノードへ接続できなくなることがある
これも割と辛い問題だったのですが、kopsでKubernetesクラスタのバージョンをアップグレードする際は まずマスターノードから更新し、それが上手く行ったらワーカーノードを rolling update するというやり方がissue等で推奨されていたため その方法でアップグレードをしていました。
基本的にマスターノードのみを更新する分には、稼働中のワーカーノードには影響がないなのですが、 DNS Controllerのバージョンが上がるときに、ワーカーノードの通信に影響を与えるケースがあります。
私が遭遇したケースだと、マスターノードとワーカーノードのDNS Controllerのバージョンが不一致になるときに
稼働中のワーカーノードに対して通信ができなくなることがありました。
そのため、このケースに遭遇するとマスターノードのアップグレードに成功してからワーカーノードのアップグレード、
ということはしてられなくて、ワーカーノードも含めて一気にアップグレードする必要が出てきます。
この辺はissueを探ると一度マスターノードのDNS Controllerのバージョンを1つ前に戻して、
そこからアップグレードすると影響がないみたいな記載も見られたのですが、
さすがにそこまで考慮してアップグレードしなくてはいけないのは非常に辛いと感じました。
5. GitHubのissueに問題がいくつも上がるものの、3ヶ月で自動的にクローズされてしまうので解決していない問題が多々ある
kopsのGitHubのissueは最後のコメントから3ヶ月経過していると自動的にクローズされるようになっています。
私のように古いバージョンからアップグレードをし続けた上で問題が起きている場合、
その原因特定も難しいのためにいつまでも解決されていない状態のままクローズされることが多々あります。
そのため、kopsを使い続けるためには原因特定が難しいケースと長期にわたって付き合っていく覚悟が必要になってきてしまいます。
以上の理由から、kopsでこれ以上運用するのは厳しいと感じてEKSへの移行を決意しました。
EKSへの移行方法
では、具体的にどのように移行していったかを簡単に紹介します。
1. Terraformの terraform-aws-modules/eks/aws モジュールを利用してEKSクラスタを構築する
EKSでクラスタを構築する際は、kopsに似た eksctl
というツールがあります。
AWSの公式でも紹介されているツールではあるのですが、
kopsで感じた裏で何をやっているかわかりづらいという問題にできるだけ対処しやすくするために、
eksctl は使わず、Terraformの terraform-aws-modules/eks/aws モジュールを利用して構築するようにしました。
このモジュールはマネージド型ノードグループにも対応しているため、
ノードの増減やオートスケールの設定を簡単に行えます。
VPCやサブネットの構築は予め行っておく必要はありますが、
これもTerraformを使って構築することでインフラ管理をTerraformへ集約できるという利点もあります。
具体的な構築スクリプトについては他サイトでも詳しく紹介されているため割愛しますが、
このモジュールを使うことで大分ラクにEKSクラスタの構築を行うことができました。
余談ですが、kopsにはTerraformの設定ファイルを書き出すオプションもあるのですが、
EC2インスタンス上にKubernetesクラスタ構築を行う関係か非常に複雑で、
Kubernetesのバージョンごとに必要な設定やコンテナのバージョンなど
ある程度把握できていないと結局コントロールすることが難しいです。
設定ファイルに不具合があったときは尚更で、パッチバージョンごとに問題を1つずつ手動解決していかなければいけないケースもあります。
そういう場合はCHANGELOGに手順が書かれてはいますが、1つずつ追っていくのはかなり大変です。
そういう意味でもEKSへ移行することで複雑なマスターノードやワーカーノードの構築は マネージドサービスとして構築することで隠蔽されるのでTerraformの設定ファイルも比較的簡潔になり、 基本的にはKubernetesのバージョンとワーカーノードのインスタンスタイプや数を気にするだけで 長期運用に耐えうることができるようになります。
但しkopsとは異なり、踏み台サーバーは自前で用意する必要があるので、 そこはTerraformの terraform-aws-modules/ec2-instance/aws モジュールなどを使って構築する必要があります。
2. ExternalDNSによるクラスタの切り替え
kopsで構築したクラスタには既に本番稼働中のシステムがあるため、
新しくEKS上に作ったクラスタへ移行するためにはDNS切り替えを行う必要があります。
私はExternalDNSを利用していたため、以下の手順にて比較的簡単にDNS切り替えを行うことが出来ました。
手順としては
- 旧クラスタ(kops)からExternalDNSをアンインストールし、ExternalDNSを止める (DNS設定自体は削除されずそのまま残る)
- 旧クラスタ側をメンテナンスモードにし、DBのバックアップと新クラスタへのデータ移行
- 新クラスタ(EKS)にExternalDNSをインストールしてデプロイする
これだけでOKです。
ExternalDNSは定期的にDNS登録をチェック&更新します。
そのため、旧クラスタのExternalDNSさえ止めてしまえば新しいクラスタ側のExternalDNS設定が旧設定を上書きして切り替わることになります。
設定の移行自体はこれで完了するのですが、
クライアントマシンやブラウザ、ルーターによってDNSキャッシュが残り続けるケースがあるため
スムーズに移行するためには予めTTLの設定も短くしておく必要があります。
まとめ
kopsはKubernetesの新機能をいち早く試す場合には最適なプロビジョニングツールですが、
数年運用しようとすると多くの問題が積み重なってきます。
そのため、長期運用することを目的とする場合は初めからEKSを使ってクラスタを構築することをおすすめします。