Kubernetes の Deploymnets について検証した時のメモ

公式ドキュメントは以下。

[Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)

# 環境

```bash
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:03:09Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.5-eks-6bad6d", GitCommit:"6bad6d9c768dc0864dab48a11653aa53b5a47043", GitTreeState:"clean", BuildDate:"2018-12-06T23:13:14Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
```


# Deployment って何？

複数の ReplicaSet を管理する。
Deploymnet が ReplicaSets を管理し、ReplicaSets が Pod を管理する。
Deploymetn を利用することでローリングアップデートやロールバックが可能となる。

# Deployment を作成する

公式ドキュメントの以下を使う。

```nginx-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15.4
        ports:
        - containerPort: 80
```

```bash
# deployment を作成
$kubectl create -f https://k8s.io/examples/controllers/nginx-deployment.yaml
deployment.apps "nginx-deployment" created

# deployments の情報を確認.3つの Pod を要求しており、3つとも起動している
$ kubectl get deployments
NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           16s

# デプロイの状態を確認.nginx-deployment が成功した事が分かる
$kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out

# deployment によって replicasets が作成されている
$kubectl get rs
NAME                         DESIRED   CURRENT   READY     AGE
nginx-deployment-d7b764d88   3         3         3         2m

# replicasets によって3つの pod が作成されている事が分かる.今回はラベルで app=nginx をつけているのでこれで一覧が確認できる
$ kubectl get pod -l app=nginx
NAME                               READY     STATUS    RESTARTS   AGE
nginx-deployment-d7b764d88-2wr7n   1/1       Running   0          3m
nginx-deployment-d7b764d88-4zrgg   1/1       Running   0          3m
nginx-deployment-d7b764d88-9w6hz   1/1       Running   0          3m

```

# Deployment の更新

Deployment のイメージを変えてみる。

```bash
# set image コマンドで変更
$kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record
deployment.apps "nginx-deployment" image updated

# デプロイ成功
$kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out

# replicasets が2つある.0 になっている方が最初にデプロイをした時の replicasets 
$kubectl get rs
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-6fdbb596db   3         3         3         1m
nginx-deployment-d7b764d88    0         0         0         11m

# どのような挙動となっていたかは describe deployments コマンドの Events からも確認できる
$kubectl describe deployments
Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Wed, 26 Dec 2018 15:22:48 +0900
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision=2
                        kubernetes.io/change-cause=kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
Selector:               app=nginx
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx:1.9.1
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   nginx-deployment-6fdbb596db (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  13m   deployment-controller  Scaled up replica set nginx-deployment-d7b764d88 to 3
  Normal  ScalingReplicaSet  3m    deployment-controller  Scaled up replica set nginx-deployment-6fdbb596db to 1
  Normal  ScalingReplicaSet  3m    deployment-controller  Scaled down replica set nginx-deployment-d7b764d88 to 2
  Normal  ScalingReplicaSet  3m    deployment-controller  Scaled up replica set nginx-deployment-6fdbb596db to 2
  Normal  ScalingReplicaSet  2m    deployment-controller  Scaled down replica set nginx-deployment-d7b764d88 to 1
  Normal  ScalingReplicaSet  2m    deployment-controller  Scaled up replica set nginx-deployment-6fdbb596db to 3
  Normal  ScalingReplicaSet  2m    deployment-controller  Scaled down replica set nginx-deployment-d7b764d88 to 0


```

上記を見るとまず最初の Deployment:nginx-deployment-d7b764d88 を 3 にスケールアップしていることが分かる。
次のイベントからが Deployments 更新時の内容であり、順番に以下が実施されている。

+ 新しい ReplicaSet「nginx-deployment-6fdbb596db」を 1 にスケールアップ
+ 古い ReplicaSet「nginx-deployment-d7b764d88」を 2 にスケールダウン
+ 新しい ReplicaSet「nginx-deployment-6fdbb596db」を 2 にスケールアップ
+ 古い ReplicaSet「nginx-deployment-d7b764d88」を 1 にスケールダウン
+  新しい ReplicaSet「nginx-deployment-6fdbb596db」を 3 にスケールアップ
+ 古い ReplicaSet「nginx-deployment-d7b764d88」を 0 にスケールダウン

上記の挙動は「RollingUpdateStrategy」の設定によって変わる。
現在の設定は「25% max unavailable, 25% max surge」となっている。
max unavailableはアップデート中にダウンしても許容される Pod を示し、 max surge は許容する超過 Pod を示す。

# Deployment をロールバックする

まずは NG なデプロイメントを実施します。

```bash
# イメージを変更
$kubectl set image deployment nginx-deployment nginx=nginx:1.999999.1 --record
deployment.apps "nginx-deployment" image updated

# デプロイメントがスタックしている
$ kubectl rollout status deployment nginx-deployment
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...

# replica set 一覧を表示.nginx-deployment-77d66694fc が新規に作成された replica set のようにみえる
$kubectl get rs
NAME                          DESIRED   CURRENT   READY     AGE
nginx-deployment-6fdbb596db   3         3         3         23m
nginx-deployment-77d66694fc   1         1         0         1m
nginx-deployment-d7b764d88    0         0         0         33m

# pod を確認.Image の pull に失敗している
$kubectl get pods |grep nginx-deployment-77d66694fc
nginx-deployment-77d66694fc-586kl   0/1       ImagePullBackOff   0          2m

$kubectl describe pod nginx-deployment-77d66694fc-586kl

(一部略)
Events:
  Type     Reason     Age              From                                                      Message
  ----     ------     ----             ----                                                      -------
  Normal   Scheduled  4m               default-scheduler                                         Successfully assigned default/nginx-deployment-77d66694fc-586kl to ip-172-31-19-51.ap-northeast-1.compute.internal
  Normal   Pulling    2m (x4 over 4m)  kubelet, ip-172-31-19-51.ap-northeast-1.compute.internal  pulling image "nginx:1.999999.1"
  Warning  Failed     2m (x4 over 4m)  kubelet, ip-172-31-19-51.ap-northeast-1.compute.internal  Failed to pull image "nginx:1.999999.1": rpc error: code = Unknown desc = Error response from daemon: manifest for nginx:1.999999.1 not found
  Warning  Failed     2m (x4 over 4m)  kubelet, ip-172-31-19-51.ap-northeast-1.compute.internal  Error: ErrImagePull
  Warning  Failed     2m (x6 over 4m)  kubelet, ip-172-31-19-51.ap-northeast-1.compute.internal  Error: ImagePullBackOff
  Normal   BackOff    2m (x7 over 4m)  kubelet, ip-172-31-19-51.ap-northeast-1.compute.internal  Back-off pulling image "nginx:1.999999.1"

```

イメージの指定が悪かったことが分かったのでロールバックするためにまずは情報を確認。

```bash
# 対象 deployment の履歴を確認.初回は --record=true を指定していないので記録にない
$ kubectl rollout history deployment nginx-deployment
deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
3         kubectl set image deployment nginx-deployment nginx=nginx:1.999999.1 --record=true

# 特定リビジョンの詳細な確認も可能.戻す予定のリビジョンを確認
$ kubectl rollout history deployment nginx-deployment --revision 2
deployments "nginx-deployment" with revision #2
Pod Template:
  Labels:       app=nginx
        pod-template-hash=2986615286
  Annotations:  kubernetes.io/change-cause=kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
  Containers:
   nginx:
    Image:      nginx:1.9.1
    Port:       80/TCP
    Host Port:  0/TCP
    Environment:        <none>
    Mounts:     <none>
  Volumes:      <none>
```

今回は一つ前のリビジョンに戻すため、`rollout undo`を実施する。

```bash
# 一つ前のリビジョンに戻す
$kubectl rollout undo deployment nginx-deployment
deployment.apps "nginx-deployment"

# deployment 成功
$kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out

# history を見ると指定したリビジョン2は消えて4として設定されている
$kubectl rollout history deployment nginx-deployment deployments "nginx-deployment"
REVISION  CHANGE-CAUSE
1         <none>
3         kubectl set image deployment nginx-deployment nginx=nginx:1.999999.1 --record=true
4         kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
```

なお、特定リビジョンにロールバックする場合 `--to-revision` オプションを指定する。


# Deployment の停止と再開

Deployment をすぐに適用たくない場合に一時的に停止が出来る。

```bash
# 停止
$kubectl rollout pause deployment nginx-deployment
deployment.apps "nginx-deployment" paused

# ステータスでは分からず
$kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out

# describe すると分かった
$kubectl describe deployment nginx-deployment |grep Pause
  Progressing    Unknown  DeploymentPaused
```

この状態で deployment のイメージを更新してみる。

```bash
# deployment を変更
$kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.15.4 --record=true
deployment.apps "nginx-deployment" image updated

# 待機中のままとなる
$kubectl rollout status deployment nginx-deployment
Waiting for rollout to finish: 0 out of 3 new replicas have been updated...

```

進まないので再開する。

```bash
# resume する
$kubectl rollout resume deployment nginx-deployment
deployment.apps "nginx-deployment" resumed

# デプロイ終了
$kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out
```