前言

我最近看到了很多有关Kubernetes健康检查以及如何使用它们的问题,对此我将尽力解释它们以及运行状况检查的类型之间的差异以及每种检查将如何影响你的应用程序。

Liveness Probes

Kubernetes健康检查分为存活探针和就绪探针,存活探针的目的是查看你的应用程序是否正在运行。通常情况下,你的应用程序可能会崩溃,而Kubernetes会看到该应用程序已终止并重新启动,但是存活探测的目的是捕获应用程序崩溃或死锁而无法终止的情况,因此,一个简单的HTTP响应就足够了。

这是我经常在Go应用程序中使用的运行健康检查的一个简单的例子。

http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("OK"))
}
http.ListenAndServe(":8080", nil)

在deployment文件里面的内容是:

livenessProbe:
  # an http probe
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15
  timeoutSeconds: 1

这只是告诉Kubernetes该应用已启动并正在运行,initialDelaySeconds告诉Kubernetes在启动Pod之后将运行状况检查延迟启动此秒数。 如果你的应用程序需要一段时间才能启动,则可以使用此设置来解决问题。 timeoutSeconds告诉Kubernetes应该等待多长时间才能进行健康检查响应,对于存活探针,这应该不会很长,但是你确实应该给你的应用足够的时间来响应,即使在负载不足的情况下也是如此。

如果应用从不启动或没有HTTP错误代码响应,Kubernetes将重新启动Pod,你要竭尽所能地不要在存活探针上做任何花哨的事情,因为如果存活探针检测失败可能会导致应用程序中断。

Readiness Probes

就绪探针与存活探针非常相似,不同之处在于探针探测失败的结果不同。 就绪探针旨在检查应用程序是否已准备好对外提供服务。 这与存活探针有细微的差别,例如,假设你的应用依赖于数据库和内存缓存,如果这两者都需要启动并运行以使你的应用程序能够对外提供服务,那么可以说这两个条件都是应用程序“就绪”所必需的。

如果针对你的应用程序的就绪探针失败,那么将从构成service的endpoints中删除该Pod,这使得Kubernetes的服务发现机制不会向尚未准备就绪的Pod导入流量,这对于启动新的service、动态伸缩,滚动更新等很有帮助。“就绪”探针可确保在Pod启动和准备对外提供服务之间的这段时间内,不向Pod导入流量。

就绪探针的定义与存活探针相同,就绪探针定义为Deployment的一部分,如下所示:

readinessProbe:
  # an http probe
  httpGet:
    path: /readiness
    port: 8080
  initialDelaySeconds: 20
  timeoutSeconds: 5readinessProbe:
  # an http probe
  httpGet:
    path: /readiness
    port: 8080
  initialDelaySeconds: 20
  timeoutSeconds: 5

你将需要检查就绪探针是否可以连接到所有应用程序的依赖项,以及要使用依赖于数据库和内存缓存的示例,接下来将检查是否能够同时连接到这两者。
大概类似这样,在这里,我检查了memcached和数据库,如果不可用,则返回503。

http.HandleFunc("/readiness", func(w http.ResponseWriter, r *http.Request) {
  ok := true
  errMsg = ""

  // Check memcache
  if mc != nil {
    err := mc.Set(&memcache.Item{Key: "healthz", Value: []byte("test")})
  }
  if mc == nil || err != nil {
    ok = false
    errMsg += "Memcached not ok.¥n"
  }

  // Check database
  if db != nil {
    _, err := db.Query("SELECT 1;")
  }
  if db == nil || err != nil {
    ok = false
    errMsg += "Database not ok.¥n"
  } 

  if ok {
    w.Write([]byte("OK"))
  } else {
    // Send 503
    http.Error(w, errMsg, http.StatusServiceUnavailable)
  }
})
http.ListenAndServe(":8080", nil)

更健壮的应用

Liveness和Readiness探针确实有助于提高应用程序的稳定性,它们有助于确保流量仅流向已准备就绪的实例,并在应用程序无响应时自愈。 对于我的同事Kelsey Hightower所说的12 Fractured Apps),它们是更好的解决方案。 通过适当的运行健康检查,你可以按任何顺序部署应用程序,而不必担心依赖关系或者复杂的endpoints脚本,应用程序准备就绪后将开始提供流量,自动伸缩和滚动更新也将顺利进行。


EngineerLeo
598 声望38 粉丝

专注于云原生、AI等相关技术