跳到主要内容

配置上游健康检查

健康检查是一种根据上游服务响应情况判断其健康或不健康的机制。启用健康检查后,网关只会将请求转发到被认为健康的上游服务,不会转发到被认为不健康的服务。

健康检查通常有两种方式:

  • 主动检查:网关主动、定期向上游服务发送请求,并根据这些请求的响应判断上游服务健康状态。
  • 被动检查:网关不主动探测,而是根据上游服务对客户端请求的响应判断健康状态。

本文介绍如何通过 Ingress Controller 为上游服务配置主动和被动健康检查。

前提条件

  1. 完成设置 Ingress Controller 和网关

启动示例上游服务

创建 Kubernetes manifest 文件,部署两个 NGINX 实例作为示例上游服务:

nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: aic
name: nginx1
spec:
replicas: 1
selector:
matchLabels:
app: nginx1
template:
metadata:
labels:
app: nginx1
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: nginx1
spec:
selector:
app: nginx1
ports:
- port: 8080
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: aic
name: nginx2
spec:
replicas: 1
selector:
matchLabels:
app: nginx2
template:
metadata:
labels:
app: nginx2
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: nginx2
spec:
selector:
app: nginx2
ports:
- port: 8081
targetPort: 80

将配置应用到集群:

kubectl apply -f nginx.yaml

通过端口转发将 NGINX Service 端口暴露到本地:

kubectl port-forward svc/nginx1 8080:8080 &
kubectl port-forward svc/nginx2 8081:8081 &

验证两个 NGINX 实例是否正常运行:

for port in 8080 8081; do
curl -s "http://127.0.0.1:$port" | grep -q "Welcome to nginx" &&
echo "NGINX welcome page available on port $port."
done

你应看到以下响应:

NGINX welcome page available on port 8080.
NGINX welcome page available on port 8081.

启用 Control API

升级网关以启用 Control API。

导出所有 values(包括默认值):

helm get values -n aic apisix --all > values.yaml

在 values 文件中按如下方式更新配置:

values.yaml
apisix:
enabled: true
control:
enabled: true

升级 Helm release:

helm upgrade -n aic apisix apisix/apisix -f values.yaml

转发 Control API 端口:

kubectl port-forward service/apisix-control 9090:9090 &

配置主动健康检查

主动检查会定期向上游服务发送请求或探针,并根据响应判断上游服务的健康状态。

本节通过两个示例帮助你理解:

  • 主动检查如何检测上游状态变化。
  • 当所有上游状态均为不健康时,网关如何向上游服务转发客户端请求。

示例:上游服务状态变化

以下示例演示当健康的上游服务变为部分不可用、全部不可用以及全部恢复时,主动健康检查如何响应。

创建指向两个服务的路由,并配置每 2 秒运行一次的主动健康检查:

active-health-checks.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: aic
name: nginx1
spec:
targetRefs:
- name: nginx1
kind: Service
group: ""
healthCheck:
active:
type: http
httpPath: /
healthy:
interval: 2s
successes: 1
unhealthy:
interval: 1s
timeouts: 3
---
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: aic
name: nginx2
spec:
targetRefs:
- name: nginx2
kind: Service
group: ""
healthCheck:
active:
type: http
httpPath: /
healthy:
interval: 2s
successes: 1
unhealthy:
interval: 1s
timeouts: 3
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: example-hc-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /
backendRefs:
- name: nginx1
port: 8080
weight: 1
- name: nginx2
port: 8081
weight: 1

将配置应用到集群:

kubectl apply -f active-health-checks.yaml

验证

你将验证以上配置,以了解上游健康检查在不同场景下的响应方式:

  • 所有上游服务均健康时。
  • 只有部分服务健康时。
  • 所有服务均不健康时。
  • 所有服务恢复健康时。

继续之前,先将网关 Service 端口暴露到本地:

# 替换为你的网关 Service 名称
kubectl port-forward svc/<gateway-service-name> 9080:80 &

验证两个上游服务均健康

向路由发送请求以启动健康检查:

curl "http://127.0.0.1:9080/"

如需查看上游健康状态,请向 Control API 中的健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到类似如下响应:

[
{
"name": "/apisix/routes/example-hc-route",
"type": "http",
"nodes": [
{
"port": 80,
"counter": {
"http_failure": 0,
"tcp_failure": 0,
"timeout_failure": 0,
"success": 0
},
"ip": "172.24.0.5",
"status": "healthy"
},
{
"port": 80,
"counter": {
"http_failure": 0,
"tcp_failure": 0,
"timeout_failure": 0,
"success": 0
},
"ip": "172.24.0.4",
"status": "healthy"
}
]
}
]

验证一个上游服务不可用

临时将一个上游服务设为不可用,验证网关是否将其中一个上游服务报告为不健康:

kubectl scale deployment nginx1 -n aic --replicas=0

等待几秒后,向健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到类似如下响应,表示其中一个上游节点出现 3 次超时失败并被标记为不健康:

[
{
"name": "/apisix/routes/example-hc-route",
"type": "http",
"nodes": [
{
"port": 80,
"counter": {
"http_failure": 0,
"tcp_failure": 0,
"timeout_failure": 0,
"success": 0
},
"ip": "172.24.0.5",
"status": "healthy"
},
{
"port": 80,
"counter": {
"http_failure": 0,
"tcp_failure": 0,
"timeout_failure": 3,
"success": 0
},
"ip": "172.24.0.4",
"status": "unhealthy"
}
]
}
]

向路由发送请求,确认网关是否会将请求转发到另一个健康节点:

curl -i "http://127.0.0.1:9080/"

你应收到 HTTP/1.1 200 OK 响应.

验证两个上游服务均不可用

临时将另一个上游服务也设为不可用,验证网关是否将两个上游服务都报告为不健康:

kubectl scale deployment nginx2 -n aic --replicas=0

等待几秒后,向健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到类似如下响应,表示两个上游节点均出现 3 次超时失败并被标记为不健康:

[
{
"name": "/apisix/routes/example-hc-route",
"type": "http",
"nodes": [
{
"port": 80,
"counter": {
"http_failure": 0,
"tcp_failure": 0,
"timeout_failure": 3,
"success": 0
},
"ip": "172.24.0.5",
"status": "unhealthy"
},
{
"port": 80,
"counter": {
"http_failure": 0,
"tcp_failure": 0,
"timeout_failure": 3,
"success": 0
},
"ip": "172.24.0.4",
"status": "unhealthy"
}
]
}
]

向路由发送请求:

curl -i "http://127.0.0.1:9080/"

你应 receive an HTTP/1.1 502 Bad Gateway response.

验证两个上游服务均已恢复

重新启用两个服务,验证网关是否将两个上游服务都报告为健康:

kubectl scale deployment -n aic nginx1 nginx2 --replicas=1

等待几秒后,向健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到一个响应,显示两个上游节点均处于健康状态,类似于开始时两个服务都健康的场景。

示例:状态不健康时转发请求

以下示例演示即使所有上游都被标记为不健康,网关仍会将客户端请求转发到上游服务。

创建指向两个服务的路由,并配置每 2 秒运行一次的主动健康检查:

active-health-checks.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: aic
name: nginx1
spec:
targetRefs:
- name: nginx1
kind: Service
group: ""
healthCheck:
active:
type: http
httpPath: /404
healthy:
interval: 2s
successes: 1
unhealthy:
interval: 1s
httpFailures: 2
---
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: aic
name: nginx2
spec:
targetRefs:
- name: nginx2
kind: Service
group: ""
healthCheck:
active:
type: http
httpPath: /404
healthy:
interval: 2s
successes: 1
unhealthy:
interval: 1s
httpFailures: 2
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: example-hc-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /
backendRefs:
- name: nginx1
port: 8080
weight: 1
- name: nginx2
port: 8081
weight: 1

将配置应用到集群:

kubectl apply -f active-health-checks.yaml

验证

将网关 Service 端口暴露到本地机器:

# 替换为你的网关 Service 名称
kubectl port-forward svc/<gateway-service-name> 9080:80 &

向路由发送请求以启动健康检查:

curl -i "http://127.0.0.1:9080/"

你应收到 HTTP/1.1 200 OK 响应.

向健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到类似如下响应:

[
{
"name": "/apisix/routes/example-hc-route",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 2,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.5",
"status": "unhealthy"
},
{
"counter": {
"timeout_failure": 0,
"http_failure": 2,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.4",
"status": "unhealthy"
}
],
"type": "http"
}
]

向路由发送请求,确认网关是否仍会转发请求:

curl -i "http://127.0.0.1:9080/"

你应收到 HTTP/1.1 200 OK 响应。这说明即使两个服务都被标记为不健康,网关仍会将客户端请求转发到上游服务。

配置被动健康检查

如需使用被动健康检查,也必须配置主动健康检查。当上游服务变为不健康时,主动健康检查会定期检查该上游服务是否已恢复。

已知问题

网关目前存在一个已知问题:Control API 显示的被动健康检查数据无法准确反映实际健康状态,因此你的测试结果可能与示例不同。该问题正在处理中。不过,被动健康检查机制本身可以正常工作,并会按预期继续路由请求。

示例:上游服务状态变化

创建指向两个服务的路由,并同时配置主动和被动健康检查:

passive-health-checks.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: aic
name: nginx1
spec:
targetRefs:
- name: nginx1
kind: Service
group: ""
healthCheck:
active:
type: http
httpPath: /
healthy:
interval: 99999s
successes: 1
unhealthy:
interval: 30s
passive:
healthy:
httpCodes: [200, 201, 202, 300, 301, 302]
successes: 1
unhealthy:
httpCodes: [429, 404, 500, 501, 502, 503, 504, 505]
httpFailures: 3
---
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: aic
name: nginx2
spec:
targetRefs:
- name: nginx2
kind: Service
group: ""
healthCheck:
active:
type: http
httpPath: /
healthy:
interval: 99999s
successes: 1
unhealthy:
interval: 30s
passive:
healthy:
httpCodes: [200, 201, 202, 300, 301, 302]
successes: 1
unhealthy:
httpCodes: [429, 404, 500, 501, 502, 503, 504, 505]
httpFailures: 3
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: example-hc-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /404
backendRefs:
- name: nginx1
port: 8080
weight: 1
- name: nginx2
port: 8081
weight: 1

将配置应用到集群:

kubectl apply -f passive-health-checks.yaml

验证

将网关 Service 端口暴露到本地机器:

# 替换为你的网关 Service 名称
kubectl port-forward svc/<gateway-service-name> 9080:80 &

向路由发送请求以启动健康检查:

curl -i "http://127.0.0.1:9080/404"

你应看到 HTTP/1.1 404 Not Found 响应。

向健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到类似如下响应:

[
{
"name": "/apisix/routes/example-hc-route",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 1,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.5",
"status": "mostly_healthy"
},
{
"counter": {
"timeout_failure": 0,
"http_failure": 0,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.4",
"status": "healthy"
}
],
"type": "http"
}
]

❶ 由于上一次请求返回了 404 响应,http_failure 的计数为 1。

mostly_healthy 状态表示当前节点仍为健康,但网关已在健康检查中开始收到不健康信号。

连续发起请求以触发 404 响应:

resp=$(seq 10 | xargs -I{} curl "http://127.0.0.1:9080/404" -o /dev/null -s -w "%{http_code}\n") && \
count=$(echo "$resp" | grep "404" | wc -l) && \
echo "Invoked $count responses with 404 status code."

向健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到类似如下响应:

[
{
"name": "/apisix/routes/example-hc-route",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 3,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.4",
"status": "unhealthy"
},
{
"counter": {
"timeout_failure": 0,
"http_failure": 4,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.5",
"status": "unhealthy"
}
],
"type": "http"
}
]

至少等待 30 秒,让主动检查探测上游服务的 / 路径并将其标记为健康。然后向健康检查端点发送请求:

curl "http://127.0.0.1:9090/v1/healthcheck"

你应看到类似如下响应:

[
{
"name": "/apisix/routes/example-hc-route",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 0,
"success": 1,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.4",
"status": "healthy"
},
{
"counter": {
"timeout_failure": 0,
"http_failure": 0,
"success": 1,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.5",
"status": "healthy"
}
],
"type": "http"
}
]