iT邦幫忙

2021 iThome 鐵人賽

DAY 19
1
Modern Web

Let's Go! 解剖Go server開發到部署的過程系列 第 19

day 19 - health check 讓k8s幫忙關懷服務

服務上k8s之後, 除了介接的系統會來打API之外, 在API沒有被觸發的期間如果服務發生問題, 很難被事先發現。

以我們現行的專案來說, k8s上面起的服務有50-60個, 每個服務還有多個pod, 況且每個服務的使用頻率不一樣, 有的每秒會被打幾百次, 發生問題很快就能被發現, 有的一兩個月都不會被打到一次, 等到要用的時候才發現它壞掉, 那就是一陣手忙腳亂了。
所以提供一個health check讓k8s可以幫忙關懷各個服務的狀況, 確實掌握叢集中裡面大大小小, 從熱門到邊緣的服務狀況, 主動發現問題才能在問題引爆之前多爭取一點時間。

這邊採用的方式是在服務上開啟一個http port, 讓k8s定期發送一個 HTTP request給Pod。

cmd.go 加上啟動 http port function runHealth(), 在每次k8s詢問的時候打一次自身的Ping並回應服務執行時長。


	grpcServer := runGrpcServer(shutdownObserver, sv)

	// health check
	go runHealth()

........ (省略)

func runHealth() {
	started := time.Now()
	connSelf, err := grpc.Dial("localhost"+config.Listen, grpc.WithInsecure())

	if err != nil {
		Logger.WithFields(map[string]interface{}{"error": err}).Errorf("連線失敗")
	}

	coco := coconut.NewCoconutClient(connSelf)

	Logger.Debugf("Healthy API is Running at port: %s", config.HealthPort)
	http.HandleFunc(config.HealthPath, func(w http.ResponseWriter, r *http.Request) {
		// 確認gRPC服務有通
		ping, err := coco.Ping(context.Background(), &coconut.PingRequest{})
		if err == nil {
			w.WriteHeader(200)
			data := fmt.Sprintf("Already run: %v", time.Since(started))
			if _, errw := w.Write([]byte(data)); errw != nil {
				Logger.WithFields(map[string]interface{}{"error": errw}).Errorf("runHealth")
			}
		} else {
			w.WriteHeader(500)
			Logger.Errorf("Service Not Ready yet, ping: %#v, err: %s", ping, err.Error())
		}
	})

	logrus.Fatal(http.ListenAndServe(":"+config.HealthPort, nil))
}

在去年的k8s主題中有學到 kubelet 可以執行三種探測

  1. livenessProbe (存活性探測):
    顯示容器是否正常運作, 如果探測失敗kubelet會終止容器, 容器會依照重啟策略進行下一個動作; 如果容器不支援存活性探測, 則默認狀態為 Success。
  2. readinessProbe (就緒性探測):
    顯示容器是否準備好提供服務, 如果探測失敗Endpoint Controller 會從匹配的所有Service Endpoint list 刪除Pod IP; 如果容器不支援就緒性探測, 則默認狀態為 Success。
  3. startupProbe (啟動探測):
    顯示容器中的應用是否已經啟動, 如果啟動startupProbe則其他探測都會被禁用,直到startupProbe成功為; 如果探測失敗kubelet會終止容器, 容器會依照重啟策略進行下一個動作; 如果容器不支援存活性探測, 則默認狀態為 Success。

health check 這裡採用的是 readinessProbe , 主要用來判斷Pod是否可以接收request。所以會在部署k8s deployment.yaml時加上這段

  template:
    spec:
      containers:
          readinessProbe:
            httpGet:
              path: {{ health.Path }}
              port: {{ health.httpPort }}
            initialDelaySeconds: 2
            periodSeconds: 5

參考資料

  1. 如何確保 Container 運行狀態 - Health Checks
  2. Kubernetes 那些事 —Health Check

上一篇
day 18 - graceful shutdown 優雅地退場
下一篇
day 20 - 新增需求:隨時通知目前統計狀況 nsq / websocket 介紹
系列文
Let's Go! 解剖Go server開發到部署的過程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言