[Kubernetes]postStart/preStopの動作を確認する

#はじめに
Kubernetesはコンテナの起動直後に任意のコマンドを実行する「postStart」と、コンテナの終了直前に任意のコマンドを実行する「preStop」ハンドラーがあります。
今回はこのpostStart/preStopの動作を確認します。

#設定
以下のマニフェストで動作を確認します。

```postStart-preStop.yaml
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
  labels:
    app: app1
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx:latest
    command: ["/bin/sh", "-c", "echo Hello from the Entrypoit >> /usr/share/message; sleep 999999"]
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", " echo Hello from the postStart handler >> /usr/share/message"]
      preStop:
        exec:
          command: ["/usr/sbin/nginx","-s","quit"]
```
postStartでは、/usr/share/messageファイルにメッセージを書き込むようにしています。
preStopでは、Podを削除する前にnginxを停止する処理を入れています。

また、postStart/preStopの他にspec.containers.commandによる通常のコマンド実行（Entrypoint）も設定しています。

#動作確認
このマニフェストをapplyします。

```
$ kubectl apply -f postStart-preStop.yaml
pod/lifecycle-demo created
```

##postStart

コンテナの/usr/share/messageの内容を確認します。

```
$ kubectl exec -it lifecycle-demo cat /usr/share/message
Hello from the Entrypoit
Hello from the postStart handler
```

Entrypoitの方が先に実行されていますね。マニュアルを確認すると以下の記載があります。

>コンテナが作成された直後にKubernetesはpostStartイベントを送信します。 ただし、コンテナのエントリーポイントが呼び出される前にpostStartハンドラーが呼び出されるという保証はありません。postStartハンドラーはコンテナのコードに対して非同期的に実行されますが、postStartハンドラーが完了するまでコンテナのKubernetesによる管理はブロックされます。
[コンテナライフサイクルイベントへのハンドラー紐付け](https://kubernetes.io/ja/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/#%e8%ad%b0%e8%ab%96)

postStartの方が先に実行される保証はないと書かれていますが、私が何回か試した限りですと常にEntrypoitの方が先に実行されていました。（実行するコマンドの影響もあるかも知れません）
postStartとEntrypointを併用する場合には、実行される順番がランダムでもよい処理を設定する必要がありそうです。常に先に実行する必要がある場合には、Init Containersの利用も考えた方がよさそうです。

[参考：[Kubernetes]Init Containersの動作を確認する](https://qiita.com/dingtianhongjie/items/8b78705cfc9126d76e2f)

##preStop
デプロイしたPodを削除します。

```
$ kubectl delete -f postStart-preStop.yaml
pod "lifecycle-demo" deleted
```

別ターミナルでPodの詳細をkubectl describeコマンドで確認します。

```
$ kubectl describe pod lifecycle-demo
Name:                      lifecycle-demo
・・・
Events:
  Type     Reason             Age   From                   Message
  ----     ------             ----  ----                   -------
  Normal   Scheduled          15m   default-scheduler      Successfully assigned default/lifecycle-demo to k8s-worker01
  Normal   Pulling            15m   kubelet, k8s-worker01  Pulling image "nginx:latest"
  Normal   Pulled             15m   kubelet, k8s-worker01  Successfully pulled image "nginx:latest"
  Normal   Created            15m   kubelet, k8s-worker01  Created container lifecycle-demo-container
  Normal   Started            15m   kubelet, k8s-worker01  Started container lifecycle-demo-container
  Normal   Killing            15s   kubelet, k8s-worker01  Stopping container lifecycle-demo-container
  Warning  FailedPreStopHook  15s   kubelet, k8s-worker01  Exec lifecycle hook ([/usr/sbin/nginx -s quit]) for Container "lifecycle-demo-container" in Pod "lifecycle-demo_default(699078ca-3f29-440e-9f01-60eb9bfb9746)" failed - error: command '/usr/sbin/nginx -s quit' exited with 1: 2020/06/06 13:38:50 [notice] 17#17: signal process started
2020/06/06 13:38:50 [error] 17#17: open() "/var/run/nginx.pid" failed (2: No such file or directory)
nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory)
, message: "2020/06/06 13:38:50 [notice] 17#17: signal process started\n2020/06/06 13:38:50 [error] 17#17: open() \"/var/run/nginx.pid\" failed (2: No such file or directory)\nnginx: [error] open() \"/var/run/nginx.pid\" failed (2: No such file or directory)\n"
```

失敗してますね。/var/run/nginx.pidがないからエラーになっています。ただ、preStopとしては実行されていることがわかりますので、preStopの動作確認としては良しとします。

ちなみに、nginxの設定を修正して/var/run/nginx.pidがある状態でPodを削除するとエラーなく終了します。ただ、Eventsにメッセージが表示されないので、preStopが実行されたのかは分からなくなります。
今回はエラーが出たので、結果としてpreStopが動作できていることが確認できました。

#まとめ
今回はpostStart/preStopの動作確認自体はあまり時間がかかりませんでしたが、nginxのエラーで時間を取られました。
また、postStartは実行される順番が保証されないので、使いどころが難しいですね。