nacos与k8s service健康检查详解

  • Nacos健康检查是由什么参数控制的?

  • k8s service健康检查配置是由什么参数控制的?

  • 如果k8s deployment滚动更新,在endpoint中会立即把对应需要替换的某一个pod给删除吗?

  • 旧版本的 Pod 被标记为 Terminating 的时间点是一个新的pod恰好ready的时候吗?

Tips:文末有思考题

Nacos健康检查

Nacos 中,服务实例可能会在某些条件下自动下线(即被标记为不健康,并从可用实例列表中移除)。这种行为通常由以下机制控制:


服务实例自动下线的条件

心跳超时(主要原因)

  • Nacos 客户端需要定期向服务端发送心跳信息,告知其状态为健康。

  • 如果在指定时间内(超时时间)未收到心跳,Nacos 服务端会将该实例标记为 不健康,并从负载均衡的候选列表中移除。

实例注销

  • 客户端显式调用 deregisterInstance() 方法,主动注销服务实例。

  • 应用进程在启动或关闭时也可能触发实例的注册和注销。

服务端检测异常

  • 服务端主动健康检查(如 TCP 或 HTTP 探针)失败,实例被标记为不健康。

网络异常

  • 客户端与 Nacos 服务端之间的网络连接中断。

  • 客户端宕机或网络不通导致心跳发送失败。


相关参数控制服务实例下线

1. 客户端心跳相关参数

这些参数主要配置在客户端( application.yml 或代码中)。

  • nacos.naming.heartbeat.interval

    描述:客户端发送心跳的间隔时间。

    默认值:5000 毫秒(5秒)。

    控制作用:降低心跳间隔可以减少误判实例下线的可能性。

    示例配置

properties 复制代码
nacos:
  naming:
    heartbeat:
      interval: 3000 # 心跳间隔为 3 秒

nacos.naming.health-check.retry

描述:在实例标记为不健康之前,允许的心跳重试次数。

默认值:3 次。

示例配置

properties 复制代码
nacos:
  naming:
    health-check:
      retry: 5 # 尝试重试 5 次

nacos.naming.health-check.timeout

描述:服务端判断实例下线的超时时间。

默认值:15,000 毫秒(15秒)。

示例配置

properties 复制代码
nacos:
  naming:
    health-check:
      timeout: 20000 # 超时时间设置为 20 秒

2. 服务端健康检查相关参数

这些参数主要配置在 Nacos 服务端( application.properties 文件)。

server.health-check.task.interval

  • 描述:服务端执行健康检查任务的时间间隔。

  • 默认值:5000 毫秒(5秒)。

  • 示例配置

bash 复制代码
server.health-check.task.interval=3000 # 每 3 秒执行一次健康检查任务

server.health-check.timeout-ms

  • 描述:服务端允许实例心跳的最大超时时间。

  • 默认值:15000 毫秒(15秒)。

  • 控制作用:心跳超时后,服务端会将实例标记为不健康。

  • 示例配置

bash 复制代码
server.health-check.timeout-ms=20000 # 心跳超时设置为 20 秒

server.health-check.retry

  • 描述:服务端重试健康检查的次数。

  • 默认值:3 次。

  • 示例配置

ruby 复制代码
server.health-check.retry=5 # 允许 5 次重试

3. 服务实例元数据相关参数

在服务注册时,通过元数据可以设置一些特定健康检查参数。

元数据设置健康检查(例如 HTTP 探针)

  • Nacos 支持在实例元数据中指定健康检查探针。

  • 示例:

sql 复制代码
metadata:
  check: "http"
  check_url: "http://127.0.0.1:8080/health"
  timeout: 5000 # 超时时间 5 秒

ephemeral 参数

  • 描述:实例是否为临时实例。

  • 临时实例依赖心跳维持状态,超时会自动下线;而非临时实例不会因心跳超时而被移除,需手动注销。

  • 配置:

ruby 复制代码
namingService.registerInstance("service-name", "127.0.0.1", 8080, "DEFAULT", true); // true 表示临时实例

其他注意事项

服务端与客户端时间一致性

  • 如果服务端和客户端的系统时间不一致,可能会导致心跳超时误判。

  • 确保时间同步(如 NTP 配置正确)。

服务端性能

  • 如果 Nacos 服务端负载过高,健康检查任务可能延迟,导致实例被错误标记为不健康。

网络抖动

  • 在网络状况较差时,心跳包可能丢失,建议适当增加超时时间和重试次数。

总结

  • 自动下线主要由心跳机制控制,客户端与服务端都需要正确配置心跳间隔、超时时间和重试次数。

  • 客户端主要通过 heartbeat.intervalhealth-check.timeout 控制心跳逻辑。

  • 服务端通过 server.health-check.timeout-ms 和相关参数执行健康检查任务。

  • 临时实例和非临时实例的健康检查行为不同,需根据场景合理选择。

k8s service健康检查配置是由什么参数控制的?

在 Kubernetes (K8s) 中,Service 的健康检查主要通过 Liveness ProbeReadiness ProbeStartup Probe 来实现。这些探针的配置决定了 Pod 的健康状态,并间接影响 Service 的行为,例如负载均衡和流量分发。


探针的类型和作用

Liveness Probe

  • 作用:检测 Pod 是否处于"活着"的状态。

  • 不健康时动作:重启容器。

  • 适用场景:应用进入死循环、卡死或内部错误时。

Readiness Probe

  • 作用:检测 Pod 是否可以接收流量。

  • 不健康时动作:从 Service 的负载均衡目标列表中移除。

  • 适用场景:应用启动缓慢、依赖外部资源时。

Startup Probe

  • 作用:检测应用是否启动完成。

  • 不健康时动作:重启容器。

  • 适用场景:应用启动时间较长,防止 Liveness Probe 误判。


健康检查的实现方式

健康检查通过以下方式执行,所有探针都支持这些方式:

HTTP GET 请求

  • 向指定的 HTTP 端点发送 GET 请求,如果返回的状态码在 200--399 范围内,则为健康。

  • 示例配置

properties 复制代码
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 3
  periodSeconds: 5

TCP Socket

  • 尝试连接到容器指定端口,如果能建立连接则认为健康。

  • 示例配置

properties 复制代码
readinessProbe:
  tcpSocket:
    port: 3306
  initialDelaySeconds: 10
  periodSeconds: 5

命令执行(Exec)

  • 在容器中运行指定命令,如果返回码为 0 则为健康。

  • 示例配置

properties 复制代码
livenessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5

关键参数

以下参数控制探针行为:

initialDelaySeconds

  • 描述:探针在容器启动后等待多少秒才开始探测。

  • 适用场景:设置应用初始化所需的时间。

  • 默认值:0。

periodSeconds

  • 描述:探针的探测频率,单位为秒。

  • 默认值:10 秒。

timeoutSeconds

  • 描述:探针的超时时间。

  • 默认值:1 秒。

successThreshold

  • 描述:探针连续成功的次数,表示从不健康到健康的阈值。

  • 默认值

    • Readiness Probe:1。

    • Liveness ProbeStartup Probe:无效。

failureThreshold

  • 描述:探针连续失败的次数,表示从健康到不健康的阈值。

  • 默认值:3。


示例完整配置

以下是一个完整的探针配置示例:

properties 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: probe-demo
spec:
  containers:
  - name: my-app
    image: my-app:latest
    ports:
    - containerPort: 8080
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds: 1
      failureThreshold: 3
    readinessProbe:
      httpGet:
        path: /readyz
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds: 1
      successThreshold: 1
      failureThreshold: 3
    startupProbe:
      httpGet:
        path: /startz
        port: 8080
      initialDelaySeconds: 0
      periodSeconds: 10
      timeoutSeconds: 1
      failureThreshold: 60

Service 与健康检查的关系

  • Liveness ProbeStartup Probe 的状态不影响 K8s Service 的流量分发,仅用于控制 Pod 的重启。

  • Readiness Probe 的状态直接影响 Service 的流量分发。

  • 当 Readiness Probe 检测为"不健康"时,Pod 将从 Endpoints 中移除,Service 不再向该 Pod 分发流量。


常见问题与优化

探针频率过高

  • 会增加容器和 K8s 控制平面的负载。调整 periodSecondstimeoutSeconds 平衡性能与可靠性。

初始延迟不足

  • 如果 initialDelaySeconds 设置过短,探针可能误判启动中的容器为不健康。

网络不稳定

  • 在使用 HTTP GET 或 TCP Socket 时,短暂网络抖动可能导致探针失败,适当提高 failureThreshold

通过探针配置,K8s 提供了灵活的健康检查机制,可以结合实际场景优化探针参数和探测方式,实现稳定可靠的服务状态监控。

如果k8s deployment滚动更新,在endpoint中会立即把对应需要替换的某一个pod给删除吗?

在 Kubernetes 中,滚动更新 (Rolling Update)是默认的部署策略,用于逐步替换旧版本的 Pod 为新版本的 Pod。关于是否会立即将需要替换的某一个 Pod 从 Endpoints 中删除,这取决于以下机制:


Endpoints 的处理流程

启动阶段

  • 在滚动更新中,新版本的 Pod 会先启动。

  • Kubernetes 会检测新 Pod 的 Readiness Probe 是否通过。

删除阶段

  • 在旧版本的 Pod 被标记为 Terminating 后,它的 Readiness Probe 会立即失效。

  • Endpoints Controller 会实时更新,移除对应 Pod 的 IP 地址。

  • 即,Pod 会立即从 Endpoints 中移除,但实际的 Pod 删除过程可能稍后完成。


滚动更新中的行为

默认行为

  • Kubernetes 遵循"先启动新 Pod,再终止旧 Pod"的逻辑,具体由 maxUnavailablemaxSurge 参数控制:

    • maxUnavailable:最大允许同时不可用的 Pod 数量。

    • maxSurge:最大允许超出指定 Pod 副本数的新增 Pod 数量。

  • 旧 Pod 在 Terminating 阶段会被从 Endpoints 中移除,因此流量不会再分发给该 Pod。

Graceful Termination(优雅终止)

  • Pod 的终止过程遵循 TerminationGracePeriodSeconds 的配置(默认 30 秒)。

  • 如果应用需要完成清理任务(如关闭连接或完成当前请求),可以在 Pod 的生命周期回调(如 preStop hook)中实现。

  • 即使 Pod 尚未完全删除,只要 Readiness Probe 判定不健康,它的 IP 仍会被移除。


关键参数和行为

以下配置项会影响滚动更新过程中 Pod 在 Endpoints 中的处理方式:

readinessProbe

  • 确保旧 Pod 的 Readiness Probe 失效后流量停止分发。

  • 配置示例:

properties 复制代码
readinessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 3
  periodSeconds: 5

Deployment 策略中的 maxUnavailablemaxSurge

  • maxUnavailable:定义最多有多少个 Pod 可以同时不可用。

  • maxSurge:定义最多可以多出多少个新 Pod。

  • 配置示例:

properties 复制代码
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1
    maxSurge: 1

TerminationGracePeriodSeconds

  • Pod 在被标记为 Terminating 后的优雅终止时间,决定清理任务完成的时间。

  • 配置示例:

properties 复制代码
spec:
  terminationGracePeriodSeconds: 30

Service 的 publishNotReadyAddresses 参数

  • 默认情况下,未准备好的 Pod 地址(即 Readiness Probe 失败的 Pod)不会加入 Endpoints。

  • 如果启用了 publishNotReadyAddresses:true,即使 Pod 未准备好,仍会暴露在 Endpoints 中。

  • 配置示例:

properties 复制代码
spec:
  publishNotReadyAddresses: true

总结

  • 在滚动更新过程中,Pod 被替换时,旧 Pod 会立即从 Endpoints 中移除,但实际 Pod 的删除可能会等待优雅终止完成。

  • 流量中断的防控

  • 配置合理的 Readiness ProbeTerminationGracePeriodSeconds

  • 设置合适的 maxUnavailablemaxSurge,保证服务有足够可用的 Pod。

    调试 Endpoints 的变化

    运行以下命令查看 Service 的 Endpoints:

cs 复制代码
kubectl get endpoints <service-name> -o yaml

旧版本的 Pod 被标记为 Terminating 的时间点是一个新的pod恰好ready的时候吗?

在 Kubernetes 的滚动更新过程中,旧版本的 Pod 被标记为 Terminating 的时间点 和新 Pod 的状态(特别是 Ready 状态)之间的关系,取决于 Deployment 策略参数配置


默认情况下的行为

滚动更新的逻辑

  • Kubernetes Deployment 默认使用 RollingUpdate 策略。

  • 控制 Pod 替换顺序的关键参数是:

    • maxUnavailable:允许的最大不可用 Pod 数量。

    • maxSurge:允许的最大超额新增 Pod 数量。

  • 具体行为:

  1. 新 Pod 启动并等待变为 Ready

  2. 确保服务总的可用 Pod 数量不低于 replicas-maxUnavailable

  3. 一旦满足条件,旧 Pod 被标记为 Terminating,并从 Endpoints 中移除。

  4. Kubernetes 会继续这一过程,直到完成所有 Pod 的替换。

是否等待新 Pod 就绪(Ready)

  • 默认情况下,滚动更新会等待一个新 Pod Ready 后才开始终止一个旧 Pod

  • 这是因为 maxUnavailable 参数控制了同时不可用的 Pod 数量,默认为 1。


例外情况

maxUnavailable > 0
  • 如果允许一定数量的不可用 Pod,则 Kubernetes 不需要等待新 Pod Ready,可能会同时终止旧 Pod 并启动新 Pod。

  • 示例配置

properties 复制代码
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 2
    maxSurge: 1

在这种情况下,旧 Pod 可能会提前进入 Terminating 状态,即便新 Pod 尚未完全 Ready

新 Pod 长时间未 Ready
  • 如果新 Pod 因配置问题或资源不足而无法变为 Ready,旧 Pod 的终止可能被延迟。

  • Kubernetes 依赖 ProgressDeadlineSeconds 参数定义超时时间。

  • 如果在指定时间内更新未完成,Deployment 将进入失败状态。

  • 默认值:600 秒。

  • 配置示例:

makefile 复制代码
spec:
  progressDeadlineSeconds: 300  # 5分钟内未完成滚动更新则标记失败
优雅终止时间(Graceful Termination)影响
  • 旧 Pod 的 TerminationGracePeriodSeconds 参数也会影响滚动更新的节奏:

  • 如果设置时间较长(默认 30 秒),即使新 Pod 已 Ready,旧 Pod 也可能延迟退出。

  • 配置示例:

properties 复制代码
spec:
  terminationGracePeriodSeconds: 60

总结:是否等新 Pod Ready 再终止旧 Pod

  • 默认情况是的 ,滚动更新会等待一个新 Pod 变为 Ready,再终止一个旧 Pod。

  • 特殊情况

  • 如果设置了 maxUnavailable>0progressDeadlineSeconds 超时 ,可能会在新 Pod 未完全 Ready 的情况下终止旧 Pod。

  • 配置了较长的 TerminationGracePeriodSeconds ,可能会让旧 Pod 在新 Pod 已 Ready 的情况下仍保持运行一段时间。


如何调试滚动更新状态

查看 Pod 状态

cs 复制代码
kubectl get pods -w
  • 可以实时观察新 Pod 的创建和旧 Pod 的 Terminating 状态变化。

查看 Deployment 策略

cs 复制代码
kubectl get deployment <deployment-name> -o yaml
  • 检查 rollingUpdate 的配置参数。

检查更新进度

xml 复制代码
kubectl rollout status deployment <deployment-name>
  • 查看更新是否卡住或超时。

通过合理配置参数,可以精确控制滚动更新过程,避免新旧 Pod 的流量切换产生中断问题。


思考:为什么流量打到了不健康的pod上?

相关推荐
aherhuo1 小时前
kubevirt网络
linux·云原生·容器·kubernetes
陌北v11 小时前
Docker Compose 配置指南
运维·docker·容器·docker-compose
catoop2 小时前
K8s 无头服务(Headless Service)
云原生·容器·kubernetes
阿里嘎多学长2 小时前
docker怎么部署高斯数据库
运维·数据库·docker·容器
小峰编程2 小时前
独一无二,万字详谈——Linux之文件管理
linux·运维·服务器·云原生·云计算·ai原生
小马爱打代码3 小时前
云原生服务网格Istio实战
云原生
liuxuzxx3 小时前
1.24.1-Istio安装
kubernetes·istio·service mesh
G_whang4 小时前
windos 安装docker
运维·docker·容器
道一云黑板报4 小时前
Flink集群批作业实践:七析BI批作业执行
大数据·分布式·数据分析·flink·kubernetes
运维小文4 小时前
K8S中的PV、PVC介绍和使用
docker·云原生·容器·kubernetes·存储