Kubernetes を本番環境に適用するための Tips

2018年12月6日 at 8:20 午後 1件のコメント

先日 JAPAN CONTAINERDAYS v18.12 に参加し 「40 Topic of Kubernetes in 40 Minutes」 という内容で 40 個の Kubernetes に関するトピックを 40 分でご紹介する内容を発表させていただきました。

第一弾の記事:JAPAN CONTAINERDAYS v18.12 での発表について

時間の関係上、セッション中でも詳しくお伝えできなかった所もあるので、ここで真意も含めて共有したいと思います。特に Kubernetes に関連した Topic 26-33 の部分を詳しくご紹介します。



26. すべての k8s 機能を利用する必要はない
Please Remember J2EE !!

27. 複雑な構成を作らない
運用構成を変えればできることを無理して k8s でしない
Simple is the Best

28. K8s にはポータビリティがある?
ある点とない点がある

29. どのバージョンを利用していますか?
バージョン毎に設定や機能の差異がある

30. 大規模 k8s クラスタを構築しない !!
ノード数を多く作らない

31. K8s のバージョン・アップは慎重に!!

32. ボリュームを扱う際には注意しましょう
Persistence Volume は極力使わないで

33. DB はマネージド・サービスを利用 !!
開発環境は OK !! でも本番は NG !!


26. すべての k8s 機能を利用する必要はない
Please Remember J2EE !!

今、Kubernetes は急速な勢いでエコシステムを拡大しています。エコシステム全体を通すと、並行して 2000 を超えるプロジェクトが走っており、日々何か新しい k8s 関連のツールや機能ができていると言っても過言ではありません。これは、もちろん Kubernetes のコンセプトが素晴らしく、多くの可能性が秘められているため、多くの方が賛同しこの状況が生まれていると思います。一方で、私は過去の経験から、今の急速な k8s の拡大に危惧している点もあります。出来る事が多くなればなる程、教育コストや運用・管理コストは大きくなっていきます。

私は Java を古くから見ている人間なので、今の状況を J2EE の時と同じような目で見ています。全てのエンタープライズ開発のニーズに応える為に J2EE はどんどん肥大化していき、結果として複雑で扱いづらくなりました。J2EE 当時は XML での設定でしたが、今 k8s では YAML で設定してます、そして YAML が辛いとか言ってらっしゃるのをお見かけします。ちょっと似てますね。

自分のやりたい事、実現したいことに対して、本当に、k8s の全機能は必要でしょうか?

例えば、マイクロサービスを作って行く事を考えると、Deployment は必須で一番の核となる機能です。一方で、それ以外の機能はどうでしょうか?すべてのマイクロサービス開発者や運用者にとって必要でしょうか?(理解しておくのは必要ですが使うかどうかは別)例えば、Job にしても Cron Job にしても、本当に k8s で実行する必要あるのでしょうか?他の別の場所でも実行出来ませんか?全てを k8s 中心で考えるのではなく、こうした事を考えるのはとても重要です。また DaemonSet にしても log を収集したりする際には設定が必要ですが、マイクロサービスを開発する多くの場合においては、多くの開発者にとっては必要無いでしょう。こうした考えを持つ事で、優先的にどの技術から検証をして行けば良いのか優先づけを行う事ができるようになります。

古いたとえですが、
J2EE で言うところの「JSP, Servlet は便利で使うけど、EJB は難しいし設定も大変なので積極的には使わない」というのに似ています(おっさんなので例えが古く、若い方にはわからない例え話で申し訳ありませんが)

でもこれ以外にも、J2EE と (k8s + エコシステム)って色々な点で良く似ているなと思います。例えばコンテナの Init Container や Pod の PostStart や PreStop なんて、Java で言う所のコンストラクタであったり、PostConstruct, PreDestroy と同様の概念ですし、Istio なんかは、AOP(Aspect Oriented Programming)をコンテナの世界に持ってきたような物です。つまり、今までエンタープライズ Java とかをやってきた人にとっては、k8s は決して目新しい物ではなく、今まで Java でやってきた事がコンテナに置き換わったんだなと思える部分は多々あると思います。

その観点で言うと、時代は繰り返すと言いますが、J2EE において Struts や Spring が出てきたように、今の k8s に対して、新しい簡単で軽量な別のオーケストレーション・ツールが出てきてもおかしくないかな?それを作った人は第二の Rod Johnson (Springの作者)になり、もしかしたらそこに新しい別のビジネスチャンスがあるのでは?と思う位です。

結局、ここで何が言いたいかと言うと、k8s に僕たちが使われるのではなく、k8s の便利な機能を私たちが選んで使うんだ!と言う気持ちや感覚が大切なのです。

無理して全部使わなくても良いし別の手段があるならば別を使っても良いと思っています。

27. 複雑な構成を作らない
運用構成を変えればできることを無理して k8s でしない
Simple is the Best

これも、26 によく似た話なのですが、k8s では複雑な構成を組むこともできます。名前空間の概念があるので、1つの k8s クラスタでマルチテナントとか、開発、テスト、本番環境を構築することも「できます」。さらに、RBAC も利用できる為、各ユーザ毎に細かい認証・認可の設定も「できます」。

でも、やります?

できるのと、実際やるかどうかは別の話で、少なくとも本番環境と他は分けるべきと私は思っています。本番環境のアプリと開発・テストのアプリが同一 Linux VM で動作するのは気持ち悪いです。
頑張って、名前空間を切り RBAC を設定し、さらには NodeSelector や Node Affinity の設定をして特定の POD を特定の Node (Linux VM) 上で走らせる事で影響を少なくできるでしょう。確かにできるのですが、やればやるほど設定は増えて行くし、設定ミスを誘発しやすくなります。そして設定をミスした時の影響はより大きくなります。

そこで、設定にしても構成にしても難しい構成にしないように留めておくべきと私は考えます。なぜなら人間は必ずミスをするからです。

私ならば、本番環境と開発・テスト環境などを分けて構築します。本番環境を触れられる人を物理的に制限しておく方が RBAC で一生懸命頑張って設定するよりも簡単ですし、確実に守れるからです。このように構成を変える事で簡単にそしてより安全にできるならば、そちらを選んだ方が私は良いのではないかと思っています。

28. k8s にはポータビリティがある?
ある点とない点がある

k8s で良く言われることに、k8s はポータビリティがあるから導入したいとか、k8s にするとベンダーロックインがなくなり移行しやすいと言われる事があるのですが、これは正しくもあり間違いもあります。

一部の設定に限って言うと同じ設定を他の環境で動かすこともできます。

しかし、細かい話をすると、実際にはノードで動いている Linux VM の種類やカーネルバージョン、さらにはコンテナ・ランタイム(Docker)のバージョンも各環境で違います。また、筆者は Azure Kubernetes Engine を利用してカスタムの k8s クラスタ環境を構築した経験もありますが、利用するテンプレートによって、機能が有効になったり無効になったりと構築時のオプション指定で、同じ k8s バージョンでも利用できる機能、できない機能を使い分ける事ができます。
これは、同じバージョンの k8s でも環境によっては使える機能、使えない機能があると言う事を示しています。

さらに言うと、k8s はご存知の通りバージョン・アップが頻繁に行われていますが、バージョンが変わる事で YAML の書き方や、場合によってはコマンドの引数が変わることまであります。
各ベンダーで提供している k8s のバージョンも時期によってメジャーバージョンやマイナーバージョンで差異が大きくありますので、全く同時期に同じバージョンのクラスタを構築するのは難しいかもしれません。

同じベンダーの k8s を利用した場合であっても、バージョンが異なると動かなくなる可能性があるのに、異なるベンダー環境 (OS, コンテナ・ランタイム(Docker)) で動かす事は本当にポータビリティがあると言って良いのでしょうか?

プレゼンでの発表時は例として、LoadBalancer や Volumeが違うことを例にあげましたが、それだけではない差がある事を、ここでお分かりいただけるかと思います。

私は、ポータビリティがあるからといって k8s の事をお勧めされる方のお話にはご注意くださいと、お客様には申し上げています。

29. どのバージョンを利用していますか?
バージョン毎に設定や機能の差異がある

28 で既に、バージョンの差異における課題について申し上げましたが、上記のような理由からどのバージョンを利用しているのかを強く意識する必要があります。

30. 大規模 k8s クラスタを構築しない !!
ノード数を多く作らない

AKS では 100 ノード、AKS Engine を使うと 1200 ノードまで、Kubernetes のノード数を増やす事が「できます」。もちろん、ニーズに応じて大規模クラスタを構築して1つのクラスタ内で全てを完結したいと思われる方もいらっしゃるでしょう。しかし、それほど大規模なクラスタを構築するのが果たして本当に必要なのかどうなのか十分に考えてお作りください。特に、メンテナンス性を考えて構築することを強くお勧めします。

たとえば、仮に1度クラスタを作ってしまえば、クラスタのメンテナンスが一切不要と言うことでしたら、大規模クラスタを構築するのもありでしょう。しかし実際には k8s もメンテナンスが必要です。各ノードの Linux VM にパッチを適用する必要もありますしバージョン・アップが必要になる場合もあります。各ノードをローリング・アップグレードで更新し完了するまでどれ程の時間を要するでしょうか。またそのメンテナンスの際、ノードが予期せぬ不具合にあった場合、もしくは API サーバ(管理サーバ)にトラブルが発生した場合どのような事態が発生するかを考えてみていただけないでしょうか。最悪の場合 k8s クラスタが壊れてまったく操作できなくなる事もありえます。その場合、またイチから 100-1200 ノードの k8s クラスタを構築するのにどれくらい時間がかかるでしょうか。再構築する間は一切のサービスが受けられなくなる程の大影響を及ぼしてしまいます。

POD を利用しコンテナ・レベルでいくら、マイクロサービスの考えに従って回復性や、可用性やスケールなどを考えていても、一番下側の VM 側がメンテナンスしやすいように作られていなければ、結局モノリシックに構築しているのと全く変わらなくなってしまいます。1つのクラスタに対するトラブルで全サービスに影響が出てしまいます。

私ならば、k8s のクラスタレベルでも適度なサイズ(もちろんマイクロやミニのレベルではなくてよく)、ミドルサイズくらい、もっと言うならば何か不足な事態が発生してもすぐに対応がしやすいようなサイズで構築することをお勧めします。限界にチャレンジしてもあまり良いことはないように思います。

31. K8s のバージョン・アップは慎重に!!

30 でも少しバージョン・アップに対して触れましたが k8s のバージョン・アップはとても危険を伴います。ベンダーが提供するバージョン・アップ・ツールやコマンドを利用すると簡単にバージョン・アップが「できる」でしょう。ただしその恩恵が得られるのは、コマンドやツールが正常に完了した場合のみです。コマンドやツールが失敗する事もありますし、その場合、最悪クラスタが壊れる事もありえます。

さらに言うならば、k8s はバージョン・アップする事で古い YAML の設定ファイルが、新しいバージョンの環境で必ず動くと言う保証はどこにもありません。そのような事態が発生する可能性がある中で、それを実行しますか?
本番サービスに直ちに影響を及ぼしても良いでしょうか?

せっかく、Deployment や Istio などを使って、ブルー・グリーン・デプロイやカナリー・デプロイなどの手法を使って、pod レベルでは本番に影響しないように頑張っても、クラスタ・レベルでも同様の事を考えていなければ意味がありません。影響は pod の比ではないほど甚大です。

もし、k8s クラスタのバージョン・アップをするならば、私ならば k8s レベルでも、新規にクラスタを構築し、リクエストのルーティングをクラスタ・レベルで 8:2 などで試しながら安全にバージョン・アップしていくでしょう。

32. ボリュームを扱う際には注意しましょう
Persistence Volume は極力使わないで

追記:この項目は Azure 用です (2018/12/07)

k8s では PV (Persistence Volue), PVC (Persistence Volume Claim) を利用して外部ストレージをマウントする事ができます。しかし、筆者の経験では PV や PVC を扱いボリュームをマウントさせた際に、今まで様々な問題に遭遇してきました。

代表的なのは下記の URL の記事のような問題です。

* How to Understand & Resolve “Warning Failed Attach Volume” and “Warning Failed Mount” Errors in Kubernetes on Azure
* Getting Unstuck with EBS: Primer on How to Use Docker and EBS

簡単に説明します。Deployment で2つの replica を常時起動しているように設定し、それぞれの pod にボリュームを1つづつマウントさせる場合を考えます。

1 pod に 1 ボリュームをマウントした場合、内部的にそれぞれ Attatch, Detach の状態を保持しているのですが、仮に1つの Pod が不意に死んだ場合、綺麗にボリュームのマウント状態を Detach してくれない場合があります。
この場合、k8s のスケジューラは1つが停止したため、新しい Pod の再作成を試みますが、ボリュームが Detach されていないため、再作成の Pod がマウントするボリュームがないため再起動に失敗する場合があります。一応、コマンドを打てば修正する方法はあるのですが、pod がいつ不意に停止するかは想定できません。

また、それ以外にもボリュームのメンテナンスはそれなりに大変です。実際にボリュームのマウントには時間を要します (実装に応じて異なる)。そして、k8s v1.13 までは、使用中のボリューム・サイズを拡張する事は出来ませんでしたので、マウントしているボリュームがいっぱいになると別のボリュームを再作成しマウントし直すなどの必要もありました。(v 1.13 に対応しているのはまだ少ないので多くの方がまだこの状況)

さらには、k8s や AKS の GitHub の Issue を見ても数多くの PV, PVC に関する問題が報告されています。

https://github.com/kubernetes/kubernetes/issues
https://github.com/Azure/acs-engine/issues

将来的には、PV, PVC のクオリティも向上し、利用する場面におけるベストプラクティスなどが出て安心して使用できるようになる時がくる事が期待されますが、現時点では、私ならば極力本番環境には適用したくないと言うのが本心です。

もしも、違う方法で回避ができるならばそちらの方法をお勧めしています。
例えば、ファイルの保存などが目的なのであれば、Stroage 用の SDK を使ってプログラム側から直接、保存・更新・削除などを実装する方法をお勧めしています。こちらの方が、POD 増加・減少それぞれにおいてもスケールしますし、Attach, Detach を気にする事もありません。

追記:2018/12/07 ここから —



また、上記以外でも私は、PV, PVC を積極的に採用しない理由があります。
実装するアプリケーションやサービス側から見て、static でマウントするにせよ dynamic でマウントするにせよ、1:1 でマウントする場合は、ボリュームのメンテも必要になります。なぜならはk8s の v1.13 まではボリューム・サイズを固定で設定しなければならずボリュームの拡張もできません。結果として管理項目も増えます。そしてアプリケーションのスケールの観点でもスケールがし辛くなります。

私ならば、プログラム的に Azure Storage などの外部ストレージに書き出した方が、アプリケーションのスケールもしやすいと考えますし、ディスク管理や制限に対する考え方も容易になります。

プログラムやサービス側からは、インメモリ・グリッドのような横にスケール・アウトさせる事ができるようなサービスを利用する方が、アプリケーションをスケールさせ易いので、私ならば、こうした違う方法を模索します。

そして、同僚の真壁さん (@tmak_tw) からのご意見はコチラ




追記:2018/12/07 ここまで —

それでも、もちろんボリュームをマウントして使いたいと言うニーズもあると思います。その際は上記のようなことが発生する可能性や他にも issue に上がっているような問題を認識した上でお使いいただく事で問題が発生した時に迅速に対応ができるようになるかと思います。ぜひお気をつけてお使いください。

33. DB はマネージド・サービスを利用 !!
開発環境は OK !! でも本番は NG !!

追記:この項目は Azure 用です (2018/12/07)

32. の「ボリュームを極力使わないでください」の延長線上で、ボリュームを扱うサービスは極力外に出したいです。例えば、代表的な所で DB が一番最初にきますが、プライベートの Docker レジストリや、Git のレポジトリなどボリュームを扱かわなければならないようなサービスは k8s の中ではなく、極力外で管理をしたいです。特に DB などのサービスはマネージドな DB の方が自分で管理をするよりも簡単に安全にご使用できる場合がありますので、仮想ネットワーク経由で安全な接続を利用した上で外部サービスに接続する方法をお勧めしたいと思います。

ご参考:AKS access to Azure Database for MySQL via VNet

最後に

k8s は今、エンタープライズ・システムの構築に必要な機能やサービスを、どんどんと追加しています。その際に、我々は一旦立ち止まって、全てを k8s 上に実装しなくても良いのでは?という考えを持つ事が重要なのではないかと思います。
それにより簡単に運用管理ができるような場面もあると思いますし、思い切ってここは使うけど、ここは使わないと言うご検討をいただくのがより有効にご活用いただけるようになるのではないかと思います。

この記事は 2018 年 12 月時点で、私が k8s HackFest などを通じて経験してきた内容をまとめていますが、もちろん今後 k8s は品質も向上しさらなる機能追加も行われていくと思います。今後、私たちは常に k8s の最新動向をウォッチしながら、できる事と、試す事、実際に本番に適用する事を分けて考えて考えて行かなければならないと思います。

ご自身にとって最適な構成をご検討・構築いただければ誠に幸いです。

私も完璧な人間ではありませんので、もし、ここは違うよなどがあれば、この記事をもとに議論したりさらなるご検討をいただければ誠に幸いです。

Entry filed under: Java.

JAPAN CONTAINERDAYS v18.12 での発表について Quarkus: コンテナ上で Java アプリを高速起動する新しい手法のご紹介

1件のコメント


Java Champion & Evangelist

Translate

ご注意

このエントリは個人の見解であり、所属する会社の公式見解ではありません

カレンダー

2018年12月
 12
3456789
10111213141516
17181920212223
24252627282930
31  

カテゴリー

clustermap

ブログ統計情報

  • 1,288,315 hits

Feeds

アーカイブ