2014年9月1日月曜日

[Kubernetes] サンプルのマニフェストファイル(?)を触る

[Kubernetes] サンプルのマニフェストファイル(?)を触る

ユーザとしてKubernetesをさわろうと思うと、Pod等の設定を書いたマニフェストファイルが大切になってきます。 今日はマニフェストファイルを触っていきます。
途中色々解説っぽいのを書いていみますが、ちょっと概念レベルで合っているか際どいので 間違ってたら教えてくだしぃ
まずマニフェストファイルを触る前に色々Kubernetes上のリソースや、役割の話をまとめます。 なお書いているのはユーザとして必要部分だけです。

Pod、Label、Service、ReplicationController

Kubernetesでは同一ホスト上に配置される(予定の)管理対象のコンテナをまとめたものを Pod と呼んでいます。 Pod(s) は同一ホスト上に配置されるので、ネットワークやストレージを共有していて、
データ共有やデプロイ、スケーリングがしやすくなっているらしいです。 将来的にはCPUやメモリーについてもシェアするような形になるようです。
Pod は Label によりキーバリュー形式でゆるく役割が定義されます。 これある程度自由に設定することができて例えばenvenvironment=devとか、environment=productionとか付けます。
また特定の Label (nameラベル) は Label Selector を利用してKubernetes内の別リソースから特定の Pod を判別するために利用されます。 現状(2014/09/01現在)だと、2つのKubernetes内で利用するリソースが Label Selector を使って管理対象の Pods を判別しています。
  • service
  • replicationController

service

service は Proxy と呼ばれる全minion(worker node)上で動作するNetwork Proxyの設定単位で、 複数(or 単一)の Pods に対して設定されます。 単純に pod に対するLoad Balancerと捉えても良いようです。
service はKubernetes APIとマニフェストファイルを利用して定義することができ、 Proxy は各Node上でport forwardやLoad Balancerの役割をします。 また service を作成しておくと、DockerのLink機能のように service のEndpointsを示した環境変数がコンテナ内に設定されます。 コレを使うことで コンテナ間の通信を行うことができます。
※あとでサンプルのマニフェストファイル触る時に出てきます。

replicationController

replicationController は管理対象の pod のレプリカ数を設定します。 もし pod が設定よりも多すぎる場合は レプリカをkillし、少なすぎるときは立ち上げます。
replicationControllerもKubernetes APIとマニフェストファイルを利用して定義することができます。
※あとでサンプルのマニフェストファイル触る時に出てきます。

サンプルのマニフェストファイルを触ってみる

では上記を踏まえて、サンプルのマニフェストファイルを触ってみたいと思います。 前回同様GCE上のkubernetesを使います。
なお前回の操作通りkubernetesのレポジトリは落としてあるものとします。 なおkubernetes上のファイルはjson形式ですがこのブログ内では気分的にyamlに変換してやっていきます。

GuestBook

GuestBookサンプルは Kubernetes上にweb frontendとredis master, redis slaveを利用したwebアプリケーションを配置します。

1. redis masterを作成

{kubernetes repository}/examples/guestbook/redis-master.jsonにある pod 用のマニフェストファイルを利用して redis master podを作成します。
---
id: "redis-master-2"
kind: "Pod"
apiVersion: "v1beta1"
desiredState: 
  manifest: 
    version: "v1beta1"
    id: "redis-master-2"
    containers: 
      - 
        name: "master"
        image: "dockerfile/redis"
        ports: 
          - 
            containerPort 6379
            hostPort: 6379
labels: 
  name: "redis-master"
このマニフェストファイルを元にpodsを作成するには以下のようにします。
$ cluster/kubecfg.sh -c examples/guestbook/redis-master.json create pods
※yamlの場合は以下
$ cluster/kubecfg.sh -c examples/guestbook/redis-master.yaml create pods
作成したらできているか確認してみましょう。
$ cluster/kubecfg.sh list pods

Name                Image(s)            Host          Labels
----------          ----------          ----------    ----------
redis-master-2      dockerfile/redis    kubernetes-minion-1.c.xxx.internal/   name=redis-master
さらに対象のhostにsshしてdockerコンテナがいるか確認します。 ※ホストはkubernetes-minion-1~4のいずれになるかはkubernetesが決めます。
$ gcutil ssh kubernetes-minion-1

...

me@kubernetes-minion-1:~$ sudo docker ps

コンテナ ID        IMAGE                     COMMAND                CREATED             STATUS              PORTS                    NAMES
cd3ee7527a6e        dockerfile/redis:latest   "redis-server /etc/r"   5 minutes ago       Up 5 minutes                                 k8s--master.63c98966--redis_-_master_-_2.etcd--ec7962dd
d2b99f5fe341        kubernetes/pause:latest   "/pause"               6 minutes ago       Up 6 minutes        0.0.0.0:6379->6379/tcp   k8s--net.51c76ba5--redis_-_master_-_2.etcd--6f81e245 
afc5600f4847        google/cadvisor:latest    "/usr/bin/cadvisor" -   18 minutes ago      Up 18 minutes                                k8s--cadvisor.1207d44b--cadvisor_-_agent.file--7a465a8e
e7fc2ae970ef        kubernetes/pause:latest   "/pause"               18 minutes ago      Up 18 minutes       0.0.0.0:4194->8080/tcp   k8s--net.46426d55--cadvisor_-_agent.file--fd866202   
podsを追加したことでdockerコンテナが立ち上がりました。

[寄り道]kubecfg.sh

前回から利用しているkubecfg.shはKubenetes Master Server上にあるAPI Serverを叩くためのCLIで、 細かい説明は以下にあります。
kubecfg command line interface そのうち細かく書きたいと思います。

2. redis-masterに対するservice を設定

redis-masterに他のコンテナがアクセスできるようにserviceを設定します。 serviceを設定することで他のコンテナは環境変数経由でIPやポートを取得できます。 またservicepodのラベルによりLoad Balance対象のコンテナを見つけます。
今回は 1. で立ち上げたredis-masterにserviceを適用します。 kubecfg.sh list podsの際に表示されたようにredis-masterにはname=redis-masterというラベルが付いているので これを使ってservicepodを特定させます。
以下はserviceのマニフェストファイルです。
examples/guestbook/redis-master-service.jsonにjson版が置いてあります。
id: redismaster
kind: Service
apiVersion: v1beta1
port: 10000 #redismasterへのport port forwardされる
selector: # label-selector 
  name: redis-master #name=redis-masterを指定
このマニフェストファイルを元にserviceを作成します。
$ cluster/kubecfg.sh -c examples/guestbook/redis-master-service.json create services
$ cluster/kubecfg.sh list services

Name                Labels              Selector            Port
----------          ----------          ----------          ----------
redismaster                             name=redis-master   10000
serviceを作成すると各minon上のservice proxyが特定ポート(今回は10000番)へのproxyを設定します。

3. Slave redis serverのレプリケーションを設定する。

redis-masterは単一構成のpodにしましたが、redis-slaveはreplacated podにします。 Kubernetesのreplication controllerを使って複数のpodを管理します。
examples/guestbook/redis-slave-controller.json
id: "redisSlaveController"
kind: "ReplicationController"
apiVersion: "v1beta1"
desiredState: 
  replicas: 2 #replica数
  replicaSelector: #label selector
    name: "redisslave" #nameがredisslaveのものを指定 ※↓で設定する
  podTemplate: #立ち上げるpodのテンプレート
    desiredState: 
      #この書式は今のところGCEのコンテナ-optimized Google Compute Engine imagesのmanifestの書式と一緒らしい
      #https://developers.google.com/compute/docs/containers/コンテナ_vms
      manifest: 
        version: "v1beta1"
        id: "redisSlaveController"
        containers: 
          - name: "slave"
            image: "brendanburns/redis-slave"
            ports: 
              - containerPort 6379
                hostPort: 6380
    labels: #podsのラベル selectorで設定しているものと揃える
      name: "redisslave"
labels:  #replication controllerのラベル
  name: "redisslave"
replication controllerも他のと同様にkubecfg.sh経由で作成します。
$ cluster/kubecfg.sh -c examples/guestbook/redis-slave-controller.json create replicationControllers
$ cluster/kubecfg.sh list replicationControllers
Name                   Image(s)                   Selector            Replicas
----------             ----------                 ----------          ----------
redisSlaveController   brendanburns/redis-slave   name=redisslave     2
Replication Controllerを作成したことでpodも作成されます。 replicasに2を設定していたのでコンテナが2つ起動していますね。
$ cluster/kubecfg.sh list pods

Name                                   Image(s)                   Host                                                  Labels
----------                             ----------                 ----------                                            ----------
redis-master-2                         dockerfile/redis           kubernetes-minion-1.c.xxx.internal/   name=redis-master
b6a84339-3195-11e4-add7-42010af08c6e   brendanburns/redis-slave   kubernetes-minion-2.c.xxx.internal/   name=redisslave,replicationController=redisSlaveController
b6a98098-3195-11e4-add7-42010af08c6e   brendanburns/redis-slave   kubernetes-minion-3.c.xxx.internal/   name=redisslave,replicationController=redisSlaveController

````

今回はredis-slaveを作成したので実際手で作成した場合は、masterのホスト名とIPを元に以下のコマンドで
redis-serverをslave化する必要があります。

```bash
$ redis-server --slaveof {masterのhost} {masterのポート}
では今回はどのようにこのコマンドを発行しているのでしょうか? 今回作成したコンテナはbrendanburns/redis-slave imageを使っています。 このimageは今回のGuestBook用に作成されたimageでここにDockerfileがあります。 このSlave用のDockerfileでは起動シェルを使って上記のslave化を実行しています。
examples/guestbook/redis-slave/run.sh
#!/bin/bash

redis-server --slaveof $SERVICE_HOST $REDISMASTER_SERVICE_PORT
このシェル内では$SERVICE_HOST$REDISMASTER_SERVICE_PORTという環境変数を利用しており、 これらは最初に作成したredis-master serviceを設定したことにより設定されています。
kubernetesではserviceを作成するとSERVICE_HOSTという環境変数と、 {サービス名}_SERVICE_PORTという環境変数を各コンテナに設定します。 コンテナ間で通信を行いたい場合はコレ経由でやる感じになるようです。
ついでなのでminon上のdockerコンテナ上でこれらに何が入っているか確認してみます。
[locahost]$ gcutil ssh kubernetes-minion-2

# gopathを設定してnsinitをインストールします。
[kubernetes-minion-2 ~]$ mkdir gopath
[kubernetes-minion-2 ~]$ export GOPATH=$HOME/gopath
[kubernetes-minion-2 ~]$ go get github.com/docker/libcontainer/nsinit

# redis-slaveのdockerコンテナに入ります。
[kubernetes-minion-2 ~]$ sudo su -
[root@kubernetes-minion-2 ~]$ docker ps

CONTAINER ID        IMAGE                             COMMAND                CREATED             STATUS              PORTS                    NAMES
ff08942157ca        brendanburns/redis-slave:latest   "/bin/sh -c /run.sh"   33 minutes ago      Up 33 minutes                                k8s--slave.235d34e8--b6a84339_-_3195_-_11e4_-_add7_-_42010af08c6e.etcd--99fa10ac
4fca8cb8fa7b        kubernetes/pause:latest           "/pause"               35 minutes ago      Up 35 minutes       0.0.0.0:6380->6379/tcp   k8s--net.4c806b9d--b6a84339_-_3195_-_11e4_-_add7_-_42010af08c6e.etcd--18b93e89
25b59ba9cb8a        google/cadvisor:latest            "/usr/bin/cadvisor" -   2 hours ago         Up 2 hours                                   k8s--cadvisor.1207d44b--cadvisor_-_agent.file--dd2c9459
7bf60938f39a        kubernetes/pause:latest           "/pause"               2 hours ago         Up 2 hours          0.0.0.0:4194->8080/tcp   k8s--net.46426d55--cadvisor_-_agent.file--bf4b5b15

[root@kubernetes-minion-2 ~]$ cd /var/lib/docker/execdriver/native/ff*
[root@kubernetes-minion-2 ff*]$ nsinit exec /bin/bash
[root@ff** ~] env

#省略

REDISMASTER_PORT_0_TCP_PORT=10000
REDISMASTER_PORT_0_TCP=tcp://kubernetes-minion-2.c.xxx.internal:10000
REDISMASTER_PORT=tcp://kubernetes-minion-2.c.xxx.internal:10000
REDISMASTER_SERVICE_PORT=10000
SERVICE_HOST=kubernetes-minion-2.c.xxx.internal
REDISMASTER_PORT_0_TCP_ADDR=kubernetes-minion-2.c.xxx.internal
REDISMASTER_PORT_0_TCP_PROTO=tcp
確かにSERVICE_HOSTREDISMASTER_SERVICE_PORTが設定されているようです。

4. redis-slaveに対するservice を設定

次にmaster同様にslaveにもserviceを設定します。 今回の 場合このserviceは各Slaveに対するLoad Balancerとして機能します。
examples/guestbook/redis-slave-service.json
id: "redisslave"
kind: "Service"
apiVersion: "v1beta1"
port: 10001
labels: 
  name: "redisslave"
selector: 
  name: "redisslave"
同じようにserviceを作成します。
$ cluster/kubecfg.sh -c examples/guestbook/redis-slave-service.json create services

5. Frontendのpodを作成する

最後にfrontendのpodを作成します。 今回はシンプルなPHP Server(with Nginx)です
複数台のfrontendにするためにreplication controllerとして作ります。
examples/guestbook/frontend-controller.json
id: "frontendController"
kind: "ReplicationController"
apiVersion: "v1beta1"
desiredState: 
  replicas: 3
  replicaSelector: 
    name: "frontend"
  podTemplate: 
    desiredState: 
      manifest: 
        version: "v1beta1"
        id: "frontendController"
        containers: 
          - name: "php-redis"
            image: "brendanburns/php-redis"
            ports: 
              - containerPort: 80
                hostPort: 8000
    labels: 
      name: "frontend"
labels: 
  name: "frontend"
そして作成します。
$ cluster/kubecfg.sh -c examples/guestbook/frontend-controller.yaml create replicationControllers
Name                 Image(s)                 Selector            Replicas
----------           ----------               ----------          ----------
frontendController   brendanburns/php-redis   name=frontend       3
podsが作成されたことを確認します。
$ kubecfg.sh list pods
Name                                   Image(s)                   Host                                                  Labels
----------                             ----------                 ----------                                            ----------
redis-master-2                         dockerfile/redis           kubernetes-minion-1.c.xxx.internal/   name=redis-master
b6a84339-3195-11e4-add7-42010af08c6e   brendanburns/redis-slave   kubernetes-minion-2.c.xxx.internal/   name=redisslave,replicationController=redisSlaveController
b6a98098-3195-11e4-add7-42010af08c6e   brendanburns/redis-slave   kubernetes-minion-3.c.xxx.internal/   name=redisslave,replicationController=redisSlaveController
d1daf55d-31a9-11e4-add7-42010af08c6e   brendanburns/php-redis     kubernetes-minion-3.c.xxx.internal/   name=frontend,replicationController=frontendController
d1db3b5f-31a9-11e4-add7-42010af08c6e   brendanburns/php-redis     kubernetes-minion-4.c.xxx.internal/   name=frontend,replicationController=frontendController
d1db4ff2-31a9-11e4-add7-42010af08c6e   brendanburns/php-redis     kubernetes-minion-1.c.xxx.internal/   name=frontend,replicationController=frontendController
これでfrontendが起動したのでhttpで確認といきたいところですが、 GCEがデフォだと対象ポートが開いていないのであけます。
$ gcutil addfirewall --allowed=tcp:8000 --target_tags=kubernetes-minion kubernetes-minion-8000
開けたらinstanceのIPアドレスを確認してfrontを確認してみます。
$ gcutil listinstances

+---------------------+--------------+---------+----------------+-----------------+
| name                | zone         | status  | network-ip     | external-ip     |
+---------------------+--------------+---------+----------------+-----------------+
| kubernetes-master   | asia-east1-a | RUNNING | 10.1.140.110 | 1.2.3.4 |
+---------------------+--------------+---------+----------------+-----------------+
| kubernetes-minion-1 | asia-east1-a | RUNNING | 10.1.216.160 | 5.6.7.8 |
+---------------------+--------------+---------+----------------+-----------------+
| kubernetes-minion-2 | asia-east1-a | RUNNING | 10.1.126.109 | 9.10.11.12   |
+---------------------+--------------+---------+----------------+-----------------+
| kubernetes-minion-3 | asia-east1-a | RUNNING | 10.1.65.27   | 13.14.15.16  |
+---------------------+--------------+---------+----------------+-----------------+
| kubernetes-minion-4 | asia-east1-a | RUNNING | 10.1.245.66  | 17.18.19.20  |
+---------------------+--------------+---------+----------------+-----------------+
確認したらpodsが起動しているminionのexternal-ipにアクセスします。
http://5.6.7.8:8000
いかが確認できれば終了です。 各frontend serverからアクセスして同じデータを見れいることも確認してみてください。
なおKubernetesではこれらのfrontend serverのLoad Balancerはそれぞれのプラットフォームのものを利用するようで、 serviceを作成することで一緒に作成することも可能です。
この辺りの話は次回書きたいと思います。

まとめ

結構色々出てきましたが、利用する観点で言えば pod、service、replicationControllerを抑えておけばなんとなくは大丈夫そうな気がします。
次回は自作で色々やっていってみます。

0 件のコメント:

コメントを投稿