【翻訳記事】Kubernetes(クーベネティス)ネットワークに対する理解:Pod

最終更新日:2019年8月15日

レバテックキャリアは
ITエンジニア・Webクリエイター専門の転職エージェントです

Mark Betz氏がブログで投稿した記事「Understanding kubernetes networking: pods (Posted Oct 27, 2017)」を翻訳してご紹介しています。
なお、この記事は原著者の許諾を得て翻訳・掲載しています。



この記事の目的は、Kubernetesのクラスタで動作するネットワーキングの複数のレイヤーをわかりやすく説明することです。Kubernetesは、多くのインテリジェントデザインの選択を可能にする強力なプラットフォームですが、Podネットワーク、サービスネットワーク、クラスタIP、コンテナポート、ホストポート、ノードポートなど、物事がどのようにやりとりを行っているかを説明すると混乱を招く可能性があります。実際、退屈して目に生気がなくなる人を何人か見てきました。この話題について話すのは主に仕事中です。例えば、何かが壊れてしまってそれを修正したいため、一度にすべてのレイヤーを縦断したいときです。少し時間をかけて各レイヤーの仕組みを理解すると、それらはすべて優雅な手法であり、理にかなっていることがわかります。

集中しやすくするために、記事を3つのパートに分割します。最初のパートでは、コンテナとPodについて説明します。2番目のパートでは、Podを一時的なものにする抽象的なレイヤーであるサービスについて説明します。最後の記事では、ingressとクラスタ外からPodへのトラフィックについて説明します。最初にいくつかの免責事項についてお話ししておきますね。この記事は、コンテナ、Kubernetes、またはPodの基本的な導入ではありません。コンテナの仕組みについてさらに知りたい方は、Dockerこちらの概要を参照してください。Kubernetesのハイレベルな概要についてはこちら、Podの具体的な概要についてはこちらを参照してください。最後に、ネットワーキングIPアドレス空間に関する基本的な知識が役立つでしょう。

 

Pod

Podとは何でしょうか?Podとは、同じホスト上に配置された1つ以上のコンテナで構成され、ネットワークスタックやボリュームといった他のリソースを共有するように設定されているものです。Podは、Kubernetesアプリケーションを構築している基本単位です。「ネットワークスタックを共有する」というのは実際にはどういう意味でしょうか?実際面では、Pod内のすべてのコンテナ同士が、localhostを使用して相互に通信できることを意味します。nginxを実行していてポート80でlistenしている(待ち受け状態の)コンテナと、scrapydを実行している別のコンテナがある場合、2番目のコンテナは、http://localhost:80のように最初のコンテナに接続することができます。しかし、それはどのような形で機能するのでしょうか?ローカルマシン上でDockerコンテナを起動する場合の典型的な状況を見てみましょう。

上から下へと説明すると、物理ネットワークインタフェースであるeth0があります。eth0にはブリッジのdocker0が付いており、docker0には仮想ネットワークインタフェースであるveth0が付いています。docker0とveth0は両方とも同じネットワーク上(この例では172.17.0.0/24)にあることに留意してください。このネットワークでは、docker0には172.17.0.1が割り当てられ、veth0には172.17.0.2が割り当てられています。docker0はveth0のデフォルトゲートウェイです。コンテナの起動時にネットワークネームスペースがどのように設定されているかによって、内部のプロセスはveth0のみを参照し、docker0とeth0を介して外部と通信します。もう一つ留意すべきことは、現在Dockerをインストールすると、これらはすべてデフォルトでipv6アドレスになりますが、この記事ではわかりやすいようにipv4を使っているということです。ipv6は未だ頭痛の種だからです。今度は2番目のコンテナを起動しましょう。

上の画像のように、2番目のコンテナは、同じdocker0ブリッジに接続された新しい仮想ネットワークインタフェースveth1を取得します。このインターフェースには172.17.0.3が割り当てられているため、ブリッジと最初のコンテナと同じロジカルネットワーク上にあります。何らかの形で他のコンテナのIPアドレスを検出できる限り、両方のコンテナはブリッジを介して通信することができます。それはわかるのですが、この説明ではKubernetesのPodの「共有ネットワークスタック」を本当の意味で理解することはできません。幸運なことに、ネームスペースは非常に柔軟です。Dockerはコンテナを開始することができ、新しい仮想ネットワークインタフェースを作成するのではなく、既存のインターフェースを共有するように指定します。この場合、上の図が少し変化します。

今度は、2番目のコンテナが、前回の例のようにveth1を取得するのではなく、veth0を参照しています。これにはいくつかの意味があります。第一に、両方のコンテナが172.17.0.2の外部からアドレス可能であり、内部では各コンテナがlocalhost上で開いているポートにアクセスできるということです。これはまた、2つのコンテナが同じポートを開くことができないことも意味しています。これは制限ですが、1つのホスト上で複数のプロセスを実行する場合と何ら違いはありません。このようにして、一連のプロセスでは、コンテナのデカップリングと隔離を最大限に活用すると同時に、可能な限りシンプルなネットワーキング環境で共同作業を行うことができます。

Kubernetesは、他のコンテナにネットワークインタフェースを提供することだけが目的である各Pod向けの特別なコンテナを作成することによって、このパターンを実装します。PodがスケジュールされたKubernetesクラスタノードにSSHで接続し、docker psを実行すると、pauseコマンドで開始されたコンテナが少なくとも1つ表示されます。pauseコマンドは、シグナルが受信されるまで現在のプロセスを中断するため、KubernetesがSIGTERMを送信するまで、これらのコンテナはスリープ以外何もしません。活動が止まるにもかかわらず、「pause」コンテナはPodの中心であり、他のすべてのコンテナが相互におよび外界と通信するために使用する仮想ネットワークインタフェースを提供します。そのため、仮説に基づいたPodのようなものにおいては、先ほどの画像は以下のように変化します。

Podのネットワーク

これはなかなか素晴らしいですが、相互に通信できるコンテナでいっぱいになっているPodを見ても、システムについて理解できるわけではありません。次の記事でサービスについてお話しするのでさらに明確になると思いますが、Kubernetesの設計の中心は、Podが同じlocalhostまたは別々のホストで実行しているかどうかにかかわらず、Podが他のPodと通信できることです。これがどのように行われるかを見るには、レベルを上げてクラスタ内のノードを見る必要があります。このセクションには、ネットワークルーティングとルートに関する不幸な参照が含​​まれています。これは、すべての人類が避けたいと思っている主題であることはわかっています(ネットワークルーティングとルートに関する説明は非常に複雑なため)。IPルーティングに関する明確で簡潔なチュートリアルを見つけるのは難しいですが、きちんとしたレビューが欲しい場合は、Wikipediaの記事がそこまでひどくないのでお勧めです。

Kubernetesクラスタは、1つ以上のノードで構成されています。ノードは、コンテナランタイムとその依存関係(主にDocker)、および複数のKubernetesシステムコンポーネントを持つ、物理的または仮想的なホストシステムであり、クラスタ内の他のノードに到達できるようにネットワークに接続されています。2つのノードの単純なクラスタは、以下のようになります。

GCPやAWSのようなクラウドプラットフォームでクラスタを実行している場合、上の画像は、単一のプロジェクト環境のデフォルトネットワークアーキテクチャとかなり似通ったものになります。この例では説明しやすくするためにプライベートネットワーク10.100.0.0/24を使用しているため、ルーターは10.100.0.1で、2つのインスタンスはそれぞれ10.100.0.2と10.100.0.3になります。このセットアップが与えられると、各インスタンスはeth0上の他のインスタンスと通信することができます。それは素晴らしいことですが、先ほどのPodはこのプライベートネットワークにはないことを思い出してください。そのPodは、全く別のネットワーク上のブリッジにぶら下がっており、それは仮想であり、特定のノード上にのみ存在します。このことを明確にするために、Podのようなものを画像に戻してみましょう。

左側のホストには10.100.0.2のアドレスを持つインターフェースeth0があり、そのデフォルトゲートウェイは10.100.0.1のルーターです。そのインターフェースにはアドレス172.17.0.1のブリッジdocker0が接続され、ブリッジdocker0にはアドレス172.17.0.2のインターフェースveth0が接続されています。veth0インターフェースは、pauseコンテナを使用して作成され、共有ネットワークスタックのおかげで3つのコンテナのすべてに表示されます。ブリッジの作成時にローカルルーティングルールが設定されているため、172.17.0.2の宛先アドレスを持つeth0に到着するパケットは、ブリッジに転送され、ブリッジはそれをveth0に送信します。ここまでOKですね。このホストの172.17.0.2にPodがあることがわかっている場合、ルーターにそのアドレスの次のホップを10.100.0.2に設定するルールを追加することができ、そこからveth0に転送されます。やりましたね!もう一方のホストを見てみましょう。

右側のホストには10​​.100.0.3のアドレスを持つeth0があり、そのeth0は10.100.0.1の同じデフォルトゲートウェイを使用しています。eth0には172.17.0.1のアドレスを持つdocker0ブリッジが接続されています。うーん。これは問題ですね。このアドレスは、実際にはホスト1の他のブリッジと同じではないかもしれません。これは病理学的に最悪のケースなので、あえてアドレスを同じにしてみました。単にDockerをインストールして、そのままにしておくなら、うまくいく可能性もあります。しかし、選択されたネットワークが異なっていたとしても、このことは根本的な問題を強調しています。つまり、ノードは通常、別のノード上のブリッジに割り当てられたプライベートアドレス空間を知らないという問題です。パケットを送信して適切な場所に到着させるためには、明らかに何らかの構造が必要であることを知っておく必要があります。

Kubernetesはその構造を2種類の方法で提供します。一つ目は、各ノードのブリッジに全体のアドレス空間を割り当て、ブリッジが構築されているノードに基づいて、その空間内のブリッジアドレスを割り当てる方法です。二つ目は、10.100.0.1のゲートウェイにルーティングルールを追加して、各ブリッジ宛てのパケットをどのようにルーティングするか(つまり、ブリッジがどのノードのeth0に到達できるか)を指示する方法です。仮想ネットワークインタフェース、ブリッジ、ルーティングルールのこのような組み合わせを、通常、オーバーレイネットワークと呼びます。Kubernetesについて話すとき、私は通常このネットワークを「Podネットワーク」と呼んでいます。なぜなら、これは、Podが任意のノードで前後に通信できるようにするオーバーレイネットワークだからです。以下は、上の画像にKubernetesが動作した状態を追加したものです。

目を引くであろうことは、ブリッジの名前を「docker0」から「cbr0」に変更したことです。Kubernetesは標準のDockerブリッジデバイスを使用しておらず、「cbr」は「カスタムブリッジ」の略です。何がカスタムかはあまりよく知りませんが、これは、Kubernetesを実行しているDockerとデフォルトインストールの重要な違いの一つです。また、この例のブリッジに割り当てられたアドレス空間は10.0.0.0/14であることに留意してください。これは、当社のGoogle Cloudのステージングクラスタの一つであるため、現実的な例です。あなたのクラスタにはまったく異なるレンジ(範囲)が割り当てられているでしょう。残念ながら、現時点ではkubectlユーティリティーを使用してこれを公開する方法はありませんが、GCPでgcloud container clusters describe コマンドを実行してclusterIpV4Cidrプロパティを検索することができます。

一般的に、このネットワークがどのように機能するかについて考える必要はありません。ほとんどの場合、Podは、サービスの抽象化を通じて別のPodと通信します。サービスの抽象化とは、次回の記事で詳しく説明するソフトウェア定義プロキシの一種です。しかし、Podネットワークアドレスはログにポップアップ表示され、デバッグする際やその他のシナリオでは、このネットワークを明示的にルーティングする必要があるかもしれません。例えば、KubernetesのPodから10.0.0.0/8のレンジ(範囲)にある任意のアドレスに向かうトラフィックは、デフォルトではNAT(ネットワークアドレス変換)になっていないため、その範囲内の別のプライベートネットワーク上のサービスと通信する場合は、パケットをPodに戻すルールを設定する必要があります。この記事を読んで、このようなシナリオを正しく動作させるために正しい手順を踏めるようになることを祈っています。

【アップデート】パート2を公開しました。

Kubernetes(クーベネティス)ネットワークに対する理解:サービス

Mark Betz
Olark 社のSRE。夫、3人の賢い子どもたち、2匹のやんちゃな犬、1匹の怒りっぽい猫の父親。



CREDIT:原著者の許諾のもと翻訳・掲載しています。

[原文]Understanding kubernetes networking: pods (Posted Oct 27, 2017) by Mark Betz
 


プロのアドバイザーがあなたのお悩みや疑問にお答えします

- 転職個別相談会開催中 -

相談内容を選択してください

※転職活動や求人への応募を強制することはありません

内定率が高い

関連する記事

人気の記事

スキルアップ記事トップへ