這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
第六節:health check
原文地址
轉載請註明原文及翻譯地址
當我們的微服務越來越複雜,讓docker swarm知道我們的服務運行良好與否很重要.下面我們來看一下如何查看服務健全狀態.
例如,我們的accountservice服務將沒用如果不能 服務http或者連結資料庫.
最好的辦法就是提供一個healthcheck存取點.我們基於http,所以映射到/health,如果運行良好,返回http 200同事一些解釋什麼是良好的資訊.如果有問題,非http 200返回,並解釋哪裡不好.有人認為都應該返回200,之後返回錯誤資訊.我同意,但是這個簡單例子中,我會用非200返回.
代碼
一樣,你可以直接branch到這部分
git checkout P6
加入BoltDB的檢查
我們的服務如果不能串連database將沒有用,因此我們加入函數 Check()
type IBoltClient interface {b OpenBoltDb() QueryAccount(accountId string) (model.Account, error) Seed() Check() bool //new}
這個函數可能很簡單,但是足夠了,他將根據BoltDb能否串連而返回true/false.
func (bc *BoltClient) Check() bool { return bc.boltDB != nil}
mocked代碼在mackclient.go遵從stretchr/testify的形式
func (m *MockBoltClient) Check() bool { args := m.Mock.Called() return args.Get(0).(bool)
加入/health路徑
很直接,我們在routes.go中加入
Route{ "HealthCheck", "GET", "/health", HealthCheck},
我們用函數HealthCheck來處理請求,我們把這個函數加到handler.go中:
func HealthCheck(w http.ResponseWriter, r *http.Request) { // Since we're here, we already know that HTTP service is up. Let's just check the state of the boltdb connection dbUp := DBClient.Check() if dbUp { data, _ := json.Marshal(healthCheckResponse{Status: "UP"}) writeJsonResponse(w, http.StatusOK, data) } else { data, _ := json.Marshal(healthCheckResponse{Status: "Database unaccessible"}) writeJsonResponse(w, http.StatusServiceUnavailable, data) }}func writeJsonResponse(w http.ResponseWriter, status int, data []byte) { w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Length", strconv.Itoa(len(data))) w.WriteHeader(status) w.Write(data)}type healthCheckResponse struct { Status string `json:"status"`}
HealthCheck函數用Check()函數來檢查資料庫情況.如果正常,我們返回healthCheckResponse結構的執行個體.注意這個小寫首字母,這樣只有在這個package中才能用這個結構.我們也提取出返回結果的代碼進一個函數來讓我們不重複代碼.
運行
在blog/accountservice檔案夾中,運行:
> go run *.goStarting accountserviceSeeded 100 fake accounts...2017/03/03 21:00:31 Starting HTTP service at 6767
curl這個/health路徑
> curl localhost:6767/health{"status":"UP"}
docker healthcheck
接下來,我們用docker的健全狀態檢查機制來檢查我們的服務.加入下面命令在Dockerfile:
HEALTHCHECK --interval=5s --timeout=5s CMD["./healthchecker-linux-amd64", "-port=6767"] || exit 1
healthchecker-linux-amd64是什麼?docker自己不知道怎樣做這個健全狀態檢查,我們需要幫一下,我們在CMD命令輸入來指引到/health路徑.根據exit code,docker會判斷服務良好與否.如果太多的檢查失敗,swarm會關掉容器並開啟新的執行個體
最常見的健全狀態檢查使用curl,然而這要求我們的docker鏡像安裝curl.這裡我們會用go來執行這個小程式.
建立helathchecker程式
在goblog下增加檔案夾
mkdir healthchecker
加入main.go
package mainimport ( "flag" "net/http" "os")func main() { port := flag.String("port", "80", "port on localhost to check") flag.Parse() resp, err := http.Get("http://127.0.0.1:" + *port + "/health") // Note pointer dereference using * // If there is an error or non-200 status, exit with 1 signaling unsuccessful check. if err != nil || resp.StatusCode != 200 { os.Exit(1) } os.Exit(0)}
代碼不多,主要做:
- 用內建flags讀取-port=NNNN命令參數,如果沒有,用預設連接埠80
- 開始http get請求127.0.0.1:[port]/health
- 如果有錯誤或者返回狀態非200,退出同一個非0值,0==成功,>0==失敗
試一下,如果你停止了accountservice,用go run *.go啟動,或者編譯它go build ./accountservice
之後回到後台運行healthchecker
> cd $GOPATH/src/github.com/callistaenterprise/goblog/healthchecker> go run *.goexit status 1
哎呀!我們忘記給連接埠號碼了.再試一次
> go run *.go -port=6767>
沒有輸出表示我們成功了.好,讓我們編譯一個linux/amd64二進位並加入到accountservice中,通過加入healthchecker在dockerfile中. 我們用copyall.sh指令碼來做:
#!/bin/bashexport GOOS=linuxexport CGO_ENABLED=0cd accountservice;go get;go build -o accountservice-linux-amd64;echo built `pwd`;cd ..// NEW, builds the healthchecker binarycd healthchecker;go get;go build -o healthchecker-linux-amd64;echo built `pwd`;cd ..export GOOS=darwin // NEW, copies the healthchecker binary into the accountservice/ foldercp healthchecker/healthchecker-linux-amd64 accountservice/docker build -t someprefix/accountservice accountservice/
同時,我們更新accountservice的dockerfile:
FROM iron/baseEXPOSE 6767ADD accountservice-linux-amd64 /# NEW!! ADD healthchecker-linux-amd64 /HEALTHCHECK --interval=3s --timeout=3s CMD ["./healthchecker-linux-amd64", "-port=6767"] || exit 1ENTRYPOINT ["./accountservice-linux-amd64"]
加入的部分
- 加入一個ADD語句來確定healthchecker加入到鏡像中.
- HEALTHCHECK語句告訴docker每3s執行一次,逾時為3s
部署healthcheck
現在我們能部署帶有healthchecking的accountservice了.自動化來做這些事,加入兩行到copyall.sh中:
docker service rm accountservicedocker service create --name=accountservice --replica=1 --network=my_network -p=6767:6767someprefix/accountservice
運行./copyall.sh等幾秒,之後檢查容器狀態,docker ps:
> docker psCONTAINER ID IMAGE COMMAND CREATED STATUS 1d9ec8122961 someprefix/accountservice:latest "./accountservice-lin" 8 seconds ago Up 6 seconds (healthy)107dc2f5e3fc manomarks/visualizer "npm start" 7 days ago Up 7 days
我們看到(healthy)欄位在status欄,沒有健全狀態檢查的服務不會有這個提示.
看一下失敗的情形
讓我們加入可以測試的api來讓路徑表現的不健康.在routes.go中,加入新路徑:
Route{ "Testability", "GET", "/testability/healthy/{state}", SetHealthyState,},
這個路徑(你不應該包括他在生產環境)提供我們一個讓健全狀態檢查失敗的方法.SetHealthyState函數在handlers.go中:
var isHealthy = true // NEWfunc SetHealthyState(w http.ResponseWriter, r *http.Request) { // Read the 'state' path parameter from the mux map and convert to a bool var state, err = strconv.ParseBool(mux.Vars(r)["state"]) // If we couldn't parse the state param, return a HTTP 400 if err != nil { fmt.Println("Invalid request to SetHealthyState, allowed values are true or false") w.WriteHeader(http.StatusBadRequest) return } // Otherwise, mutate the package scoped "isHealthy" variable. isHealthy = state w.WriteHeader(http.StatusOK)}
重啟accountservice
func HealthCheck(w http.ResponseWriter, r *http.Request) { // Since we're here, we already know that HTTP service is up. Let's just check the state of the boltdb connection dbUp := DBClient.Check() if dbUp && isHealthy { // NEW condition here! data, _ := json.Marshal( ... ... }
重新請求healthcheck
> cd $GOPATH/src/github.com/callistaenterprise/goblog/accountservice> go run *.goStarting accountserviceSeeded 100 fake accounts...2017/03/03 21:19:24 Starting HTTP service at 6767
第一次嘗試成功,現在改變accountservice用curl請求到測試路徑
> curl localhost:6767/testability/healthy/false> go run *.go -port=6767exit status 1
工作正常,讓我們在docker swarm中運行,用copyall.sh重新編譯和部署
> cd $GOPATH/src/github.com/callistaenterprise/goblog> ./copyall.sh
等一會,之後運行docker ps來看我們的健康服務
> docker psCONTAINER ID IMAGE COMMAND CREATED STATUS 8640f41f9939 someprefix/accountservice:latest "./accountservice-lin" 19 seconds ago Up 18 seconds (healthy)
注意CONTAINER ID和CREATED.請求測試api,我的是192.168.99.100
> curl $ManagerIP:6767/testability/healthy/false>
現在,運行docker ps
> docker psCONTAINER ID IMAGE COMMAND CREATED STATUS NAMES0a6dc695fc2d someprefix/accountservice:latest "./accountservice-lin" 3 seconds ago Up 2 seconds (healthy)
看,一個新的CONTAINER ID和新的CREATED和STATUS時間戳記.因為swarm每三秒會檢查一次,之後探索服務不健康,所以用一個新的服務替換掉,並且不需要管理員的插手
總結
我們加入一個簡單的/health路徑和一些docker的健全狀態檢查機制.展示swarm是如何控制非健康服務的.
下一節,我們會深入swarm,我們會關注微服務兩個架構:服務發現和負載平衡.