Kubernetes in Action 筆記 —— 管理 Pod 的生命周期

理解 Pod 的狀態(tài)

Pod phase

在 Pod 完整的生命周期中卢厂,存在著 5 種不同的階段:


Pod’s phases
  • Pending:創(chuàng)建 Pod 對象后的初始化階段。會一直持續(xù)到 Pod 被分配給某個工作節(jié)點惠啄,鏡像被拉取到本地并啟動
  • Running:Pod 中至少一個容器處于運行狀態(tài)
  • Succeeded:對于不打算無限期運行的 Pod慎恒,其容器部署完成后的狀態(tài)
  • Failed:對于不打算無限期運行的 Pod,其容器中至少有一個由于錯誤終止
  • Unknown:由于 Kubelet 與 API Server 的通信中斷礁阁,Pod 的狀態(tài)未知巧号。可能是工作節(jié)點掛掉或斷網(wǎng)

kubia.yml 清單文件創(chuàng)建一個 Pod姥闭。

apiVersion: v1
kind: Pod
metadata:
  name: kubia
spec:
  containers:
  - name: kubia
    image: luksa/kubia:1.0
    ports:
    - containerPort: 8080

$ kubectl apply -f kubia.yml

查看 Pod 的 Phase

$ kubectl get po kubia -o yaml | grep phase
  phase: Running

或者借助 jq 工具從 JSON 格式的輸出中檢索 phase 字段:

$ kubectl get po kubia -o json | jq .status.phase
"Running"

也可以使用 kubectl describe 命令:

$ kubectl describe po kubia | grep Status:
Status:       Running
Pod conditions

Pod 的 conditions 用來表示某個 Pod 是否達到了特定的狀態(tài)以及達到或未達到的原因丹鸿。
與 phase 相反,一個 Pod 可以同時有幾個 conditions棚品。

  • PodScheduled:表明 Pod 是否已經(jīng)被安排給了某個工作節(jié)點
  • Initialized:Pod 的初始化容器已經(jīng)部署完成
  • ContainersReady:Pod 中的所有容器都已經(jīng)準備完畢
  • Ready:Pod 自身已經(jīng)準備好對其客戶端提供服務(wù)

查看 Pod 的 conditions

$ kubectl describe po kubia | grep Conditions: -A5
Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True

kubectl describe 命令只會顯示每個 condition 是 true 還是 false靠欢,不會顯示更詳細的信息廊敌。
為了顯示某個 condition 為 false 的具體原因,需要檢索 Pod 的清單文件:

$ kubectl get po kubia -o json | jq .status.conditions
[
  {
    "lastProbeTime": null,
    "lastTransitionTime": "2021-12-30T03:02:45Z",
    "status": "True",
    "type": "Initialized"
  },
  {
    "lastProbeTime": null,
    "lastTransitionTime": "2021-12-30T03:02:46Z",
    "status": "True",
    "type": "Ready"
  },
  {
    "lastProbeTime": null,
    "lastTransitionTime": "2021-12-30T03:02:46Z",
    "status": "True",
    "type": "ContainersReady"
  },
  {
    "lastProbeTime": null,
    "lastTransitionTime": "2021-12-30T03:02:45Z",
    "status": "True",
    "type": "PodScheduled"
  }
]

當 condition 為 false 時门怪,上述輸出中會包含 reasonmessage 字段來顯示失敗的具體原因和詳細信息骡澈。

容器的 status

容器的 status 包含多個字段。其中 state 字段表示該容器當前的狀態(tài)掷空,restartCount 表示容器重啟的頻率肋殴,此外還有 containerIDimage坦弟、imageID 等护锤。

Container status

容器的 status 包含以下幾種:

  • Waiting:容器等待啟動。reasonmessage 字段會記錄容器處于此狀態(tài)的原因
  • Running:容器已經(jīng)創(chuàng)建酿傍,進程正在運行
  • Terminated:容器中運行的進程已經(jīng)終止烙懦。exitCode 字段會記錄進程的退出碼
  • Unknown:容器的狀態(tài)無法確定

比如修改 kubia.yml 清單文件中的 image 字段,故意改成 uksa/kubia:1.0 這樣無效的地址赤炒,運行 kubectl apply -f kubia.yml 命令重新應(yīng)用清單文件氯析。
等待幾分鐘直到新的配置生效,查看容器的狀態(tài)莺褒。

可以使用 kubectl describe 命令查看容器的狀態(tài):

$ kubectl describe po kubia | grep Containers: -A15
Containers:
  kubia:
    Container ID:   docker://62fa208957d396c38f65305fd073d6b334dd8da22ab5beab196ca9bcf2f9ff91
    Image:          uksa/kubia:1.0
    Image ID:       docker-pullable://luksa/kubia@sha256:a961dc8f377916936fa963508726d77cf77dcead5c97de7e5361f0875ba3bef7
    Port:           8080/TCP
    Host Port:      0/TCP
    State:          Waiting
      Reason:       ImagePullBackOff
    Last State:     Terminated
      Reason:       Error
      Exit Code:    137
      Started:      Fri, 31 Dec 2021 14:50:39 +0800
      Finished:     Fri, 31 Dec 2021 14:51:36 +0800
    Ready:          False
    Restart Count:  0

或者使用 kubectl get po kubia -o json 命令:

$ kubectl get po kubia -o json | jq .status.containerStatuses
[
  {
    "containerID": "docker://62fa208957d396c38f65305fd073d6b334dd8da22ab5beab196ca9bcf2f9ff91",
    "image": "luksa/kubia:1.0",
    "imageID": "docker-pullable://luksa/kubia@sha256:a961dc8f377916936fa963508726d77cf77dcead5c97de7e5361f0875ba3bef7",
    "lastState": {
      "terminated": {
        "containerID": "docker://62fa208957d396c38f65305fd073d6b334dd8da22ab5beab196ca9bcf2f9ff91",
        "exitCode": 137,
        "finishedAt": "2021-12-31T06:51:36Z",
        "reason": "Error",
        "startedAt": "2021-12-31T06:50:39Z"
      }
    },
    "name": "kubia",
    "ready": false,
    "restartCount": 0,
    "started": false,
    "state": {
      "waiting": {
        "message": "Back-off pulling image \"uksa/kubia:1.0\"",
        "reason": "ImagePullBackOff"
      }
    }
  }
]

上面輸出中的 state 字段都表明了容器當前的狀態(tài)是 waiting掩缓,還有 reasonmessage 字段表明處于此狀態(tài)的原因:鏡像拉取失敗。

確保容器的健康狀態(tài)

理解容器的自動重啟機制

當一個 Pod 被分配給了某個工作節(jié)點癣朗,該工作節(jié)點上的 Kubelet 就會負責啟動容器并保證該容器一直處于運行狀態(tài)拾因,只要該 Pod 對象一直存在沒被移除旺罢。
如果容器中的主進程由于某些原因終止運行旷余,Kubernetes 就會自動重啟該容器。

創(chuàng)建如下內(nèi)容的清單文件 kubia-ssl.yml

apiVersion: v1
kind: Pod
metadata:
  name: kubia-ssl
spec:
  containers:
  - name: kubia
    image: luksa/kubia:1.0
    ports:
    - name: http
      containerPort: 8080
  - name: envoy
    image: luksa/kubia-ssl-proxy:1.0
    ports:
    - name: https
      containerPort: 8443
    - name: admin
      containerPort: 9901

運行如下命令應(yīng)用上述清單文件扁达,并啟用端口轉(zhuǎn)發(fā):

$ kubectl apply -f kubia-ssl.yml
pod/kubia-ssl created
$ kubectl port-forward kubia-ssl 8080 8443 9901
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Forwarding from 127.0.0.1:8443 -> 8443
Forwarding from [::1]:8443 -> 8443
Forwarding from 127.0.0.1:9901 -> 9901
Forwarding from [::1]:9901 -> 9901

待容器啟動成功后正卧,訪問 localhost 的 8080、8443跪解、9901 端口就等同于訪問容器中 8080炉旷、8443、9901 端口上運行的服務(wù)叉讥。

打開一個新的命令行窗口運行 kubectl get pods -w 命令窘行,實時監(jiān)控容器的運行狀態(tài)。
打開一個新的命令行窗口運行 kubectl get events -w 命令图仓,實時監(jiān)控觸發(fā)的事件罐盔。

打開一個新的命令行窗口,嘗試終止 Envoy 容器中運行的主進程救崔。Envoy 容器 9901 端口上運行的服務(wù)剛好提供了一個管理接口惶看,能夠接收 HTTP POST 請求來終止進程:

$ curl -X POST http://localhost:9901/quitquitquit
OK

此時查看前兩個窗口中的輸出捏顺,負責監(jiān)控容器狀態(tài)的窗口輸出如下:

$ kubectl get pods -w
NAME        READY   STATUS    RESTARTS   AGE
kubia-ssl   2/2     Running   0          11m
kubia-ssl   1/2     NotReady   0          12m
kubia-ssl   2/2     Running    1 (2s ago)   12m

最新的輸出表明,在殺掉 Envoy 容器中的主進程后纬黎,Pod 的狀態(tài)是先變成 NotReady幅骄,之后就立即重啟該容器,Pod 的狀態(tài)稍后恢復(fù)成 Running本今。

負責監(jiān)控最新事件的窗口輸出如下:

$ kubectl get events -w
LAST SEEN   TYPE     REASON      OBJECT          MESSAGE
11m         Normal   Scheduled   pod/kubia-ssl   Successfully assigned default/kubia-ssl to minikube
11m         Normal   Pulled      pod/kubia-ssl   Container image "luksa/kubia:1.0" already present on machine
11m         Normal   Created     pod/kubia-ssl   Created container kubia
11m         Normal   Started     pod/kubia-ssl   Started container kubia
11m         Normal   Pulled      pod/kubia-ssl   Container image "luksa/kubia-ssl-proxy:1.0" already present on machine
11m         Normal   Created     pod/kubia-ssl   Created container envoy
11m         Normal   Started     pod/kubia-ssl   Started container envoy
0s          Normal   Pulled      pod/kubia-ssl   Container image "luksa/kubia-ssl-proxy:1.0" already present on machine
0s          Normal   Created     pod/kubia-ssl   Created container envoy
0s          Normal   Started     pod/kubia-ssl   Started container envoy

最新的事件信息中包含了新的 envoy 容器啟動的過程拆座。其中有一個很重要的細節(jié):Kubernetes 從來不會重啟容器,而是直接丟棄停止的容器并創(chuàng)建一個新的冠息。一般在 Kubernetes 中提及“重啟”容器懂拾,實質(zhì)上都指的是“重建”。
任何寫入到容器文件系統(tǒng)中的數(shù)據(jù)铐达,在容器重新創(chuàng)建后都會丟失岖赋。為了持久化這些數(shù)據(jù),需要向 Pod 添加 Volume瓮孙。

配置容器的重啟策略
Kubernetes 支持 3 種容器重啟策略:

  • Always:默認配置唐断。不管容器中主進程的退出碼是多少,容器都會自動重啟
  • OnFailure:容器只會在退出碼非 0 時重啟
  • Never:容器永不重啟
Restart policy

容器重啟時的延遲時間
第一次容器終止時杭抠,重啟會立即觸發(fā)脸甘。但容器第二次重啟時會先等待 10s,這個等待時間會隨著重啟次數(shù)依次增加到 20偏灿、40丹诀、80魄咕、160s辉浦。再之后則一直保持在 5 分鐘惫皱。
等待過程中容器會處于 Waiting 狀態(tài)路翻,reason 字段顯示 CrashLoopBackOff做盅,message 字段顯示需要等待的時間敌蚜。

liveness probes

Kubernetes 會在容器的進程終止時重啟容器灵再,以保證應(yīng)用的健康边翁。但應(yīng)用實際上有可能在進程不終止的情況下無響應(yīng)啼肩,比如一個 Java 應(yīng)用報出 OutOfMemoryError 錯誤橄妆,而 JVM 進程仍在運行中。
理想情況下祈坠,Kubernetes 需要能夠檢測到此類錯誤并重啟容器害碾。

當然,應(yīng)用自身也可以捕獲這類錯誤并令進程立即終止赦拘。但假如應(yīng)用因為進入無限循環(huán)或死鎖導致無響應(yīng)慌随,又或者應(yīng)用本身無法檢測到錯誤存在呢?
為了確保容器能夠在這些復(fù)雜情況下重啟另绩,應(yīng)該提供一種從外部檢查應(yīng)用狀態(tài)的機制儒陨。

liveness probe 介紹
Kubernetes 可以通過配置 liveness probe 來檢查某個應(yīng)用是否能夠正常響應(yīng)花嘶,Pod 中的每個容器都可以分別配置 liveness probe。一旦應(yīng)用無響應(yīng)或有錯誤發(fā)生蹦漠,容器就會被認為是不健康的并被終止掉椭员。之后容器被 Kubernetes 重新啟動。

Kubernetes 支持以下三種 probe 機制:

  • HTTP GET probe:會發(fā)送 GET 請求到容器的 IP 地址笛园、端口號和 URL 路徑隘击。如果 probe 收到正常的響應(yīng)(2xx 或 3xx),該 probe 就被認定是成功的研铆。如果服務(wù)返回了一個錯誤的響應(yīng)碼埋同,或者沒有在規(guī)定的時間內(nèi)響應(yīng),則該 probe 被認定是失敗的棵红。
  • TCP Socket probe:會嘗試打開一個 TCP 連接到容器的特定端口凶赁。若連接成功,probe 就被認定是成功的逆甜;否則失敗虱肄。
  • Exec probe:會在容器內(nèi)部執(zhí)行一個命令并檢查該命令的退出碼。若退出碼為 0交煞,則 probe 被認定是成功的咏窿;否則失敗。

HTTP GET liveness probe
創(chuàng)建如下內(nèi)容的 kubia-liveness.yml 清單文件:

apiVersion: v1
kind: Pod
metadata:
  name: kubia-liveness
spec:
  containers:
  - name: kubia
    image: luksa/kubia:1.0
    ports:
    - name: http
      containerPort: 8080
    livenessProbe:
      httpGet:
        path: /
        port: 8080
  - name: envoy
    image: luksa/kubia-ssl-proxy:1.0
    ports:
    - name: https
      containerPort: 8443
    - name: admin
      containerPort: 9901
    livenessProbe:
      httpGet:
        path: /ready
        port: admin
      initialDelaySeconds: 10
      periodSeconds: 5
      timeoutSeconds: 2
      failureThreshold: 3

其中 kubia 容器的 liveness probe 是最簡單版本的 HTTP 應(yīng)用的 probe素征。該 probe 只是向 8080 端口的 / 路徑發(fā)送 HTTP GET集嵌,看容器是否仍然能夠處理請求。當應(yīng)用的響應(yīng)碼介于 200 到 399 之間時御毅,該應(yīng)用就被認為是健康的根欧。
由于該 probe 沒有配置其他選項,默認配置生效亚享。第一次檢查請求會在容器啟動 10s 后發(fā)起咽块,之后每隔 10s 發(fā)起新的請求绘面。若應(yīng)用沒有在 1s 之內(nèi)響應(yīng)欺税,則該次 probe 請求被認定是失敗的。連續(xù) 3 次請求失敗以后揭璃,容器就被認為是不健康的并被終止掉晚凿。

Envoy 容器的管理員接口提供了一個 /ready 入口,可以返回其健康狀態(tài)瘦馍,因此 envoy 容器的 liveness probe 的目標可以是容器的 admin 端口即 9901歼秽。
參數(shù) initialDelaySeconds 表示容器啟動后到發(fā)起第一個檢測請求之間的等待時間,periodSeconds 表示兩次連續(xù)的檢測請求之間的時間間隔情组,timeoutSeconds 表示多長時間以后沒有響應(yīng)則認定此次檢測失敗燥筷,failureThreshold 則表示連續(xù)多少次檢測失敗以后才認定容器失效并重啟箩祥。

liveness probe

觀察 liveness probe 的效果
運行 kubectl apply 命令應(yīng)用上述清單文件并通過 kubectl port-forward 命令啟用端口轉(zhuǎn)發(fā),啟動該 Pod 并令其能夠被訪問:

$ kubectl apply -f kubia-liveness.yml
pod/kubia-liveness created
$ kubectl port-forward kubia-liveness 8080 8443 9901
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Forwarding from 127.0.0.1:8443 -> 8443
Forwarding from [::1]:8443 -> 8443
Forwarding from 127.0.0.1:9901 -> 9901
Forwarding from [::1]:9901 -> 9901

Pod 啟動成功以后肆氓,liveness probe 會在初始等待時間過后持續(xù)向 Pod 中的容器發(fā)起檢測請求袍祖,其檢測結(jié)果只會在容器的 log 中看到。
kubia 容器中的 Node.js 應(yīng)用會在每次處理 HTTP 請求時向標準輸出打印記錄谢揪,這些請求也包括 liveness probe 的檢測請求蕉陋。因此可以打開一個新的命令行窗口,使用如下命令查看請求記錄:

$ kubectl logs kubia-liveness -c kubia -f
Kubia server starting...
Local hostname is kubia-liveness
Listening on port 8080
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
Received request for / from ::ffff:172.17.0.1
...

envoy 容器的 liveness probe 被配置成向其管理員接口發(fā)送 HTTP 請求拨扶,這些請求被記錄在 /var/log/envoy.admin.log 文件中凳鬓。可以使用如下命令查看:

$ kubectl exec kubia-liveness -c envoy -- tail -f /var/log/envoy.admin.log
[2022-01-02T18:34:59.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"
[2022-01-02T18:35:04.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"
[2022-01-02T18:35:09.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"
[2022-01-02T18:35:14.818Z] "GET /ready HTTP/1.1" 200 - 0 5 0 - "172.17.0.1" "kube-probe/1.22" "-" "172.17.0.3:9901" "-"

觀察失敗的 liveness probe
可以嘗試手動令 liveness probe 的檢測請求失敗患民。先在一個新的窗口中運行 kubectl get events -w 命令缩举,方便后續(xù)觀察檢測失敗時輸出的事件信息。
訪問 Envoy 容器的管理員接口匹颤,手動配置其健康狀態(tài)為 fail

$ curl -X POST localhost:9901/healthcheck/fail
OK

此時轉(zhuǎn)到觀察事件信息的命令行窗口蚁孔,發(fā)現(xiàn)連續(xù)輸出了 3 次 probe failed 503 錯誤,之后 envoy 容器開始重啟:

kubectl get events -w
LAST SEEN   TYPE      REASON          OBJECT               MESSAGE
...
0s          Warning   Unhealthy       pod/kubia-liveness   Liveness probe failed: HTTP probe failed with statuscode: 503
0s          Warning   Unhealthy       pod/kubia-liveness   Liveness probe failed: HTTP probe failed with statuscode: 503
0s          Warning   Unhealthy       pod/kubia-liveness   Liveness probe failed: HTTP probe failed with statuscode: 503
0s          Normal    Killing         pod/kubia-liveness   Container envoy failed liveness probe, will be restarted
0s          Normal    Pulled          pod/kubia-liveness   Container image "luksa/kubia-ssl-proxy:1.0" already present on machine
0s          Normal    Created         pod/kubia-liveness   Created container envoy
0s          Normal    Started         pod/kubia-liveness   Started container envoy
exec & tcpSocket liveness probe

添加 tcpSocket liveness probe
對于接收非 HTTP 請求的應(yīng)用惋嚎,可以配置 tcpSocket liveness probe杠氢。
一個 tcpSocket liveness probe 的示例配置如下:

livenessProbe:
  tcpSocket:
    port: 1234
    periodSeconds: 2
    failureThreshold: 1

該 probe 會檢查容器的 1234 端口是否打開,每隔 2s 檢查一次另伍,一次檢查失敗則認定該容器是不健康的并重啟它鼻百。

exec liveness probe
不接受 TCP 連接的應(yīng)用可以配置一條命令去檢測其狀態(tài)。
下面的示例配置會每隔 2s 運行 /usr/bin/healthcheck 命令摆尝,檢測容器中的應(yīng)用是否仍在運行:

livenessProbe:
  exec:
    command:
    - /usr/bin/healthcheck
  periodSeconds: 2
  timeoutSeconds: 1
  failureThreshold: 1
startup probe

默認的 liveness probe 配置會給應(yīng)用 20 到 30s 的時間啟動温艇,如果應(yīng)用需要更長的時間才能啟動完成,容器會永遠達不到 liveness probe 檢測成功的狀態(tài)堕汞,從而進入了無限重啟的循環(huán)勺爱。
為了防止上述情況發(fā)生,可以增大 initialDelaySeconds讯检、periodSecondsfailureThreshold 的值琐鲁,但也會有一定的副作用。periodSeconds * failureThreshold 的值越大人灼,當應(yīng)用不健康時重啟的時間就越長围段。

Kubernetes 還提供了一種 startup probe。當容器配置了 startup probe 時投放,容器啟動時只有 startup probe 會執(zhí)行奈泪。startup probe 可以按照應(yīng)用的啟動時間配置,檢測成功之后 Kubernetes 會切換到使用 liveness probe 檢測。
比如 Node.js 應(yīng)用需要 1 分鐘以上的時間啟動涝桅,當啟動成功以后若應(yīng)用狀態(tài)不正常拜姿,則在 10s 以內(nèi)重啟》胨欤可以這樣配置:

containers:
- name: kubia
  image: luksa/kubia:1.0
  ports:
  - name: http
    containerPort: 8080
  startupProbe:
    httpGet:
      path: /
      port: http
    periodSeconds: 10
    failureThreshold: 12
  livenessProbe:
    httpGet:
      path: /
      port: http
    periodSeconds: 5
    failureThreshold: 2

上面配置的效果如下圖:


startup probe & liveness probe

應(yīng)用有 120s 的時間啟動砾隅。Kubernetes 一開始每隔 10s 發(fā)起 startup probe 請求,最多嘗試 12 次债蜜。
不同于 liveness probe晴埂,startup probe 失敗是很正常的,只是說明應(yīng)用還未成功啟動寻定。一旦某次 startup probe 檢測返回成功狀態(tài)儒洛,Kubernetes 就會立即切換到 liveness probe 模式,通常擁有更短的檢測間隔狼速,能夠?qū)ξ错憫?yīng)應(yīng)用做出更快速的反應(yīng)琅锻。

在容器啟動或關(guān)閉時觸發(fā)動作

可以向容器中添加 lifecycle hooks。Kubernetes 目前支持兩種類型的鉤子:

  • Post-start hooks:在容器啟動后執(zhí)行
  • Pre-stop hooks:在容器停止前執(zhí)行
Lifecycle hooks
post-start hooks

post-start lifecycle hook 會在容器創(chuàng)建完成之后立即觸發(fā)向胡∧张睿可以使用 exec 類型的鉤子在主進程啟動的同時執(zhí)行一個額外的程序,或者 httpGet 類型的鉤子向容器中運行的應(yīng)用發(fā)送 HTTP 請求僵芹,以完成初始化或預(yù)熱操作处硬。
假如你是應(yīng)用的作者,類似的操作當然可以加入到應(yīng)用本身的代碼中拇派。但對于一個已經(jīng)存在的并非自己創(chuàng)建的應(yīng)用荷辕,就有可能無法做到。post-start hook 提供了一種不需要修改應(yīng)用或容器鏡像的替代方案件豌。

post-start hook 在容器中執(zhí)行命令

apiVersion: v1
kind: Pod
metadata:
  name: fortune-poststart
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    lifecycle:
      postStart:
        exec:
          command:
          - sh
          - -c
          - "apk add fortune && fortune > /usr/share/nginx/html/quote"
    ports:
    - name: http
      containerPort: 80

上述清單文件定義的 Pod 名為 fortune-poststart疮方,包含一個基于 nginx:alpine 鏡像的容器,同時定義了一個 postStart 鉤子茧彤。該鉤子會在 Nginx 服務(wù)啟動時執(zhí)行以下命令:
sh -c "apk add fortune && fortune > /usr/share/nginx/html/quote"

postStart 這個名稱其實有些誤導作用骡显,它并不是在主進程完全啟動后才開始執(zhí)行,而是在容器創(chuàng)建后曾掂,幾乎和主進程同時執(zhí)行惫谤。

$ kubectl apply -f fortune-poststart.yml
pod/fortune-poststart unchanged
$ kubectl port-forward fortune-poststart 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

打開一個新的命令行窗口使用 curl 命令測試效果:

$ curl localhost:8080/quote
The Official MBA Handbook on business cards:
        Avoid overly pretentious job titles such as "Lord of the Realm,
        Defender of the Faith, Emperor of India" or "Director of Corporate
        Planning."

post-startup hook 對容器的影響
雖然 post-start hook 相對于容器的主進程以異步的方式執(zhí)行,它還是會對容器產(chǎn)生兩個方面的影響遭殉。
首先石挂,在 post-start hook 的執(zhí)行過程中容器會一直處于 Waiting 狀態(tài),原因顯示為 ContainerCreating险污,直到 hook 執(zhí)行完畢。
其次,若 hook 綁定的命令無法執(zhí)行或返回了一個非零的狀態(tài)值蛔糯,則整個容器會被重啟拯腮。

在容器終止前執(zhí)行命令

前面 fortune Pod 中的 Nginx 服務(wù)在收到 TERM 信號后會立即關(guān)閉所有打開的連接并終止進程,這并不是理想的操作蚁飒,不會等待正在處理的客戶端請求徹底完成动壤。
可以使用 pre-stop hook 執(zhí)行 nginx -s quit 命令舒緩地關(guān)閉 Nginx 服務(wù)。示例配置如下:

lifecycle:
  preStop:
    exec:
      command:
      - nginx
      - -s
      - quit

假如某個 pre-stop hook 執(zhí)行失敗淮逻,只會在 Pod 的 events 消息中顯示一條 FailedPreStopHook 警告信息琼懊,并不影響容器繼續(xù)被終止。

理解容器的生命周期

一個 Pod 的生命周期可以被分成如下三個階段:


Pod 生命周期的三個階段
  • 初始化階段:Pod 的 init 容器從開始運行到啟動完成
  • 運行階段:Pod 的普通容器從開始運行到啟動完成
  • 終止階段:Pod 的所有容器被終止運行
初始化階段

Pod 中的初始化容器會最先運行爬早,按照 specinitContainers 字段中定義的順序哼丈。
第一個初始化容器的鏡像被下載到工作節(jié)點并啟動,完成后繼續(xù)拉取第二個初始化容器的鏡像筛严,直到所有的初始化容器都成功運行醉旦。
若某個初始化容器因為某些錯誤啟動失敗,且其重啟策略設(shè)置為 AlwaysOnFailure桨啃,則該失敗的容器自動重啟车胡。若其重啟策略設(shè)置為 Never,則 Pod 的狀態(tài)顯示為 Init:Error照瘾,必須刪除并重新創(chuàng)建 Pod 對象匈棘。

All init containers must run to completion before the regular containers can start

運行階段

當所有的初始化容器成功運行后,Pod 的普通容器開始以并行的方式創(chuàng)建(需要注意的是析命,容器的 post-start hook 會阻塞下一個容器的創(chuàng)建)羹饰。

termination grace period
容器中的應(yīng)用都有一個固定的關(guān)閉時間做緩沖用,定義在 spec 下的 terminationGracePeriodSeconds 字段中碳却,默認是 30s队秩。
該時間從 pre-stop hook 觸發(fā)或收到 TERM 信號時開始計算,若時間過了進程仍在運行昼浦,應(yīng)用會收到 KILL 信號被強制關(guān)閉馍资。

container’s termination sequence

終止階段

Pod 的容器以并行的方式終止。對每個容器來說关噪,pre-stop hook 觸發(fā)鸟蟹,然后主進程接收 TERM 信號,如果應(yīng)用關(guān)閉的時間超過了 terminationGracePeriodSeconds使兔,就發(fā)送 KILL 信號給容器的主進程建钥。
在所有的容器都被終止以后,Pod 對象被刪除虐沥。

termination sequence inside a pod

可以在刪除一個 Pod 時手動指定一個新的時間覆蓋 terminationGracePeriodSeconds 的值熊经,如:
kubectl delete po kubia-ssl --grace-period 10

Pod 完整生命周期圖示
初始化階段
運行階段和終止階段

參考資料

Kubernetes in Action, Second Edition

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泽艘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子镐依,更是在濱河造成了極大的恐慌匹涮,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件槐壳,死亡現(xiàn)場離奇詭異然低,居然都是意外死亡,警方通過查閱死者的電腦和手機务唐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門雳攘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人枫笛,你說我怎么就攤上這事吨灭。” “怎么了崇堰?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵沃于,是天一觀的道長。 經(jīng)常有香客問我海诲,道長繁莹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任特幔,我火速辦了婚禮咨演,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蚯斯。我一直安慰自己薄风,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布拍嵌。 她就那樣靜靜地躺著遭赂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪横辆。 梳的紋絲不亂的頭發(fā)上撇他,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音狈蚤,去河邊找鬼困肩。 笑死,一個胖子當著我的面吹牛脆侮,可吹牛的內(nèi)容都是我干的锌畸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼靖避,長吁一口氣:“原來是場噩夢啊……” “哼潭枣!你這毒婦竟也來了比默?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤卸耘,失蹤者是張志新(化名)和其女友劉穎退敦,沒想到半個月后粘咖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚣抗,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年瓮下,在試婚紗的時候發(fā)現(xiàn)自己被綠了翰铡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡讽坏,死狀恐怖锭魔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情路呜,我是刑警寧澤迷捧,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站胀葱,受9級特大地震影響漠秋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抵屿,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一庆锦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧轧葛,春花似錦搂抒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至衷笋,卻和暖如春芳杏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背右莱。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工蚜锨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人慢蜓。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓亚再,卻偏偏與公主長得像,于是被迫代替她去往敵國和親晨抡。 傳聞我的和親對象是個殘疾皇子氛悬,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容