Istio シリーズ 第12回です。
Istio は各 Pod に sidecar として Envoy コンテナを差し込み、通信の受信も送信も Envoy を経由します。アプリの更新時などに旧バージョンの Pod の停止する時、先に Envoy コンテナが停止してしまうとアプリのコンテナが通信できなくなり処理が完了できなくなったりします。開始時にもコンテナの起動順序は不定であるため起動スクリプトの調整や LivnessProbe, ReadinessProbe は重要です。
preStop フック
そこで、sidecar である Envoy が先に終了してしまわないようにするために Pod の preStop hook を活用することができます。
Envoy sidecar は istio によって deploy 時に inject されますが、どんな設定を inject するかは istio-system ネームスペースにある istio-sidecar-injector という ConfigMap に定義されています。
$ kubectl get configmap -n istio-system
NAME DATA AGE
istio 3 21d
istio-ca-root-cert 1 21d
istio-leader 0 21d
istio-security 1 21d
istio-sidecar-injector 2 21d
pilot-envoy-config 1 21d
prometheus 1 21dconfig にテンプレートなどと、そのテンプレートに渡す values という変数が入っています。
istio-sidecar-injector ConfigMap の config
| |
| |
istio-sidecar-injector ConfigMap の values
$ kubectl get configmap -n istio-system istio-sidecar-injector -o jsonpath='{.data.values}' | |
preStop hook のカスタマイズ
template の中に次のような箇所があります。よって、values でこの global.proxy.lifecycle を定義してやれば preStop hook を入れることが可能になります。
{{- if .Values.global.proxy.lifecycle }}
lifecycle:
{{ toYaml .Values.global.proxy.lifecycle | indent 4 }}
{{- end }}preStop hook にどんなコマンドを入れるかですが「本番環境のマルチテナント Kubernetes クラスタへの Istio 導入」で Istio の issue #7136 に投稿されているものが紹介されています。
| |
netstat で envoy 以外に port を listen しているプロセスが存在するかどうかを確認して、存在しなくなるまで sleep 1 して再チェックを繰り返し、存在しなくなったら終了します。その後コンテナのプロセスに対して SIGTERM が送られます。
試しに Istio 1.5 環境で netstat -plunt を実行してみると次のようになりました。pilot-agent も istio-proxy コンテナ内で実行されているため、このコマンドのままでは terminationGracePeriodSeconds (デフォルト30秒) を待っても終了せず、その2秒後に SIGTERM が送られることになります。
$ netstat -plunt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:15090 0.0.0.0:* LISTEN 18/envoy
tcp 0 0 127.0.0.1:15000 0.0.0.0:* LISTEN 18/envoy
tcp 0 0 0.0.0.0:15001 0.0.0.0:* LISTEN 18/envoy
tcp 0 0 0.0.0.0:15006 0.0.0.0:* LISTEN 18/envoy
tcp6 0 0 :::15020 :::* LISTEN 1/pilot-agentところで、netstat に -u がついてるけど grep tcp してるから意味ないな。あと、xargs って何の意味があるんだろうか??
ということで global.proxy.lifecycle に設定するのは次のようになる。kubectl edit cm istio-sidecar-injector -n istio-system で編集します。
$ kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.values}' | jq .global.proxy.lifecycle
{
"preStop": {
"exec": {
"command": [
"/bin/sh",
"-c",
"while [ $(netstat -plnt | grep tcp | egrep -v 'envoy|pilot-agent' | wc -l) -ne 0 ]; do sleep 1; done"
]
}
}
}Deployment の Pod を削除すれば新しい Pod が作成される時に新しい設定で istio-proxy が Inject されるため、kubectl get pod で確認できる。
$ kubectl get pod httpbin-deployment-v2-ccd49cc9c-5z9mt -o jsonpath='{.spec.containers[*].lifecycle.preStop}'
map[exec:map[command:[/bin/sh -c while [ $(netstat -plnt | grep tcp | egrep -v 'envoy|pilot-agent' | wc -l) -ne 0 ]; do sleep 1; done]]]Istio 導入への道シリーズ
- Istio 導入への道 (1) – インストール編
- Istio 導入への道 (2) – サービス間通信編
- Istio 導入への道 (3) – VirtualService 編
- Istio 導入への道 (4) – Fault Injection 編
- Istio 導入への道 (5) – OutlierDetection と Retry 編
- Istio 導入への道 (6) – Ingress Gatway 編
- Istio 導入への道 (7) – 外部へのアクセス / ServiceEntry 編
- Istio 導入への道 (8) – 外部へのアクセスでも Fault Injection 編
- Istio 導入への道 (9) – gRPC でも Fault Injection 編
- Istio 導入への道 (10) – 図解
- Istio 導入への道 (11) – Ingress Gateway で TLS Termination 編
- Istio 導入への道 (12) – sidecar の調整編


