Kubernetes查漏补缺
Kubernetes查漏补缺
在【超聚变】的日子里天天跟 Kubernetes 打交道,即使如此对它的认识依旧浅显,只是停留在部署服务、定位问题上,虽然我还曾基于 CRD 设计出了服务插件化接入,但对深层的控制和网络等依旧知之甚浅。
一部分原因是当时忙于业务和毕设,没有太多精力去深入,另一方面毕竟 Kubernetes 建立在 Google 大规模运行生产工作负载十几年经验 的基础上,结合了社区中最优秀的想法和实践,难度也确实有些大。
最近看了一些相关的书,发现了一些之前未曾注意到的知识,在这里整理了下,由于不是科普向且查漏补缺,所以本篇的逻辑性与关联性可能不甚清晰。
Node
kubelet 有两个参数可以控制镜像删除的行为,一个是 image-gc-high-threshold,另一个是 image-gc-low-threshold,它们的值默认是 85% 和 80%,这意味着当磁盘使用率达到 85% 的时候自动执行清理,并将磁盘使用率降到 80%。不过一般不用担心,由于镜像层次之间的复用性,并不是每次拉取镜像都会额外占用一份镜像空间大小。
Pod 与控制器
Pod 不具备自动恢复能力,所以需要 ReplicaSet,ReplicaSet 只在副本数发生变动时有感知,所以需要更上层的 Deployment/StatefulSet,Deployment 的滚动更新是通过 ReplicaSet 实现的:
1 | |
1 | |
当发生更新时,会创建新的 replicaset,旧的 replicaset 期望数会变为 0。
Deployment 在更新 Pod 时默认会采用 RollingUpdate 也就是滚动更新的方式,它不会造成业务停机
1 | |
max surge 用来指定最大超出期望 Pod 的个数,max unavailable 是允许 Pod 不可用的数量,以期望 8 个副本数的工作负载为例,max unavailable 的值为 25% ,也就是 2,max surge 的值为 25%,也是 2,那么在滚动更新时,更新策略是:
- 更新期间最多会有 10 个 Pod(8 个所需的 Pod + 2 个 max surge Pod)处于运行状态;
- 更新期间至少会有 6 个 Pod(8 个所需的 Pod - 2 个 max unavailable Pod)处于运行状态。
当 kubernetes 决定要驱逐 Pod 的时候,按照 未配置资源配额、Request 小于 Limit、Request 等于 Limit 的顺序驱逐,对于一些基础核心组件,例如中间件或者核心服务,可以将 Request 预估为一个 较高的合理水平,并且将 Limit 配置为相同的值。
HPA 需要安装 Metrics Server 和为工作负载配置资源 Request 才能工作。
对于启动非常慢的大型应用,随意配置 Readiness 和 Liveness 探针,Pod 将因为探针失败而永远无法启动。修改初始检测时间等字段虽然有效但降低了 kubernetes 检测 Pod 健康状态的频率,这会延迟 kubernetes 感知故障的速度。可以用 StartupProbe 探针来解决这个问题。
- Readiness 就绪探针可以让 kubernetes 感知到业务的 Ready 就绪状态,以此来控制什么时候将 Pod 加入到 EndPoints 列表中接收外部流量;
- Liveness 存活探针当感知到 Pod 不健康时,会重启 Pod;
- StartupProbe 探针主要用来解决服务启动慢的问题。
Service
Pod 每次创建都会分配一个新的 IP,无法进行固定访问,Service 将一组来自同一个 ReplicaSet 创建的 Pod 组合在一起,并提供 DNS 的访问能力。
Service 在集群内拥有唯一的 IP 地址,并且这个 IP 是稳定的(但是删了重新建会获得一个新的 IP)。此外,Service 本身并没有直接提供服务发现的能力,它需要借助 Endpoints 来实现。Endpoints 记录了一组 Pod 的 IP 地址,Service 只需要查看自身所对应的 Endpoints 便能够找到具体的 Pod。
1 | |
Service 通过 selector 选择关联的 Pod,通过 metadata.name 关联 endpoints,如下的示例就会关联 app.kubernetes.io/name=redis-cluster 的 Pod,port 字段代表 Service 监听端口,targetPort 字段代表将请求转发到 Pod 时的目标端口。
1 | |
Service 只有在创建后才会分配得到 IP,且删除后重建还会分配新的 IP,所以也需要一个 IP 无关的唯一标识:
1 | |
日常可以省略 .svc.cluster.local,同一命名空间下 namespace 也可以省略,即同一命名空间下可以这么访问:
1 | |
所以在 A Pod 访问其它服务的 B Pod 时的流程其实是:
1 | |
ExternalName 类型的 Service 可以将 Service 和另外一个命名空间的 Service 关联起来
1 | |
为了统一访问,还可以创建 Service 和 EP 绑定外部服务地址,如下示例展示了如何在当前集群内通过 service 访问外部的 mysql 服务:
1 | |