[工做隨筆] 配置 cron 檢查 K8s Pod 存活狀態以推送釘釘消息

背景

前段時間接手了一份維護老系統的任務。該系統使用了早期的 Spring Cloud 全家桶,其中有一個微服務隨着時間運行會出現大量 CLOSE_WAIT 狀態的 socket 鏈接以致於堵塞網關,檢查後發現與 HttpClient 相關(可參考 解決:HttpClient致使應用出現過多Close_Wait的問題 這篇博文),可是因爲沒有完整的源碼,沒法經過博文裏提到的方法解決。所以考慮經過外部手段檢測並重啓服務來恢復網關與服務的通信,簡單的檢測手段是經過發起 HTTP 請求看超時狀況:html

$ curl --connect-timeout 10 -m 10 <host>:<port>

配置 Kubernetes 存活探測

咱們使用了 Kubernetes 做爲部署環境,它使用存活探測器來知道何時要重啓容器。存活探測器有三種類型:shell

  • 存活命令;
  • HTTP 存活探測,發起 HTTP GET 請求以探測容器是否存活;
  • TCP 存活探測,發起 socket 鏈接以探測容器是否存活。

因爲咱們須要檢測的服務的問題是容器內存在大量的 CLOSE_WAIT 狀態鏈接,此時新的 socket 鏈接已經沒法連通,使用 HTTP 存活探測時其超時檢查沒法做用於 socket 超時,所以應該使用 TCP 存活探測。json

參照 Kubernetes 官方文檔提供的示例便可配置相關探測器:ubuntu

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20
注意

更多信息參見 定義 TCP 的存活探測api

配置 cron 執行腳本以檢查 K8s Pod 存活狀態

通過一段的運行後,Kubernetes 自帶的存活探測工做良好,可是客戶但願能獲悉服務實例重啓的信息,即每當服務實例重啓時發送消息至羣聊。app

一開始考慮使用 BOTKUBE 收集服務實例重啓信息,可是有幾個小問題:curl

  • BOTKUBE 原生僅支持 Slack、Mattermost、Microsoft Teams、Elastic Search、Webhook 五種方式;
  • BOTKUBE 是被動收集指定負載的相關事件。

可是客戶但願能在釘釘羣裏中獲悉 「N 個實例中重啓了 M 個」 信息以進行評估穩定性。socket

若是經過 Webhook 接入 BOTKUBE,則須要在一個短暫的週期內維護服務的總實例數與週期內重啓實例數量。相關編碼工做量太大,因而咱們經過編寫簡單的腳本並配置 cron 定時任務來完成該需求。tcp

腳本思路

假定咱們要檢查的服務名稱爲 service
export KUBECONFIG=/path/to/your/kubernetes.yaml
pods=""
total=`/usr/local/bin/kubectl --kubeconfig=$KUBECONFIG get pods -o wide | grep service | sed -n '$='` # 1
for pod in `/usr/local/bin/kubectl --kubeconfig=$KUBECONFIG get pods -o wide | grep service | awk '{print $1 "_" $6}'`    # 2
do
        name=`echo $pod | awk -F_ '{print $1}'`
        ip=`echo $pod | awk -F_ '{print $2}'`
        sname=`echo $name | awk -F- '{print $5}'`
        curl -s --connect-timeout 10 -m 10 $ip:8672 > /dev/null # 3
        if [ $? -ne 0 ]; then # 4
                /usr/local/bin/kubectl delete pod $name
                pods="$pods$sname ×, "
        else
                pods="$pods$sname √, "
        fi
done
pods="${pods%??}" # 5
success=`echo $pods | awk -F"√" '{print NF-1}'` # 6
if [ $success -ne $total ]; then
        # 7
        curl 'https://oapi.dingtalk.com/robot/send?access_token=***' \
                        -H 'Content-Type: application/json' \
                        -d '{ "msgtype": "text", "text": { "content": "檢查結果 ['"$success"'/'"$total"'] :\n'"${pods}"'" } }'
fi
  1. 統計當前正在運行的容器實例數量
  2. 咱們須要 pod 的名稱以在必要的時候經過 kubectl delete 刪除它,還須要 pod 的虛擬 ip 地址以經過 curl 測試鏈接狀況;
  3. 咱們不須要 curl 的鏈接狀態信息和鏈接成功後的資源下載進度信息,所以經過 -s 參數和重定向到空設備來 靜音
  4. curl 因 socket 鏈接超時返回非 0 值時刪除該容器;
  5. 截斷多餘的 ,<空格>
  6. 統計尚在正常運行的容器數量;
  7. 僅當刪除了一個或以上的容器時,發送構造好的報告信息至釘釘機器人。

效果:ide

檢查結果 [11/12] :
wdqdd ×, 5xwpz √, rgmc7 √, 8cf4f √, spttn √, dvw2l √, tg9lw √, kzrc2 √, fpk9s √, 9plpt √, dpkpf √, gnhrl √

配置 cron 定時任務

咱們使用的是 Ubuntu Server 18,經過 crontab -e 配置定時任務:

*/10 8-22 * * * /path/to/your/script.sh

使用 cron 執行腳本須要注意幾個問題:

  • cron 與腳本的權限問題;
  • 設置腳本的可執行權限(chmod +x script.sh);
  • cron 執行腳本時傳遞的是最小集環境變量,所以須要指定二進制執行文件的路徑,推薦在腳本開頭使用 export 指定路徑,但咱們內部使用且從簡處理,選擇直接指定絕對路徑 /usr/local/bin/kubectl
  • 系統的時區設置,若是修改了時區,須要重啓 cron 服務。

更多關於配置 cron 的注意事項能夠參考 Why crontab scripts are not working?

相關文章
相關標籤/搜索