あさのひとりごとスマートフォン用の表示で見るあさのひとりごと3日坊主にならないように、全力を尽くします。記事は個人のひとりごとです。所属する組織の意見を代表するほど、仕事熱心じゃないです。HOMEBooksProfileこの広告は、90日以上更新していないブログに表示しています。HatebuKubernetesは、コンテナアプリケーションをデプロイするためのオーケストレーションツールです。Kuberenetesは分散環境におけるスケーラブルなコンテナ実行環境をつくるための、さまざまな機能が提供されています。Googleが開発したBorgをもとにOSS化したものですが、今日ではマイクロソフトや(ryKubernetesをつかうとステートレスでマイクロサービス的なアプリケーションを1日に何度もデプロイでき、スパイクアクセスがきても水平スケールが容易なので、大規模Webシステムでスケーラブルな基盤を作れる、というのは広く知られています。Requests」という機能があり、これはPodをデプロイする時に必要とするリソース(CPU/メモリ)を指定できるものです。これにより、Kubernetesクラスタのリソースの使用率を高め、効率よくアプリを稼働させることができるのも、うれしさの一つです。Kubernetesではコンテナが使用するコンピューティングリソースを明示的に要求したり制限をかけたりすることができます。Request)ついて、コンテナアプリが使うメモリを明示的に要求するとクラスタ上でどういう動きをするのか?メモリをたくさん使う別アプリが邪魔してきたとき、きちんとシステムは動作するのか?が気になり、簡単な検証をしてみました。実験環境AzureのKubernetesのフルマネージドサービスであるAKSを使います。公式サイトをもとにKubernetesクラスタを構築しました。Docsここでは、次の構成のクラスタで実験します。MasterもNodeもkubernetes1.9.6で検証しています。VMの「Standard_D1_v2」をNodeにつかっています。Standard_D1_v2は1台当たり約3.3GBのメモリが使えます。念のため、次のコマンドで確認します。3399192KiNode上ではkube-proxy等も動作しているため、Podを1つも動作させていない状態でも、223M/499Mのメモリを使用しています。Requestの動きを確認します。コンテナに制限をかけるには[resources:]-[requests:]で値を指定します。2」つまり2つのPodがKubernetesクラスタ上にスケジューリングされる定義になります。1.5Gi]を指定します。対して「このPodにあるNginxコンテナは1.5Giのメモリ必要だからよろしく!」を宣言しています。1.5Giこれを次のコマンドを実行してクラスタ上でリソースを作ります。createdPodがそれぞれNode1とNode2で1つずつ動いています。aks-nodepool1-12354740-1絵で描くとこんな感じ。起動しているNginxは何も仕事をしていないので、実際のメモリ使用量はほとんど増えていません。15%要求されたメモリが実際のメモリを超えるとどうなるか次のコマンドを実行して、Podのレプリカ数を2から3に増やします。scaledNode1に2つのPod、Node2に1つのPodが動いています。定義ファイルで要求した総メモリ量は、実際のクラスタのメモリ量を超えていません。aks-nodepool1-12354740-1絵で描くとこんな感じです。次はレプリカ数を3から4に変更します。scaled4つ目のPodである「reqest-exp-fgrpn」はどこのNodeでも起動せず「Pending」になっているのが分かります。aks-nodepool1-12354740-1またまた絵で描くとこんな感じ。しつこいですが、実際のメモリ使用量はほとんど増えていません。実際はアイドル状態なのに4つ目のPodはスケジューリングされていないということをいっています。これは、4つ目のPodを配置しようとしても、メモリの空きがマニュフェストで定義した「1.5GB」を確実に確保できるスペースがNode上にないからこのような状態になっています。Requestsは、Podに対して指定したリソースが使えるように保証する仕組みです。この値はPodをNodeにスケジューリングするときに使われます。Requestsを指定したコンテナを含むPodを作成すると、KubernetesのスケジューラーはNodeを選択して実行します。その際、各Nodeには、各リソースタイプの最大容量をもっていてスケジューラは、各リソースタイプに対して、スケジュールされたコンテナのリソース要求の合計がノードの容量よりも少ないことをチェックします。実際のメモリ使用率は非常に低くても、スケジューラはチェックが失敗した場合はNodeにPodを配置しません。Requestsの設定はPodではなく、コンテナに対して行われます。今回指定したメモリはバイト単位で設定でき、E/P/T/G/M/K(Ei/Pi/Ti/Gi/Mi/Ki)のいずれかを使用して、メモリを整数または固定小数点整数として指定します。今回のケースでは、実際のメモリがたくさん空いているにもかかわらずPodは配置されませんでした。Nodeのメモリの最大容量は分かっているので、あらかじめ基盤の方式設計段階でNodeにぎゅうぎゅうにPodがスケジューリングされることを避けることができます。今回は同じサイズのNodeで検証しているのできちんと2台でスケジューリングされそうな気もしますが、なにか見落としているのかもわかりません。いうわけで、ソースコードをきちんと読みたいと思います。(理由をご存知の人がいればおしえてください)追記:まかべ@マイクロソフトさんから教えてもらいました!ご指摘通り、Node1だけheapsterが動いておりました。Requestsについてですが、片方のNodeだけheapsterが動いていて非対称なので、その分メモリが296Mi足りなくて4つめのPodが行儀よく待っちゃってるかも。heapster分を考慮してPodごとのRequestを1.3Giにしたら、4つ動きました。Requests」で宣言した分のメモリをきっちり確保してPodをスケジューリングしているのが分かりました。Requestsは、実際のメモリの使用量ではなく、クラスタに割り当てられているリソースに基づいていることもわかりました。Requests」の宣言なしにメモリをたくさん使う野良Podががんがんデプロイされたらどうなるでしょうか?まず実験のため、次のようなメモリを1.0GBつかうDockerイメージを作ります。これをビルドしてmem-stressという名前のDockerイメージを作ります。Registryなどのレジストリで公開します。次にこのDockerイメージを動かすPodを起動するReplicaSetのマニュフェスト(mem-stress.yaml)を作ります。5」と定義しています。クラスタには理論上各Nodeに3.5GBずつメモリがありますので、ざっくり5つくらいの野良Podを起動してみます。Request)を指定していないことです。どれだけリソースを使うコンテナが入ったPodなのか一切知らないのです。createdなるほど。「mem-exp-xxx」のPodは4つしか起動せず、うちいずれかの1つはCrashLoopBackOff―Errorで再起動を繰り返しています。aks-nodepool1-12354740-1絵にかくと次の感じです。Podのログを確認するとエラーが出ているのが分かります。39sシステム全体のメモリ使用量はきちんと上がっています。77%これを、40分ほど放置します。その間に夕飯のしたくを。aks-nodepool1-12354740-1何が起こっているか、よーく見てみます。1.Node1にスケジューリングされた野良Pod3つ「mem-exp-6dcgh」と「mem-exp-dnwjk」と「mem-exp-x9gxl」はPodを稼働させたくても実際のメモリが足りないため、うち1つのいずれかが再起動を繰り返し「CrashLoopBackOff」のステータスになっています。2.Node2にスケジューリングされた野良Pod2つ「mem-exp-grxvz」と「mem-exp-v5j29」は再起動されることもなく順調に稼働しています。3.マニュフェストでメモリの使用量をあらかじめ宣言したPod4つ「reqest-exp-9kztw」は再起動されることなく3つが稼働中、そして空き容量待ち「reqest-exp-fgrpn」はPenddingでお行儀よく待っていること分かります。Requestsでメモリを記述しないと、「Podがいつメモリ不足で終了されても構わない」という意味になります。(QoS)クラスを提供しています。Limitsの2つから次の条件でclassが決まります。describeでできます。「mem-exp-96vdn」のQoSを確認するときは次のコマンドになります。BestEffortちなみにpod内に複数のコンテナが存在する場合はまず各コンテナに上記のルールに従ってQoSを割り当てます。全てのコンテナがBestEffortならPodのQoSはBestEffortとなり、全てのコンテナがGuaranteedならPodのQoSはGuaranteedになるとのことです。いずれの条件にも当てはまらない場合BestEffortになるとのことです。Requestsを指定したPodのQoSは「Burstable」、なにも指定しない野良Podは「BestEffort」が設定されていました。Nodeのメモリ上限に達した場合、どういった判断でkillされるかKubernetesクラスタは魔法の箱ではないので、実際のメモリを超えるアプリは実行できません。今回の検証のNode1でなにがおきていたかというと。Kubernetesでは、QoSに従ってどのPodのコンテナがkillされるか決まります。優先度が低く最初にkillされるのはBestEffort、つぎにはBurstable、最後にGuaranteedがkillされます。processがメモリを必要とした場合のみkillされます。scoreのよってどのプロセスをkillするかを比較して決めているようです。適当にkillしているわけではなく、Kubernetesはちゃんと忖度しながらkillしています。今回の検証では、メモリが足りていないNode0上で、優先度の低い野良Podがkillされ、再起動されていました。この再起動のルールも、実はとても興味深い処理方式で動いています。こちらは後日別ブログで。まとめKubernetesでは、アプリケーション(コンテナ)が使うメモリに制限をかけると、クラスタ上の理論的なリソースが配分されてPodがスケジューリングされることがわかりました。Podの優先度が高くなり、クラスタの実際の使用メモリが多くなったときも、killされる可能性が低くなることが分かりました。検証していませんが、ServiveやIngressでサービスディスカバリーを定義しておけば、今回のケースではいずれかのPodは動いているはずですので、クラスタ外部からのアクセスをみてみると、サービスが正しく動作している状態を維持できているはずです。Limitsを与えたときの動きや、CPUに関しても後日ひまを見つけて検証してまとめてみたいと思います。いうわけで、クラウドのKubernetesマネージドサービスを使うと、クラスタそのものの構築やMasterのメンテはお任せできますので、分散基盤のめんどうがみられるレベルのインフラエンジニアがいなくても、快適なデプロイ環境を作れますが、一方、、、知識としてのインフラ技術は、ある程度勉強しておかないと、障害時に中でなにがおこっているのか、だけでなく適切な基盤方式設計ができない、ということにもなります。難しいですが勉強だいじ。17:18Kubernetesで実際のメモリを超えるコンテナアプリを動かすと、どうなるか?Tweet広告を非表示にする関連記事2018-04-02Kubernetesはクラスタで障害があったとき、どういう動きをするのかKubernetesは、コンテナアプリケーションをデプロイするための...2017-12-19自宅PCクラスタのKubernetesを1.9にバージョンアップしたログ我が家の自宅PCクラスタ自宅並列計算機のOSがUbuntu16.04だった...2017-12-15TensorFlowをKubernetesで分散学習するためのKubeFlowを動かしてみた話Kubernetesが機械学習基盤としてKubeflowをリリースしました。ASA.はてなブログをはじめよう!dr_asaさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。