Kubernetes Design Overview

このエントリはKubernetesアドベントカレンダー2014の2日目です。

今日はKubernetesのDesign Overviewを見ていきます。

Cluster Architecture

まずはCluster Architectureと、その中にある図(以下)を見ながら読んでください。

Kubernetes Cluster Architecture

Pod

Kubernetesではdockerのコンテナを Pod という単位でまとめています。 Pod には関係の密な複数のコンテナを配置するもの、ということなので、1コンテナ1プロセスの原則を踏まえたうえでプロセスを集約する、仮想的なサーバのようなものだと捉えています。関係が密である前提なので、同じ Pod のコンテナは同じ基盤サーバ( Minion )に配置されます。

Service

通信のエンドポイントを既定します。

Kubernetesから Service の一覧を取得すると、 Service ごとのエンドポイントIPアドレス・ポートなどが取得できます。

[root@k8s-master1 kubernetes]# cluster/kubecfg.sh list /services
Name                Labels              Selector                                  IP                  Port
----------          ----------          ----------                                ----------          ----------
redisslave          name=redisslave     name=redisslave                           172.17.154.76       6379
...

ReplicationController

Podの多重度(3並列であるべき、など)を設定し、継続的に監視・調整します。

Kubernetesから ReplicationController の一覧を取得すると、 ReplicationController ごとの多重度が取得できます。

[root@k8s-master1 kubernetes]# cluster/kubecfg.sh list /replicationControllers
Name                   Image(s)                   Selector            Replicas
----------             ----------                 ----------          ----------
redisSlaveController   brendanburns/redis-slave   name=redisslave     2
frontendController     brendanburns/php-redis     name=frontend       3

Label

Label は、いくつかの Pod をまとめるために利用します。いくつかの Pod をまとめて env=(dev|qa|production) だとか tier=(frontend|backend) だとかを設定できます。

なお ServiceReplicationController にもラベルが付与できます。

Label の使いドコロとしては、 ServiceReplicationController を作成する際に Label を使って PodService を指定することができます。

MasterとMinion

Kubernetesは、API受付やスケジューリングなどを実施するMasterと、実際にコンテナを動かすMinionの2種類の基盤サーバで構成されます。 なおMasterとMinionは1台のサーバで兼ねることができます。

Networking

次にネットワークについて見てみます。

kubernetes/networking.md at master · GoogleCloudPlatform/kubernetes と見比べながら見るとよいとおもいます。

Podへの通信

通信のエンドポイントとなるのは Service です。 各Podの機能を利用するためには、 Service が既定したエンドポイントに向けて通信します。

Kubernetesでは、その Service ごとのエンドポイント宛の通信を kube-proxy プロセスが中継し、配下の Pod に分配します。いまのところ分配のアルゴリズムはRoundRobinだけのようです。
kubernetes/pkg/proxy at master · GoogleCloudPlatform/kubernetes

この仕組みを実現するために、iptablesのNATテーブルに作成した KUBE-PROXY チェインを使って通信を kube-proxy に集めています。

[root@k8s-minion1 ~]# iptables -nv -t nat -L KUBE-PROXY
Chain KUBE-PROXY (2 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            172.17.118.106       /* kubernetes-ro */ tcp dpt:80 redir ports 34584
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            172.17.17.77         /* kubernetes */ tcp dpt:443 redir ports 43724
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            172.17.148.137       /* redis-master */ tcp dpt:6379 redir ports 38579
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            172.17.154.76        /* redisslave */ tcp dpt:6379 redir ports 43320
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            172.17.190.33        /* frontend */ tcp dpt:80 redir ports 33993

基盤サーバをまたぐ通信

dockerのネットワークは基本的に基盤サーバ(Minion)単体で閉じているので、 他の基盤サーバ(Minion)のPodとやりとりする場合にはなんとかしないといけません。

解決する方法としては、以下があります。

  1. dockerのネットワークを基盤サーバのネットワークインターフェイスにbridgeする
  2. OpenVSwitch with GRE/VxLAN
  3. flannelでオーバーレイネットワークを組む

1.はお手軽ですがクラウド環境だと利用できないことも多いため環境を選ぶ、2.はよくわからない(私が)、ということで、3.がよく利用されているようです。

コンテナへの接続先情報の渡し方

各Serviceのエンドポイントへの接続情報は、dockerのLink機能のように環境変数でコンテナに渡されます。

{NAME}_SERVICE_HOST
{NAME}_SERVICE_BAR

例えばredis-master Serviceのエンドポイントは以下のように指定します。

$REDISMASTER_SERVICE_PORT
$REDISMASTER_SERVICE_PORT

例えばredisslave Serviceのエンドポイントは以下のように指定します。

$REDISSLAVE_SERVICE_PORT
$REDISSLAVE_SERVICE_PORT

データがコンテナにたどり着くまで

外部から Service のエンドポイントに向けて発行されたリクエストが Pod にたどり着くまでの経路を整理してみました。 たとえば redis:latest imageを使ってredisの Service を作成した場合の経路は以下のとおりのようです。

基本的にはIPで通信しているのでひとつひとつ紐解いていけば大丈夫です。

k8s-network


See also