在传统的软件测试中,我们通常通过一个给定的条件来判断系统的反馈,通过断言来判断是否符合预期,测试条件和结果通常比较明确和固定。而混沌工程,是通过注入一些“不确定”因素,象放进了一群淘气的猴子,在系统资源、可用性、安全性、延迟、压力等方面进行捣乱,而此过程中,要求系统可以毫无影响的提供服务,用户无感知。
  
  这其实对系统的自愈能力,健壮性都有很高的要求。故障注入一般是指比较受控的一些实验条件,通过注入一些相对极端的异常场景,为系统提供可靠性测试的过程。 整体来说,混沌是一种故障注入规则,强调了一些不确定性、随机性,比较常见的"猴子"有 Netflix 的"猴子军团",可以用来随机关闭系统实例,注入延时,回收资源,检查安全漏洞等等。
  
  开源工具介绍
  
  除了一般系统的 monkey,基于 Kubernetes 已经有一些"猴子"工具可以测试系统的健壮性。接下来,介绍一下比较常见的三种 Kubernetes monkey:
  
  kube-monkey
  
  http://dasheng178.com/#portal/list.html
  
  运行方式:kube-monkey 通过 label 设置受害者 pod,创建了一个单独的 kube-monkey pod 对受害者 pod 施加影响;
  
  注入类型:目前支持的故障注入类型仅有杀容器;
  
  配置项:可以通过配置文件设置运行周期和频率,在一定时间内随机的杀死打标范围内的 pod。
  
  powerfulseal
  
  https://github.com/bloomberg/powerfulseal
  
  注入类型:powerfulseal 的故障注入类型包括杀 pod 和启停 node。
  
  运行方式:包括交互模式,自动模式、打标模式和示例模式。交互模式通过界面交互查询node/namespace/pod,启停 node 或杀死 pod 操作;自动模式通过读取配置文件确定注入范围,注入频率;打标模式通过给 pod 打标确定注入的靶向 pod 及注入频率;示例模式可以反映根据使用资源情况进行故障注入的过程。
  
  Chaos Toolkit-kubernetes
  
  https://github.com/chaostoolkit/chaostoolkit-kubernetes
  
  />
  
  是 chaos 工具包中的一个,通过 chaos run experiment.json 设置 json 文件来指定 namespace,正则匹配名字等等来随机杀一个 pod。
  
  以上三种"猴子",主要是基于杀 pod 场景来注入故障,虽然是最有力的场面但是比较有局限性,对于商业化系统面临的复杂场景,是值得参考但是不够的。
  
  结合 Ali Kubernetes 故障场景分析
  
  Ali Kubernetes 作为一个管理大规模集群的商业调度系统,需要应对的不仅包括一些基本的 Kubernetes 中 pod 误删误停的故障现象,也包含一些底层 OS、内核、网络、误配置等灾难场景。同时由于其支撑业务生态的复杂性,全链路综合异常流也需要特殊的验证。
  
  为更系统的进行演练,在过程中主要进行了以下几部分工作:
  
  FMEA 分析就是失效模式和效果分析,旨在对系统范围内潜在的失效模式加以分析,以便按照严重程度加以分类,或者确定失效对于该系统的影响。
  
  从故障场景上,分析得出较为符合 Ali Kubernetes 的三大类场景:
  
  通用故障场景:包括网络相关故障(网络 iohang ,断网,网络延迟等),宿主机相关故障(机器重启,机器 load 高等)
  
  Ali Kubernetes 业务场景故障:包括 Kubernetes 相关的故障(pod 删除,pod patch等),pod 迁移,混部、etcd 等业务相关场景;
  
  chaos 故障:较为随机的故障注入,可以为以上任何故障的组合
  
  从影响面上,需要 case by case 确定影响范围为无任何影响,仅影响部分功能,影响核心功能等等;从验证恢复手段上,也可以分为自动恢复、手动恢复,同时需要关注监控情况及恢复时间。
  
  在分析过程中,我们发现,已有的开源工具无法完全满足 Ali Kubernetes 的故障场景。下面举 2 个典型故障场景:
  
  pod 被误删
  
  这个场景并不是简单的 pod 随机删除,而是在 kubelet 连错 apiserver 配置等异常情况下,重启 ali-kubelet 后,al 自行判断了容器在当前集群内不存在,自己做了删除操作。
  
  要引入这个故障需要修改 kubelet 组件的配置,重启 kubelet,才算是真正引入了故障,而当前的无论是 kube-monkey 还是 powerfulseal 场景都无法满足。
  
  master 组件断网
  
  有的人可能会说,直接指定 master 组件的机器引入断网操作,是不是就可以了呢?然鹅现实是比较骨感的,我们也许只知道这个 master 所在集群的 kubeconfig,组件的机器其实也可以随着每次升级变动的。在仅仅已知 kubeconfig 的情况下我们只能先查一下 master 组件的机器信息,再在机器上引入断网的操作,才算是一个整体的故障引入。而目前所有的开源工具也没有此类稍微复杂一些的场景,只是通过指定 pod namespace 来随机的删除一些 pod。
  
  所以综上所述,其实我们需要对此进行扩展开发,除了简单的杀 pod,我们亟需一套可以自由开发的小程序,把这个步骤拼接起来,进行更为复杂的故障注入。
  
  套件实现
  
  为了满足此类复杂的故障注入,我们使用了目前集团内正在开发的一套故障注入系统 monkeyking,并在它的基础上扩展了一些 kubernetes 相关的套件,来达到既可以注入 kubernetes 相关的故障,又可以注入一些通用故障,同时又可以相对自由的扩展故障集合的目的。
  
  这个故障注入的演练流程如下图所示:
  
  2
  
  它的每一个步骤都可以是我们自由扩展的一个或者多个小程序,各个小程序之间的执行顺序也可以自由的定义。考虑到 Ali Kubernetes 的场景,我们在其中扩展了四大类小程序套件。
  
  通用故障小程序
  
  在这一部分主要实现了一些比较通用的 os 故障,网络故障,比如最基本的指定一个宿主机断网,指定宿主机重启这类。
  
  Kubernetes 套件小程序
  
  这一部分主要实现了一些通用的 Kubernetes 命令,通过指定这些命令和入参,我们可以执行比如 create delete apply patch 这些操作,来间接的达到注入一些 Kubernetes 相关故障的目的。
  
  实现原理如下:
  
  要点说明如下:
  
  下载集群证书的地址及证书的 md5 码都作为小程序的输入,在执行实际的 kubectl 生效命令前进行下载校验;
  
  底层 toolkit 中已经加入了 kubectl 命令行工具,无需自己找环境进行配置和下载;
  
  目前已经支持了 apply,create,delete,patch,get 操作,支持指定 label,namespace,-o json 的操作
  
  举个例子,上文中 master 组件故障的场景中,我们就可以利用以上的两类小程序来完成故障注入的操作:
  
  开源工具小程序
  
  目前我们和集团安全生产的 MonkeyKing 团队合作,联合在故障注入平台 monkeyking 中集成了开源工具 kube-monkey,实现过程借助了上文的 kubernetes 套件执行,可以通过打标的方式标记受害者,让 kube-monkey 随机的杀受害者 pod。步骤如下:
  
  环境准备
  
  锁演练环境
  
  在当前集群中初始化kube-monkey: 使用kubernetes套件的apply功能提交km-config.yaml文件,部署 kube-monkey deployment
  
  给应用标记受害者 label
  
  使用 Kubernetes 套件的 patch 功能,标记受害者
  
  验证步骤
  
  自定义组件校验应用服务是否可用
  
  故障恢复
  
  使用 Kubernetes 套件的 patch 功能,给受害者去标
  
  使用 Kubernetes 套件的 delete 功能,删除 kube-monkey deployment
  
  解锁演练环境
  
  from wsgiref.simple_server import make_server
  
  2
  
  3 def f1():
  
  4 f1=open("index1.html","rb")
  
  5 data1=f1.read()
  
  6 return [data1]
  
  7
  
  8 def f2():
  
  9 f2=open("index2.html","rb")
  
  10 data2=f2.read()
  
  11 return [data2]
  
  12
  
  13 def application(environ, start_response):
  
  14
  
  15 print(environ['PATH_INFO'])
  
  16 path=environ['PATH_INFO']
  
  17 start_response('200 OK', [('Content-Type', 'text/html')])
  
  18
  
  19
  
  20 if path=="/yuan":
  
  21 return f1()
  
  22
  
  23 elif path=="/alex":
  
  24 return f2()
  
  25
  
  26 else:
  
  27 return ["<h1>404</h1>".encode("utf8")]
  
  28
  
  29
  
  30 httpd = make_server('', 8502, application)
  
  31
  
  32 print('Serving HTTP on port 8084...')
  
  33
  
  34 # 开始监听HTTP请求:
  
  35 httpd.serve_forever()
  
  复制代码
  
  复制代码
  
  1 from wsgiref.simple_server import make_server
  
  2
  
  3
  
  4 def f1(req):
  
  5 print(req)
  
  6 print(req["QUERY_STRING"])
  
  7
  
  8 f1=open("index1.html","rb")
  
  9 data1=f1.read()
  
  10 return [data1]
  
  11
  
  12 def f2(req):
  
  13
  
  14 f2=open("index2.html","rb")
  
  15 data2=f2.read()
  
  16 return [data2]
  
  17
  
  18 import time
  
  19
  
  20 def f3(req): #模版以及数据库
  
  21
  
  22 f3=open("index3.html","rb")
  
  23 data3=f3.read()
  
  24 times=time.strftime("%Y-%m-%d %X", time.localtime())
  
  25 data3=str(data3,"utf8").replace("!time!",str(times))
  
  26
  
  27
  
  28 return [data3.encode("utf8")]
  
  29
  
  30
  
  31 def routers():
  
  32
  
  33 urlpatterns = (
  
  34 ('/yuan',f1),
  
  35 ('/alex',f2),
  
  36 ("/cur_time",f3)
  
  37 )
  
  38 return urlpatterns
  
  39
  
  40
  
  41 def application(environ, start_response):
  
  42
  
  43 print(environ['PATH_www.hengtongyoule.com INFO'])
  
  44 path=environ['PATH_INFO']
  
  45 start_response('200 OK', [www.jrgjze.com/('Content-Type', 'text/html')])
  
  46
  
  47
  
  48 urlpatterns = routers()
  
  49 func = None
  
  50 for item in urlpatterns:
  
  51 if item[0] == path:
  
  52 func = item[www.dfgjpt.com]
  
  53 break
  
  54 if func:
  
  55 return func(environ)
  
  56 else:
  
  57 return ["www.bsylept.com<h1>404</h1>".encode("utf8")]
  
  58
  
  59 httpd = make_server('www.dasheng178.com', 8518, application)
  
  60
  
  61 print('Serving HTTP on port 8084...')
  
  62
  
  63 # 开始监听HTTP请求:
  
  64
  
  65 httpd.serve_forever(www.yongshi123.cn)
  
  这一部分比较自由,主要根据 Ali Kubernetes 的业务需求,接入了一些常用的小程序。
  
  比如故障演练过程中,环境需要独占,不允许其他测试执行,在这里实现了一个小程序用来对环境进行加解锁操作;比如校验阶段需要验证服务是否可用,这里实现了一个通过 curl 命令校验返回值的方式验证服务是否可用的小程序;比如故障注入过程可能影响vip挂载,这里也实现了一个调用 vip 服务校验 vip 下 ip 数量及是否可用的小程序。
  
  总结
  
  在 Ali Kubernetes 中,我们将故障以场景化的方式进行沉淀,将底层 os,内核、网络、误配置等故障联合 Kubernetes 相关故障,引入混沌工程的理念进行注入,有效的发现了很多系统稳定性问题,驱动开发人员更多关注系统健壮性。
  
  后续我们会在 Ali Kubernetes 演进过程中持续发力,基于架构和业务场景输入更多 Kubernetes 相关的故障场景,为系统的高可用保驾护航。

在 Ali Kubernetes 系统中,我们这样实践混沌工程的更多相关文章

  1. 腾讯云分布式数据库TDSQL在银行传统核心系统中的应用实践

    本文是腾讯云TDSQL首席架构师张文在腾讯云Techo开发者大会现场的演讲实录,演讲主题是<TDSQL在银行传统核心系统中的应用实践>. 我是TDSQL架构师张文,同时也是TDSQL的开发 ...

  2. 浏览器对localstorage的支持情况以及localstorage在saas系统中的应用实践思考

    首先,还是要说,任何一种新特性的引入,通常有着其特有的场景和解决的目标需求,localstorage也一样.在我们的应用场景中,主要在金融业务服务的saas系统.其中涉及很多更改频率很多的元数据的客户 ...

  3. China .NET Conf 2019-.NET技术架构下的混沌工程实践

    这个月的8号.9号,个人很荣幸参加了China.NET Conf 2019 , 中国.NET开发者峰会,同时分享了技术专题<.NET技术架构下的混沌工程实践>,给广大的.NET开发小伙伴介 ...

  4. iOS系统中导航栏的转场解决方案与最佳实践

    背景 目前,开源社区和业界内已经存在一些 iOS 导航栏转场的解决方案,但对于历史包袱沉重的美团 App 而言,这些解决方案并不完美.有的方案不能满足复杂的页面跳转场景,有的方案迁移成本较大,为此我们 ...

  5. 应用在Windows系统中的自动化部署实践

    因为公司的产品有linux 和windows两套部署环境,领导安排我先来做windows的自动化部署.由于本人对windows 的dos命令基本没啥概念,所以在最终完成之前,走了很多弯路,在这里记载下 ...

  6. Kubernetes系统架构简介

    1. 前言 Together we will ensure that Kubernetes is a strong and open container management framework fo ...

  7. Kubernetes系统架构简介--转

    原文地址:http://www.infoq.com/cn/articles/Kubernetes-system-architecture-introduction?utm_campaign=infoq ...

  8. 网易云基于 Kubernetes 的深度定制化实践

    本文由  网易云发布. 2017 年,Kubernetes 超越 Mesos 和 Docker Swarm成为最受欢迎的容器编排技术.网易云从 2015 下半年开始向 Kubernetes 社区贡献代 ...

  9. (分享)Paxos在大型系统中常见的应用场景

    原帖http://timyang.net/distributed/paxos-scenarios/ 在分布式算法领域,有个非常重要的算法叫Paxos, 它的重要性有多高呢,Google的Chubby ...

随机推荐

  1. HNOI2018做题笔记

    HNOI2018 寻宝游戏(位运算.基数排序) 看到位运算就要按位考虑.二进制下,\(\land 1\)与\(\lor 0\)没有意义的,\(\land 0\)强制这一位变为\(0\),\(\lor ...

  2. Angularjs实现select的下拉列表

    练习使用angularjs实现一个select下拉列表: <div ng-app="selectApp" ng-controller="selectControll ...

  3. openMP多线程编程

    OpenMP(Open Muti-Processing) OpenMP缺点: 1:作为高层抽象,OpenMp并不适合需要复杂的线程间同步和互斥的场合: 2:另一个缺点是不能在非共享内存系统(如计算机集 ...

  4. 历时25天,我的博客(www.ityouknow.com)终于又活了过来

    时间回到2016年的7月10号,那时候我刚刚开始正式在博客园写博客,博客园的交流氛围很好,但鉴于博客园古老的界面,同时计划创建一个自己独立的博客,毕竟自己的博客怎么折腾都行. 那时候正在研究 Spri ...

  5. .NET持续集成与自动化部署之路第一篇——半天搭建你的Jenkins持续集成与自动化部署系统

    .NET持续集成与自动化部署之路第一篇(半天搭建你的Jenkins持续集成与自动化部署系统) 前言     相信每一位程序员都经历过深夜加班上线的痛苦!而作为一个加班上线如家常便饭的码农,更是深感其痛 ...

  6. 【CV】ICCV2015_Learning Temporal Embeddings for Complex Video Analysis

    Learning Temporal Embeddings for Complex Video Analysis Note here: it's a review note on novel work ...

  7. mysql数据库忘记密码时如何修改

    工具/原料 mysql数据库 cmd命令行 打开mysql.exe和mysqld.exe所在的文件夹,复制路径地址 打开cmd命令提示符,进入上一步mysql.exe所在的文件夹

  8. PAT 1039 到底买不买

    https://pintia.cn/problem-sets/994805260223102976/problems/994805283241443328 小红想买些珠子做一串自己喜欢的珠串.卖珠子的 ...

  9. PAT 1022 D进制的A+B

    https://pintia.cn/problem-sets/994805260223102976/problems/994805299301433344 输入两个非负10进制整数A和B(<=2 ...

  10. PAT 1036 跟奥巴马一起编程

    https://pintia.cn/problem-sets/994805260223102976/problems/994805285812551680 美国总统奥巴马不仅呼吁所有人都学习编程,甚至 ...