KubernetesのPetSetでサンプルを動かす

#概要
KubernetesのPetSetの動作を自作のコンテナで理解する記事です。
Kubernetesの構築[(記事はこちら)](http://qiita.com/mmitti/items/6c1bedbcffdda6a63473)とDNSサーバーの構築[(記事はこちら)](http://qiita.com/mmitti/items/186280552f63931d9420)が完了していることが前提となります。

#PetSetについて
通常のReplication controllerなどでPodを区別なく横に並べるものではなく各Podを個別に区別し（連番のIDが振られるようです）ストレージの永続化や、固有のホスト名が与えられます。
また、Podが削除されても同じホスト名、同じストレージのマウントが保証されているようです。

![図面1.png](https://qiita-image-store.s3.amazonaws.com/0/140084/40b53636-4d73-23c2-7aa0-3f76afe16c84.png)


Pod同士で通信が必要なモノやDBなどへの利用が考えられます。

詳しくは公式のドキュメントをご覧ください。
http://kubernetes.io/docs/user-guide/petset/

#環境
DNSサーバーの構築[(記事はこちら)](http://qiita.com/mmitti/items/186280552f63931d9420)の記事の環境がベースになっています。

||masterサーバー|nodeサーバー|
|:----|:----|:----|
|ホスト名|master|node1|
|IPアドレス|192.168.137.20|192.168.137.21|
|動作しているサービス|kube-apiserver<BR>kube-controller-manager<BR>kube-scheduler<BR>kube-dns|kubelet<BR>kube-proxy|

追加でnfsサーバーを別途用意し、各ノードにnfsクライアントのインストールをしてください。  （サンプルの例はmaster上でnfsサーバーを動かしています。）

また、ドメイン名がmmitti.infoであることにも注意してください。

#構成
今回は2つのコンテナで構成されています。

- test-db  
  DBサーバ(実際はjsonファイルを読みだすだけ)  
  PetSetとして配置します  
  DockerHub上にmmitti/test-dbとしてイメージを公開しています  
- test-db-client  
  testst-dbにアクセスしてHTMLを生成したりデータをポストするWebサーバー  
  DockerHub上にmmitti/test-db-clientとしてイメージを公開しています

test-db-clientからtest-dbへのアクセスは、テストのためサービス経由でアクセスするパターンと特定のホストにアクセスするパターンを用意しています。

![図面1.png](https://qiita-image-store.s3.amazonaws.com/0/140084/33ffd596-853d-05e6-c8f6-ef44ae0815d4.png)


#サンプルコード
ここからさきで提示するyamlファイルはGithub上で公開しています。
cloneしてファイルを利用すると便利です。

https://github.com/mmitti/kube-petset-sample

ここからはクローンしたディレクトリ内で作業していると仮定してコマンドを示します。

#PersistentVolumeの作成   
PetSetのPodと接続するストレージを用意します。   

/publicフォルダーがnfsサーバ(192.168.137.20)上で共有されていて、/public以下に01,02,03フォルダーが存在する状態と仮定してPersistentVolumeを作成します。  
環境に合わせてyamlファイルを修正してください。

[pv.yaml](https://github.com/mmitti/kube-petset-sample/blob/master/pv.yaml)

```
apiVersion: v1
kind: PersistentVolume
metadata:
  name: dbpv01
  annotations:
    volume.beta.kubernetes.io/storage-class: "slow"
spec:
  capacity:
    storage: 10Mi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /public/01
    server: 192.168.137.20
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: dbpv02
  annotations:
    volume.beta.kubernetes.io/storage-class: "slow"
spec:
  capacity:
    storage: 10Mi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /public/02
    server: 192.168.137.20
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: dbpv03
  annotations:
    volume.beta.kubernetes.io/storage-class: "slow"
spec:
  capacity:
    storage: 10Mi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /public/03
server: 192.168.137.20
```

以下のコマンドでPersistentVolumeを作成します。

```
kubectl create -f pv.yaml
```

以下のコマンドで正しく作成されたか確認します。

```
kubectl get pv

NAME      CAPACITY   ACCESSMODES   STATUS      CLAIM     REASON    AGE
dbpv01    10Mi       RWX           Available                       3s
dbpv02    10Mi       RWX           Available                       3s
dbpv03    10Mi       RWX           Available                       3s
```


#コンテナの配置

最初にtest-dbを配置します。

APIサーバーのスクリプトは/db以下にdat.jsonを生成しますので/dbをマウントしています。
[test-db.yaml](https://github.com/mmitti/kube-petset-sample/blob/master/test-db.yaml)

```
apiVersion: v1
kind: Service
metadata:
  name: test-db
  labels:
    app: test-db
spec:
  ports:
  - port: 8000
    name: test-db
  clusterIP: None
  selector:
    app: test-db
---
apiVersion: apps/v1alpha1
kind: PetSet
metadata:
  name: test-db
spec:
  serviceName: "test-db"
  replicas: 2
  template:
    metadata:
      labels:
        app: test-db
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: test-db
        image: mmitti/test-db
        ports:
        - containerPort: 8000
          name: test-db
        volumeMounts:
        - name: pv
          mountPath: /db
  volumeClaimTemplates:
  - metadata:
      name: pv
    spec:
      accessModes: [ "ReadWriteMany" ]
      resources:
        requests:
storage: 5Mi
```

以下のコマンドでtest-dbを作成します。

```
kubectl create -f test-db.yaml
```

次にtest-db-clientを作成します。
APIサーバーのドメインを環境変数として渡します。

（ホスト名.サービス名.ネームスペース.ドメインで各ポッドにアクセスできるため API_PODという環境変数を用意しましたがあまり意味が無い気がします。APIと同じ値にしてください。)

[test-db-client.yaml](https://github.com/mmitti/kube-petset-sample/blob/master/test-db-client.yaml)

```
kind: ReplicationController
apiVersion: v1
metadata:
  name: test-db-client
  labels:
    app: test-db-client
spec:
  replicas: 2
  selector:
    app: test-db-client
  template:
    metadata:
      name: test-db-client
      labels:
        app: test-db-client
    spec:
      containers:
      - name: test-db-client
        image: mmitti/test-db-client
        env:
        - name: API
          value: test-db.default.svc.mmitti.info:8000
        - name: API_POD
          value: test-db.default.svc.mmitti.info:8000
---
kind: Service
apiVersion: v1
metadata:
  name: test-db-client
  labels:
    app: test-db-client
spec:
  ports:
  - name: tcp
    protocol: TCP
    port: 5000
    targetPort: 5000
  selector:
app: test-db-client
```


以下のコマンドでtest-db-clientを作成します。

```
kubectl create -f test-db-client.yaml
```

#アクセスしてみる

http://192.168.137.20:8080/api/v1/proxy/namespaces/default/services/test-db-client:5000/
にアクセスるとtest-db-clientに接続されます。

この時test-db-clientでは`環境変数APIに指定されたURL/info`にアクセスします。
この時ロードバランサー経由で接続されたいずれかのtest-dbポッドのホスト名を取得し
`room/test-dbポッドのホスト名`にリダイレクトします。

以降test-db-clientは指定されたホスト名のtest-dbと通信しデータの読み書きを行います。

`room/test-dbポッドのホスト名`の末尾の数字を0や1にして別のAPIサーバーに接続されていること、また、nfsサーバーのpublic/01とpublic/02内に生成されているjsonファイルなどを確認してみてください。

画面の詳しい見方や使い方は[GithubのReadme](https://github.com/mmitti/kube-petset-sample/blob/master/README.md)を御覧ください。

#Podを削除してみる
PetSetとして配置したPodを削除してみます。

まず削除前のpodの一覧を確認します。

```
kubectl get po -l app=test-db

NAME        READY     STATUS    RESTARTS   AGE
test-db-0   1/1       Running   0          4m
test-db-1   1/1       Running   0          4m
```
次にpodを削除してみます

```
kubectl delete po -l app=test-db
```

少し待った後podの一覧を取得してみます。

```
kubectl get po -l app=test-db

NAME        READY     STATUS    RESTARTS   AGE
test-db-0   1/1       Running   0          10s
test-db-1   1/1       Running   0          5s
```

このように削除前と同じ名前で再生成されていることがわかると思います。
また、test-db-clientのWebページにアクセスしてもAPIサーバーのjsonファイルを生成したホスト名と現在jsonファイルを読みだしているホスト名が一致していると思います。

このようにホスト名が固定されストレージも対応付けを保ったまま永続化されていることが確認できると思います。