そんな今日この頃の技術ネタ

本家側に書くほどでもない小ネタ用

kubernetes学習その3 スケールとかB/Gデプロイとか

引き続きk8s学習話。

前回k8sでPodとServiceという概念や、その中で名前やラベルといった抽象的な表現を用いて扱うことを学んだ。

blue1st-tech.hateblo.jp

今回は実際にそれを利用してスケールしたりB/Gデプロイ的なことをしてみる。

スケールする

Manifestfile

前回はpodとserviceを単純に1対1揃えたが、今回は以下のようなManifestfileを用意した。

# service.yaml
kind: Service
apiVersion: v1
metadata:
  name: http-service
  labels:
    app: http-app
spec:
  selector:
    app: http-app
  ports:
    - port: 8080
      targetPort: http-port
  externalIPs:
    - 192.168.99.100
# pod-blue.yaml
apiVersion: v1
kind: Pod
metadata:
  name: http-blue
  labels:
    app: http-app
    color: blue
spec:
  containers:
    - name: nginx
      image: nginx:latest
      ports:
        - name: http-port
          containerPort: 80
      lifecycle:
        postStart:
          exec:
            command:
              - /bin/sh
              - -c
              - echo "<html><body>blue</body></html>" > /usr/share/nginx/html/index.html
# pod-green.yaml
apiVersion: v1
kind: Pod
metadata:
  name: http-green
  labels:
    app: http-app
    color: green
spec:
  containers:
    - name: nginx
      image: nginx:latest
      ports:
        - name: http-port
          containerPort: 80
      lifecycle:
        postStart:
          exec:
            command:
              - /bin/sh
              - -c
              - echo "<html><body>green</body></html>" > /usr/share/nginx/html/index.html

どちらのpodにも同じapp: html-appのラベルを付けているが、表示するhtmlをそれぞれ変えている。

動作チェック

ひとまず起動。

$ kubectl create -f pod-blue.yaml -f pod-green.yaml -f service.yaml
pod "http-blue" created
pod "http-green" created
service "http-service" created


適当な回数をリクエストを投げてみると、両方のpodにランダムに疎通されていることが確認できる。

$ for i in $(seq 0 10); do echo $i;curl 192.168.99.100:8080;done
0
<html><body>green</body></html>
1
<html><body>green</body></html>
2
<html><body>green</body></html>
3
<html><body>blue</body></html>
4
<html><body>blue</body></html>
5
<html><body>blue</body></html>
6
<html><body>blue</body></html>
7
<html><body>green</body></html>
8
<html><body>green</body></html>
9
<html><body>green</body></html>
10
<html><body>blue</body></html>

当然、一方のpodを停止すれば、動いている方のみにリクエストが飛ぶ。

$ kubectl delete -f pod-blue.yaml
pod "http-blue" deleted
$ for i in $(seq 0 10); do echo $i;curl 192.168.99.100:8080;done
0
<html><body>green</body></html>
1
<html><body>green</body></html>
2
<html><body>green</body></html>
3
<html><body>green</body></html>
4
<html><body>green</body></html>
5
<html><body>green</body></html>
6
<html><body>green</body></html>
7
<html><body>green</body></html>
8
<html><body>green</body></html>
9
<html><body>green</body></html>
10
<html><body>green</body></html>


このように、必要に応じてPodだけを増減させることができるわけで、付加に応じてスケールさせるなんてことを実現することができる。


Blue/Greenデプロイ

Manifestfile

先のpod-blue.yaml、pod-green.yamlを利用するような、以下のようなservice-bg.yamlを作成してみる。

# service-bg.yaml
kind: Service
apiVersion: v1
metadata:
  name: http-service
spec:
  selector:
    app: http-app
    color: green
  ports:
    - port: 8080
      targetPort: http-port
  externalIPs:
    - 192.168.99.100

selectorとしてapp項に加えてcolor項も条件に加えてみる。


動作チェック

先に記述した状態でリクエストを投げると、当然greenの側にだけ通信がいく。

$ for i in $(seq 0 10); do echo $i;curl 192.168.99.100:8080;done
0
<html><body>green</body></html>
1
<html><body>green</body></html>
2
<html><body>green</body></html>
3
<html><body>green</body></html>
4
<html><body>green</body></html>
5
<html><body>green</body></html>
6
<html><body>green</body></html>
7
<html><body>green</body></html>
8
<html><body>green</body></html>
9
<html><body>green</body></html>
10
<html><body>green</body></html>


service-bg.yamlのcolor項をblueに書き換えた上でapplyコマンドで適用すると・・・

$ kubectl apply -f service-bg.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
service "http-service" configured
$ for i in $(seq 0 10); do echo $i;curl 192.168.99.100:8080;done
0
<html><body>blue</body></html>
1
<html><body>blue</body></html>
2
<html><body>blue</body></html>
3
<html><body>blue</body></html>
4
<html><body>blue</body></html>
5
<html><body>blue</body></html>
6
<html><body>blue</body></html>
7
<html><body>blue</body></html>
8
<html><body>blue</body></html>
9
<html><body>blue</body></html>
10
<html><body>blue</body></html>

切り替わることが確認できる。


実用上の話、deployment

さて、サービス運用においては実用上は同じ内容のpodを増減させるという使い方になるだろう。

k8sではpodの上にそのスケール数なんかを管理させる概念も用意していて、古くはreplication controllerというresourceとして扱っていたのだが、最近のバージョンからはpodを管理するreplica setとそれを更に管理するdeploymentというresourceを用いる、らしい。

前回のpod.yamlに準拠して以下のようなdeployment.yamlを作成した。

# deployment.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: http-deploy
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: http-app
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - name: http-port
              containerPort: 80
          volumeMounts:
            - name: docroot
              mountPath: /usr/share/nginx/html
        - name: html
          image: busybox
          command:
            - tail
            - -f
            - /dev/null
          volumeMounts:
            - name: docroot
              mountPath: /opt/html
          lifecycle:
            postStart:
              exec:
                command:
                  - /bin/sh
                  - -c
                  - echo "<html><body>Hello k8s!</body></html>" > /opt/html/index.html
      volumes:
        - name: docroot
          emptyDir: {}

apiVersionに注意。起動する数をreplicasに記述し、template内にpodの内容を記述していく。


動作チェック

起動してみる。

$ kubectl create -f deployment.yaml -f service.yaml
deployment "http-deploy" created
service "http-service" created


deploymentが作成され

$ kubectl get deploy
NAME          DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
http-deploy   3         3         3            3           34s

reploca setが生成され

$ kubectl get rs
NAME                     DESIRED   CURRENT   READY     AGE
http-deploy-2570210715   3         3         3         1m

replicasの設定値分のpodが起動されていることが確認できる。

$ kubectl get pod
NAME                           READY     STATUS    RESTARTS   AGE
http-deploy-2570210715-lf1j3   2/2       Running   0          1m
http-deploy-2570210715-s4z8l   2/2       Running   0          1m
http-deploy-2570210715-tl63x   2/2       Running   0          1m


deployment.yamlのreplocasを2に変えて適用してみると・・・

$ kubectl apply -f deployment.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment "http-deploy" configured

実際にpodの数が変化することが分かる。

$ kubectl get pod
NAME                           READY     STATUS    RESTARTS   AGE
http-deploy-2570210715-lf1j3   2/2       Running   0          3m
http-deploy-2570210715-s4z8l   2/2       Running   0          3m


実用上はこのdeploymentを用いてpodを管理していくのが良いのだと思う。



そんな感じで、k8sの一見するとまどろっこしい概念がなぜ必要だったのかがなんとなく掴めたと思う。

実際にはGKEのNodeを動的に増減させられる機能なんかと組み合わせることで威力を発揮しそうだ。

Kubernetes Cookbook

Kubernetes Cookbook