問題的來由
在kubernetes集群的生產中,經常遇到這樣的一個問題,就是在應用大規模更新時,大量容器刪除而后大量容器創建,創建的容器需要很長時間才能就緒。這其中一個可能的原因,就是大量容器刪除釋放ip過於緩慢,導致新創建的容器無法及時獲取ip,從而無法及時啟動。
這種情況普遍存在於ip池較小或者應用升級需要ip保持不變的情景下,具有較為普遍的意義。針對這一情況,筆者先前做過一個方案用以解決該問題,在這里與大家分享一下。
k8s容器刪除的流程
首先,我們先來梳理下容器刪除的整個流程,看下為什么會釋放ip緩慢。kubernetes容器的整個刪除流程基本套路如下:
- 發送刪除請求到apiserver,標記容器的deletionTimestamp
- kubelet watch到該事件,知道pod需要刪除,進入刪除流程
- pod執行killPod流程
- kill app容器
- 執行preStopHook
- 等待gracePeriod
- 停止app容器
- kill pause容器
- 調用cni接口,停止容器網絡
- 停止pause容器
- 從apiserver中將pod的信息清除(真正刪除掉存儲在etcd的pod信息)
那么可以看到,ip的釋放其實是發生在調用cni接口的時候。因此,按照常規流程,其需要等待的時間為執行preStopHook的時間 + gracePeriod + 停止app容器的時間。這個時間對於希望快速釋放ip的情形下,是較為漫長的(一般要幾十秒)。
加速ip資源釋放的方案與利弊
如果想要加速ip資源的釋放,那么方式也就是顯而易見的,就是在kubernetes的現有流程基礎上進行定制開發,將cni的調用前置,將其提前到kill app容器之前。
特別注意,這里只是將cni接口調用提前,但是不要將停止pause容器提前,否則先停止pause容器可能會導致app容器停止時會有一些問題。
修改后的流程如下:
- 發送刪除請求到apiserver,標記容器的deletionTimestamp
- kubelet watch到該事件,知道pod需要刪除,進入刪除流程
- pod執行killPod
- 調用cni接口,停止容器網絡,釋放容器ip
- kill app容器
- 執行preStopHook
- 等待gracePeriod
- 停止app容器
- kill pause容器
- 調用cni接口,停止容器網絡(可選)
- 停止pause容器
- 從apiserver中將pod的信息清除(真正刪除掉存儲在etcd的pod信息)
這樣的話,可以在第一時間盡快釋放ip,而無需等待過久。
但是這樣的方案也存在着很大的弊端,就是首先摘除了容器的網絡,而如果preStopHook的執行或者停止app容器時需要依賴容器網絡(比如應用需要調用某個接口才能進行下線等),可能會導致流程無法進行,容器被卡住,形成僵屍容器或者形成應用信息錯誤。
因此這個方案最好要做成可選的選項,在annotation中增加一個注解。而后根據應用的實際情況,選擇是否使用快速釋放ip的策略。
