Kubernetesの公式チュートリアルをやってみる その7

[Kubernetesの公式チュートリアルをやってみる その6][topic-6] ではスケーリングについて扱いました。
この記事のチュートリアルでは無停止でのアップデートについて扱います。

基本事項のチュートリアルはこの内容で最後になります。

#### 注意 && disclaimer

翻訳・意訳が主目的ではないのでいろいろ端折ったりすることがあります。
明らかな間違いはしないつもりですが、何かあれば優しくツッコんであげてください。

→記事のまとめは [Kubernetesの公式チュートリアルをやってみる その1][topic-1] にあります。


## 本記事の取り扱う範囲

[Performing a Rolling Update][tutorial-6] の内容を扱います。


## Performing a Rolling Update

ローリングアップデート 関連の内容

### Rolling Updates

- kubernetes では無停止更新を `Rolling Updates` によって実現する。
    - デフォルトでは新バージョンのコンテナ Pod を1つ起動、旧 Pod を1つ停止を繰り返す。
    - 同時に行う数量、またはパーセンテージで数を変更することができる。
- 無停止更新を行う際は、アプリのレプリカが複数稼働していることが必須である。
- アプリ更新後に過去に正常に稼働していたバージョンへ戻すことができる。
- Service はアプリ更新時に `AVAILABLE` となっている Pod のみにトラフィックを振り分ける。
    - 新しいバージョンが一つ `AVAILABLE` になると古いバージョンが一つ `AVAILABLE` でなくなるイメージ。

### Interactive Tutorial

Estimate Time: 10分

- `kubectl get deployment`
    - 初期で4レプリカ起動している状態から開始する。
    - v1のイメージから作成されている
- `kubectl set image deployments/[deployment name] [container name]=[new image path]`
    - Deployment 内の対象のコンテナ定義のイメージを更新する。

```bash
$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
deployment.extensions/kubernetes-bootcamp image updated
# 新バージョンのPod起動→旧バージョンのPod破棄を繰り返す
$ kubectl get pods
NAME                                   READY     STATUS              RESTARTS   AGE
kubernetes-bootcamp-5c69669756-cs96h   1/1       Terminating         0          5m
kubernetes-bootcamp-5c69669756-dnzh9   1/1       Terminating         0          5m
kubernetes-bootcamp-5c69669756-q2h89   1/1       Terminating         0          5m
kubernetes-bootcamp-5c69669756-xfknn   1/1       Terminating         0          5m
kubernetes-bootcamp-7799cbcb86-7sd6l   1/1       Running             0          5s
kubernetes-bootcamp-7799cbcb86-94hl8   1/1       Running             0          5s
kubernetes-bootcamp-7799cbcb86-b9l9f   0/1       ContainerCreating   0          4s
kubernetes-bootcamp-7799cbcb86-v9h2x   1/1       Running             0          4s
```

- Service の確認
    - アプリ更新後にアクセスすると更新後のアプリをすでに参照している。[^1]

[^1]: チュートリアル開始時は `v=1` のレスポンスが返るようになっている

```bash
$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
$ curl $(minikube ip):$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-7799cbcb86-94hl8 | v=2
```

- `kubectl rollout status deployments/[deployment name]`
    - ローリングアップデートの状態を確認することができる。

```bash
$ kubectl rollout status deployments/kubernetes-bootcamp
deployment "kubernetes-bootcamp" successfully rolled out
# Podのイメージがv=2の内容に変更されている
$ kubectl describe pods | grep Image:
    Image:          jocatalin/kubernetes-bootcamp:v2
    Image:          jocatalin/kubernetes-bootcamp:v2
    Image:          jocatalin/kubernetes-bootcamp:v2
    Image:          jocatalin/kubernetes-bootcamp:v2
```

- 不正なアップデート時
    - ここでは存在しないイメージを指定した場合

```bash
$ kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10
deployment.extensions/kubernetes-bootcamp image updated
# 更新後のPodが2、利用可能が3と出ている
$ kubectl get deployments
NAME                  DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kubernetes-bootcamp   4         5         2            3           5m
# 新バージョンのPodを1つ作成→旧バージョンのPodを1つ破棄→新バージョンのPodを2つ目作成辺りでエラーに気づいて止まっている？
# -- ErrImagePullからしばらくするとImagePullBackOffになる
$ kubectl get pods
NAME                                   READY     STATUS             RESTARTS   AGE
kubernetes-bootcamp-5f76cd7b94-6xjs4   0/1       ErrImagePull       0          1m
kubernetes-bootcamp-5f76cd7b94-fz9kl   0/1       ImagePullBackOff   0          1m
kubernetes-bootcamp-7799cbcb86-cgh8q   1/1       Running            0          4m
kubernetes-bootcamp-7799cbcb86-nvxdv   1/1       Running            0          4m
kubernetes-bootcamp-7799cbcb86-xqndd   1/1       Running            0          4m
```

```bash
# エラーしているPodの詳細
$ kubectl describe pod kubernetes-bootcamp-5f76cd7b94-6xjs4
Name:           kubernetes-bootcamp-5f76cd7b94-6xjs4
Namespace:      default
Node:           minikube/172.17.0.115
Start Time:     Thu, 27 Sep 2018 17:56:34 +0000
Labels:         pod-template-hash=1932783650
                run=kubernetes-bootcamp
Annotations:    <none>
Status:         Pending
IP:             172.18.0.2
Controlled By:  ReplicaSet/kubernetes-bootcamp-5f76cd7b94
Containers:
  kubernetes-bootcamp:
    Container ID:
    Image:          gcr.io/google-samples/kubernetes-bootcamp:v10
    Image ID:
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Waiting              # <= 待機状態
      Reason:       ImagePullBackOff     # <= イメージがpullできなかったので
    Ready:          False                # <= 稼働準備ができていない
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-sp5hf (ro)
Conditions:
  Type           Status
  Initialized    True
  Ready          False
  PodScheduled   True
Volumes:
  default-token-sp5hf:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-sp5hf
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:                                   # <= エラーまでの流れがここで確認できる
  Type     Reason                 Age               From               Message
  ----     ------                 ----              ----               -------
  Normal   Scheduled              7m                default-scheduler  Successfully assigned kubernetes-bootcamp-5f76cd7b94-6xjs4 to minikube
  Normal   SuccessfulMountVolume  7m                kubelet, minikube  MountVolume.SetUp succeeded for volume "default-token-sp5hf"
  Normal   Pulling                5m (x4 over 6m)   kubelet, minikube  pulling image "gcr.io/google-samples/kubernetes-bootcamp:v10"
  Warning  Failed                 5m (x4 over 6m)   kubelet, minikube  Failed to pull image "gcr.io/google-samples/kubernetes-bootcamp:v10": rpc error: code = Unknown desc = unauthorized: authentication required
  Warning  Failed                 5m (x4 over 6m)   kubelet, minikube  Error: ErrImagePull
  Warning  Failed                 5m (x6 over 6m)   kubelet, minikube  Error: ImagePullBackOff
  Normal   BackOff                1m (x20 over 6m)  kubelet, minikube  Back-off pulling image "gcr.io/google-samples/kubernetes-bootcamp:v10"
```

- `kubectl rollout undo deployments/[deployment name]`
    - 更新をロールバックするコマンド。

```bash
$ kubectl rollout undo deployments/kubernetes-bootcamp
deployment.extensions/kubernetes-bootcamp
# ロールバック後、エラーのPod2つが消えて旧バージョンのPodが1つ追加されている(AGEが他と異なる)
$ kubectl get pods
NAME                                   READY     STATUS    RESTARTS   AGE
kubernetes-bootcamp-7799cbcb86-cgh8q   1/1       Running   0          13m
kubernetes-bootcamp-7799cbcb86-l4vl5   1/1       Running   0          5s
kubernetes-bootcamp-7799cbcb86-nvxdv   1/1       Running   0          13m
kubernetes-bootcamp-7799cbcb86-xqndd   1/1       Running   0          13m
```

----

## 参考リンク

- [Kubernetes公式][kubernetes]
- [Kubernetes公式チュートリアル][tutorials]

[kubernetes]:https://kubernetes.io/
[tutorials]:https://kubernetes.io/docs/tutorials/kubernetes-basics/
[tutorial-6]:https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/

[topic-1]:https://qiita.com/kitamin/items/f50fe470a04e38023f7a
[topic-2]:https://qiita.com/kitamin/items/c4902edba777f4bf4826
[topic-3]:https://qiita.com/kitamin/items/c2fb850bbf0397acd9c2
[topic-4]:https://qiita.com/kitamin/items/a7657db9689111c9e4dc
[topic-5]:https://qiita.com/kitamin/items/7b56d1c40824414ec768
[topic-6]:https://qiita.com/kitamin/items/b675cbdeb06c97fcb5fa