跳到主要内容

配置上游健康检查

健康检查帮助网关识别能正常响应的上游节点,并检测节点何时发生故障或恢复。

健康检查分为两类:

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

以下示例针对两个 NGINX 服务配置这两类检查,并区分探针失败与端点移除。

前置条件​

  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:
- name: http
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:
- name: http
port: 8081
targetPort: 80

将配置应用到集群:

kubectl apply -f nginx.yaml

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

kubectl port-forward svc/nginx1 -n aic 8080:8080 &
kubectl port-forward svc/nginx2 -n aic 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 --version 2.18.0 -f values.yaml

转发 Control API 端口:

kubectl port-forward service/apisix-control -n aic 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: ""
# 仅将此策略应用到命名的 Service 端口。
sectionName: http
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: ""
sectionName: http
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

sectionName 通过 spec.ports[].name 选择 Service 端口。若命名端口不存在,策略不会挂载,其状态会报告 Accepted=False,并显示类似 No section name http found in Service aic/nginx1 的消息。可使用以下命令检查策略状态:

kubectl describe backendtrafficpolicy nginx1 -n aic

验证​

网关通常选择健康节点。当所有节点都被标记为不健康但端点仍然存在时,负载均衡器仍可回退到这些节点;这与完全没有端点不同。

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

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

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

验证两个上游服务均健康​

在 Controller 应用配置并初始化上游检查器时,通过路由生成流量。轮询 http://127.0.0.1:9090/v1/healthcheck,直到两个 Service 上游都存在健康节点。一次请求不能保证每个 worker 都已初始化检查器。

for attempt in $(seq 10); do
curl -sS --max-time 5 "http://127.0.0.1:9080/" -o /dev/null
curl -sS --max-time 5 "http://127.0.0.1:9090/v1/healthcheck"
sleep 2
done

如果检查器仍在初始化,请重复请求。开始故障测试前,确认两个上游都处于健康状态。

响应包含 nginx1 和 nginx2 各自独立的上游检查器条目,每个条目都有自己的节点和计数器。名称和 Pod IP 会动态生成;不要预期看到一个以路由命名、同时包含两个 Service 的检查器。

验证探针失败与恢复​

保持两个 Deployment 运行,使其端点继续存在。请为已应用配置的选项卡选择对应资源类型:

# Gateway API:
export HEALTH_RESOURCE="backendtrafficpolicies.apisix.apache.org"
# 对于 APISIX CRD 选项卡,请改用:
# export HEALTH_RESOURCE="apisixupstreams.apisix.apache.org"

让第一个上游的探针请求 /404(返回不健康的 HTTP 状态),并设置失败阈值:

kubectl patch "$HEALTH_RESOURCE" nginx1 -n aic --type merge \
-p '{"spec":{"healthCheck":{"active":{"httpPath":"/404","unhealthy":{"httpFailures":2}}}}}'
curl -i "http://127.0.0.1:9080/"
curl "http://127.0.0.1:9090/v1/healthcheck"

重复发送流量并查询检查器,直到 nginx1 检查器报告 HTTP 失败并变为不健康,而 nginx2 保持健康。EndpointSlice 此时仍应包含两个后端。计数和时间会有差异;一次请求不保证状态一定完成转换。

对第二个上游应用相同变更:

kubectl patch "$HEALTH_RESOURCE" nginx2 -n aic --type merge \
-p '{"spec":{"healthCheck":{"active":{"httpPath":"/404","unhealthy":{"httpFailures":2}}}}}'
curl -i "http://127.0.0.1:9080/"
curl "http://127.0.0.1:9090/v1/healthcheck"

轮询直到两个检查器都报告不健康节点。由于服务器及其端点仍然可用,对 / 的请求仍可通过“全部不健康”回退机制成功。

恢复两个资源的探针路径:

for service in nginx1 nginx2; do
kubectl patch "$HEALTH_RESOURCE" "$service" -n aic --type merge \
-p '{"spec":{"healthCheck":{"active":{"httpPath":"/"}}}}'
done
curl -i "http://127.0.0.1:9080/"
curl "http://127.0.0.1:9090/v1/healthcheck"

开始端点移除测试前,请等待两个上游健康检查器恢复健康。这验证的是 HTTP 探针失败与恢复,而不是超时计数或端点移除。

验证端点移除​

将一个后端缩容到零:

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

等待其 EndpointSlice 与网关配置收敛。被移除的端点会从上游消失;移除端点并不能证明发生了三次探针失败,也不会增加超时计数器。

使用 HTTPRoute 时,剩余的可用后端可以继续处理请求。在 ApisixRoute 示例中,空后端仍保留权重,因此重复请求时可能同时出现成功响应和 503 响应。

将第二个后端缩容到零:

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

收敛后,两个后端都没有可用端点,请求将返回 503 而不是 502。若要演示探针超时,请保持端点存在,同时阻止其探针响应。

恢复上游​

kubectl scale deployment nginx1 -n aic --replicas=1
kubectl scale deployment nginx2 -n aic --replicas=1
kubectl rollout status deployment/nginx1 -n aic --timeout=120s
kubectl rollout status deployment/nginx2 -n aic --timeout=120s

等待端点、网关配置和健康的检查器状态全部就绪后再继续。仅 Pod 就绪并不能证明网关已应用恢复的端点。

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

本示例测试两个 Service 仍有端点时的“全部不健康”回退机制。

创建指向两个服务的路由。将健康探针配置为每 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> -n aic 9080:80 &

发送一个请求以初始化上游检查器。该请求发往 /;随后主动探针会按自身调度检查 /404,因此第一次响应并不能证明已触发回退:

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

轮询健康检查端点,直到两个检查器在达到两次失败阈值后都报告不健康节点:

for attempt in $(seq 10); do
curl -sS --max-time 5 "http://127.0.0.1:9090/v1/healthcheck"
sleep 2
done

如果探针仍在运行,请重复检查。当两个检查器都变为不健康后,响应类似如下:

[
{
"name": "<generated-upstream-checker-for-nginx1>",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 2,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.5",
"status": "unhealthy"
}
],
"type": "http"
},
{
"name": "<generated-upstream-checker-for-nginx2>",
"nodes": [
{
"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/"

两个检查器都显示不健康节点后,200 响应可确认已回退到可用端点。

测试被动失败前,请应用下面的配置。它会将主动探针路径恢复为 /;等待两个检查器都报告健康节点后,再向 /404 发送请求。

配置被动健康检查​

被动检查应与主动检查配合使用,以便对因客户端流量而被标记为不健康的节点进行恢复探测。

示例:上游服务状态变化​

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

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> -n aic 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": "<generated-upstream-checker-for-nginx1>",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 1,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.5",
"status": "mostly_healthy"
}
],
"type": "http"
},
{
"name": "<generated-upstream-checker-for-nginx2>",
"nodes": [
{
"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": "<generated-upstream-checker-for-nginx1>",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 3,
"success": 0,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.4",
"status": "unhealthy"
}
],
"type": "http"
},
{
"name": "<generated-upstream-checker-for-nginx2>",
"nodes": [
{
"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": "<generated-upstream-checker-for-nginx1>",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 0,
"success": 1,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.4",
"status": "healthy"
}
],
"type": "http"
},
{
"name": "<generated-upstream-checker-for-nginx2>",
"nodes": [
{
"counter": {
"timeout_failure": 0,
"http_failure": 0,
"success": 1,
"tcp_failure": 0
},
"port": 80,
"ip": "172.25.0.5",
"status": "healthy"
}
],
"type": "http"
}
]