写点什么

思考 - 从传统雪崩到 K8S

用户头像
东风微鸣
关注
发布于: 2020 年 11 月 01 日
思考 - 从传统雪崩到K8S

传统环境发生底层故障, 往往会产生雪崩效应, 需要人为干预涉及到各个环节, 而且 MTTR 长.


我一直在思考, 如何才能做的更好, 有哪些可以借鉴的先进经验.


最近一直在学习 Kubernetes(以下简称为 K8S), 越了解越感到谷歌的理念先进, K8S 的博大精深. K8S 是谷歌开源的容器集群编排管理系统, 是谷歌多年大规模容器管理技术 Borg 的开源版本, 主要功能包括:


● 基于容器的应用部署、维护和滚动升级

● 负载均衡和地址发现

● 跨机器和跨地区的集群调度

● 自动伸缩

● 无状态服务和有状态服务

● 广发的 Volume 支持

● 插件机制保证扩展性

K8S 的设计理念与分布式系统

API 设计原则

● 所有的 API 应该是声明式的. 对于重复操作的效果更稳定. 同时这些名词也描述了用户期望得到的一个目标.

控制机制设计原则

● 控制逻辑应该只依赖于当前状态. 保证分布式系统的稳定可靠.

假设任何错误的可能, 并作容错处理. 在一个分布式系统中, 出现局部和临时错误是大概率事件. 错误可能来自于物理系统故障, 外部系统故障也可能来自于系统自身, 因此要设计对任何可能错误的容错处理.

● 每个模块都可以在出错后自动恢复: 每个模块都要有自我修复的能力, 保证不会因为连接不到其他模块而自我崩溃.

● 每个模块都可以在必要时优雅地降级服务. 这是对系统鲁棒性的要求, 保证基本功能不会依赖高级功能.


对传统雪崩故障的思考

对于传统故障的思考, 也让我愈发觉得 K8S 的设计之精妙. 以下罗列一些自己的各种散乱的对比:

应用视角

现在都是以应用为核心, 以用户体验为核心. 那么出了故障后, 最重要的是如何做到从应用角度来梳理、排查、快速回复和验证。

而在 K8S 中, 是通过命名空间namespace来提供隔离. 而我们也往往通过namespace来拆分应用: 一个namespace就是一个系统, 1 个deployment就是一个系统的应用. 通过进入到namespace, 可以清楚地看到各项资源和应用的运行情况是否正常. 是否需要进行下一步操作.

快速恢复

如何做到快速恢复? 越自动化, 自我修复能力越强. 恢复越快. 很简单的道理: 如果这个恢复需要用到人, 而他/她正好在进行人生大事没法立即处理. 那么就快不了.

而在 K8S 中, 关于快速恢复, 如上文所述, K8S 设计之初就考虑到了这一点. 另外, 为了做到部署在其上的应用的快速恢复, 至少有以下几项措施:


  1. 部署在 K8S 上的应用(deployment)刚开始会配置一个期望的副本数(通过RC控制) – 出现故障导致副本数降低, RC会自动启动运行新的 POD 副本以达到期望的副本数. 多于指定数目, RC 就会杀死多余的 pod 副本. 即使指定数为 1, RC 也能发挥它的高可用, 保证永远有 1 个 pod 在运行. 如果在传统环境, 可能会发生: 少启动, 甚至多启动而导致的各种次生灾害.

  2. 如果故障导致某几台主机不可用 - K8S 会自动将这些主机上的 pod 调度到其他可用主机。而这个调度是无需干预, 无感知的.

应用监控

关于应用监控, 拆开细说又是一个庞大的话题. 这里只讨论简单的实现.

当今, 出了故障:

  1. 首先, 我希望通过监控发现应用或服务是否可用?

  2. 启动好之后, 我希望通过监控知道这些应用是否已经准备好对外提供服务.

传统环境下, 运维人员或监控可能知道所有应用或服务的可用性. 底层出故障:不清楚该系统, 该服务, 该节点是否不可用; 启动了之后, 不清楚该系统, 该服务, 该节点是否恢复正常.

而在 K8S 中, 关于应用可用性监控. K8S 提供了 2 个标准的 Probe:

● LivenessProbe

● ReadinessProbe


每个 pod 都会配置 2 个探针,Readiness 和 liveness。以应用实例举例来说, liveness 就是刚启动,端口监听了就是 liveness;readiness 就是实例为 running 状态, 应用的某个页面可以访问了就是 readiness。以数据库举例来说, liveness 就是端口已监听; readiness 就是执行了SELECT 1 FROM DUAL且返回正常. 为 readiness 流量才会分发进来。这就保证了基本的可用性检测全覆盖.

信息准确性

当今, 出了故障, 网络拉取了一个表, 主机拉取了一个表, 数据库拉取了一个表, 应用运维拉取了一个表. 结果这些表可能存在:

● 信息不准确(已经下线的还显示为运行中状态)

● 关键信息对不上(主机的表里, 叫 A 系统; 应用运维的表里, 就叫A'系统了.)


而在 K8S 中, 通过 K8S 的一套完整的体系. 信息是这样进行维护的:

● Namespace – 对应系统

● Deployment – 对应具体应用或微服务

● Pod – 对应具体应用实例

● Volume – 对应存储卷.

● SVC – 对应内部负载均衡和服务发现

● Ingress – 对应外部访问 URL

● ...


与应用相关的每个资源都通过 yaml 定义, 并存储在 K8S 的 etcd 存储中. 保证信息环环相扣且无遗漏. 出现故障, 可以迅速分析:

  1. 整个系统是否正常;

  2. 具体的某一个应用或微服务是否正常

  3. 具体的应用实例是否正常

  4. 具体的存储卷是否正常

  5. 具体的内部负载均衡是否正常, 服务是否可以内部访问和分发

  6. 对外服务 URL 是否正常

  7. ...

存储

当今, 假如发生存储故障, 可能会导致:

  1. OS 卷异常;

  2. 中间件/数据库卷异常, 进而服务异常;

  3. 应用实例/微服务实例的日志存储卷\配置存储卷\持久化存储卷异常, 进而业务异常.

如果上述的其中一项未修复, 那么整个系统对外服务还是不可用的. 还是需要深入排查和分析. 那么底层的类似存储故障就会如雪崩一般, 影响范围迅速扩散.

而在 K8S 中, 具有以下 2 个概念:

● Persistent Volume - 持久存储卷(PV)

● Persistent Volume Claim - 持久存储卷声明(PVC)


PV 和 PVC 使得 K8S 集群具备了存储的逻辑抽象能力, 使得在配置 pod 的逻辑里可以忽略对实际后台存储技术的配置, 而把这项配置的工作交给 PV 的配置者, 即集群的管理者. PV 是资源的提供者, 根据集群的基础设施变化而变化, 由 K8S 集群管理员配置; 而 PVC 是资源的使用者, 根据业务服务的需求变化而变化, 由 K8S 集群的使用者即服务的管理员来配置.


这样, PV 和 PVC 可以将 pod 和数据卷解耦, pod 不需要知道确切的文件系统或者支持它的持久化引擎.


在发生故障时, 首先可以通过查看 PV 状态, 知道存储故障的范围. 通过查看 PVC 状态, 知道存储故障对服务的影响范围. 如果存储故障无法快速恢复, 可以尝试将 PVC 解绑, 并绑定到另一个正常的 PV 上.

总结和反思

反思一

通过以上的零散的思考, K8S 的出现确实会给正在为到处救火的运维提供一个更好的解决方案. 虽然任何一项新技术的引入, 都会引入新的问题. 但是在如今分布式系统大行其道的今天, K8S 确实值得引入.

反思二

犹豫, 就会败北



上层应用已经发生巨大变化的今天, 底层技术也要果断跟进;

如果还是"苦练功夫", 功夫练的再高, 也撑不过扳机扣动的霎那.


附录: 


发布于: 2020 年 11 月 01 日阅读数: 72
用户头像

东风微鸣

关注

资源共享, 天下为公! 2018.11.08 加入

APM行业认证专家, 容器技术认证专家. 现任中国大地保险PAAS平台架构师. 公众号:东风微鸣技术博客

评论

发布
暂无评论
思考 - 从传统雪崩到K8S