このエントリはKubernetesアドベントカレンダー2014の2日目です。
今日はKubernetesのDesign Overviewを見ていきます。
Cluster Architecture
まずは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)
だとかを設定できます。
なお Service
や ReplicationController
にもラベルが付与できます。
Label
の使いドコロとしては、 Service
や ReplicationController
を作成する際に Label
を使って Pod
や Service
を指定することができます。
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とやりとりする場合にはなんとかしないといけません。
解決する方法としては、以下があります。
- dockerのネットワークを基盤サーバのネットワークインターフェイスにbridgeする
- OpenVSwitch with GRE/VxLAN
- 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で通信しているのでひとつひとつ紐解いていけば大丈夫です。