大家好,我是软件测试工程师和混沌实验工程师robot。今天分享一个如何提高容器健壮性的故事。
混沌实验中,容器所在虚机或物理机掉电重启操作是很平常的,但是掉电恢复后容器是否能自动恢复呢?或者由于内存触发OOM等原因导致容器异常退出后是否能自动恢复呢?再或者容器部署时没有考虑健壮性,后面还可以再优化考虑嘛?
鉴于以上问题,加上相关的混沌实验经验,想和大家一起聊聊。
容器的重启策略
docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]
Options本文仅关心重启策略参数--restart,该参数可以指定容器退出时如何重启。
no 默认策略,容器退出时不会自动重启(没想明白为啥不重启?什么时候不需要重启呢?先自己思考下后面告诉你答案)
on-failure[:max-retries] 仅仅在容器退出响应非0状态码时重启容器(容器退出码有哪些?何时为0?)。限制了容器引擎重启容器的最大次数。
always 不管容器退出码,只要容器退出总是重启。当指定always,容器引擎将无限期的重启容器。不管容器当前的状态,当容器引擎重启时容器总是重启(这也太high了,容器正常运行,引擎容器引擎异常,为啥重启容器呢?这必然影响容器中运行的业务,危险啊)。
unless-stopped 不管容器退出码,只要容器退出总是重启,包括容器引擎重启,除了在容器引擎停止前停止的容器。
以上给出4种重启策略,但如果重启失败,后续如何重启呢?一直周期性重启吗?
为了防止服务器上容器重启泛滥,每次重启前都会增加一定的时延,从100毫秒开始,每次是前一次时延的两倍。意味着容器引擎将以100毫秒,200毫秒,400,800,1600,直到on-failure边界值或者docker stop或者docker rm -f容器。
假如容器重启成功(容器至少重启10秒),容器重启的时延将置为默认值100毫秒。
$ docker inspect -f "{{ .RestartCount }}" my-container
# 2
$ docker inspect -f "{{ .State.StartedAt }}" my-container
# 2015-03-04T23:47:07.691840179Z
彩蛋时刻:
1. 为什么容器不需要重启?
经验告诉我大多数容器退出是需要重启的。
2. 什么时候容器不需要重启呢?
容器一次性操作的比如初始化某些配置等等类似于一次性筷子。
退出码和重启策略
还记得容器退出码非0时才重启容器的重启策略on-failure[:max-retries] 嘛?容器退出码有哪些?何时为0?
退出码0 表示特定容器没有附加前台进程。
当docker run退出码非0,退出码要遵循chroot标准。
125 意味着容器引擎自身错误
126 意味着容器中不能调用包含的命令
127 意味着容器命令找不到
137 一般是因为 pod 中容器内存达到资源限制(resources.limits),如内存溢出(OOM),CPU达到限制只需要不分时间片给程序就可以。因为限制资源是通过 linux 的 cgroup 实现的,所以 cgroup 会将此容器强制杀。
139 表明容器收到了SIGSEGV信号,无效的内存引用,对应kill -11。
143表明容器收到了SIGTERM信号,终端关闭,对应kill -15。
当然也可以设计容器退出码
$ docker run busybox /bin/sh -c 'exit 3'; echo $?
3
已部署的容器,如何支持重启策略
docker update支持动态修改容器配置,可以修改容器使用的资源(内存/CPU/磁盘),很幸运,支持修改容器的重启策略--restart,很棒,竟然支持running的容器。重启策略更新后就立即生效。
注意:docker update和docker container update不支持Windows容器。
命令举例:docker update --restart=on-failure:3 abebf7571666 hopeful_morse
注意:带有--rm参数启动的容器是不支持更新重启策略的。对于容器来说,AutoRemove和RestartPolicy是互斥的。
这个故事告诉我们什么
测试或混沌工程师,看到异常现象要思考如何提高系统健壮性,要想正确使用,最好从官网找使用方法,并结合自身产品来验证。此外不管是测试工程师或混沌工程师,都要搞清楚每次混沌实验的价值所在,如何自动恢复环境。