一、前言
某次,某容器服务发现无法使用了,查看状态为restaring状态,后看是云主机重启了,导致本地的nfs-server未自动启动,导致关联的集群主机,远程挂载点无法使用,影响容器服务运行。故此,本文列举了当出现docker容器宕机后排查的思路,以供参考;另外应养成定期备份容器数据和镜像的习惯。
二、FAQ及处理
2.1、Docker容器异常宕机排查处理
1、查看Docker的日志文件:
关联资源:shim reaped exception、Docker 容器常见故障排查
journacl -x -n 100 -u docker #-f 实时滚动显示最新日志,-k查看内核的,-n 默认尾部的最新10行,--r 查看最新的日志
journalctl -b -0 #查看本次启动的
journalctl -b -1 #查看上一次启动的日志
journalctl --since=“2024-08-01 00:22:02”
journalctl --since “30 min ago”
journalctl --since yesterday
journalctl --since “2024-08-01” --until “2024-08-13 13:40”
journalctl --since 08:30 --until “2 hour ago”
journalctl -u docker.service --since today #查看docker unit服务的日志,-u可多次使用显示多个unit日志
tail -1000 /var/log/messages |grep -Ei ' "out of memory"|"Kill process"|score|sacrifice'
grep "reboot|grep shutdown" /var/log/messages #确认是否Linux系统宕机了
dmesg | grep "error"
cat /var/log/kern.log | grep "error"
last reboot #查看系统最后重启的时间和原因
last -F |grep crash
dmesg | tail -N
dmesg | egrep -i -B100 'killed process' #查看'killed process’之前的100行内容
sar -u -f /var/log/sa/sa27 |more #利用sa文件查看宕机时CPU情况,-r查看内存
ulimit -c unlimited #修改对core文件大小的限制,0为不允许生成core文件
sysctl -w "kernel.core_name_format=/coredump/%n.core" #将core文件放在/coredump目录下,文件名是进程名+.core,便于下次系统崩溃时查看崩溃转储dump文件
检查系统资源:CPU、内存、磁盘等资源是否达到了限制,当资源不足或负载长期过高触发内核异常会导致Docker挂掉,或内存跑满引起OOM。相关经验表明,Docker长期运行会导致Linux内存buff/caches占用过高,可按如下手动释放缓存。
# 表示清除pagecache (执行后问题得以解决)
echo 1 > /proc/sys/vm/drop_caches
# 表示清除回收slab分配器中的对象(包括目录项缓存和inode缓存)
# slab分配器是内核中管理内存的一种机制,其中很多缓存数据实现都是用的pagecache
echo 2 > /proc/sys/vm/drop_caches
# 表示清除pagecache和slab分配器中的缓存对象 (这个可以的)
echo 3 > /proc/sys/vm/drop_caches
2、查看容器的状态
docker inspect --format '{{.State}}' <container_id_or_name>
docker inspect --format '{{.State.Health}}' <container_id_or_name>
从docker 1.12 版本之后,Docker 实现了原生的健康检查实现。对于容器而言,最简单的健康检查是进程级的健康检查,即检验进程是否存活。Docker Daemon 会自动监控容器中的 PID1 进程,如果 docker run 命令中指明了 restart policy,可以根据重启策略自动重启已结束的容器。但是在很多实际应用中,仅使用进程级健康检查方式还远远不够。比如,容器中进程虽然还在运行却由于其他种种原因无法继续响应用户请求(如应用死锁)。容器启动之后,初始状态会为 starting (启动中)。Docker Engine 会等待 interval 时间,开始执行健康检查命令,并周期性执行。如果单次检查返回值非 0 或者运行需要比指定 timeout 时间还长,则本次检查被认为失败;如果健康检查连续失败超过了 retries 重试次数,状态就会变为 unhealthy (不健康),有一次健康检查成功,Docker 会将容器标记为healthy (健康)状态。
#容器启用监控检查
docker run -d --name=nginx --health-cmd="curl http://localhost:8080/ || exit 1" --health-interval=5s --health-retries=6 --health-timeout=3s nginx
#参数说明
– health-cmd string 运行检查健康状况的命令
–health-interval duration 运行间隔时间(ms|s|m|h)(缺省为 0s)
–health-retries int 需要报告不健康的连续失败次数
–health-start-period duration 容器在开始健康之前初始化的起始周期(ms|s|m|h)(默认 0)
–health-timeout duration 允许一次检查运行的最大时间(ms|s|m|h)(默认为 0s)
–no-healthcheck 禁用任何容器指定的HEALTHCHECK,会使 Dockerfile 构建设置的HEALTHCHECK
功能失效
#Dockerfile 方式:Dockerfile 中HEALTHCHECK只可以出现一次,如果写了多个,只有最后一个生效。HEALTHCHECK 返回值,决定了该次健康检查的成功与否:0:成功;1:失败;2:保留
#使用包含HEALTHCHECK指令的 Dockerfile 构建出来的镜像,在实例化 Docker 容器的时候,就具备了健康状态检查的功能。启动容器后会自动进行健康检查
#格式:HEALTHCHECK [选项] CMD <命令>;--retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认3次;--start-period=<间隔>: 应用的启动的初始化时间,在启动过程中的健康检查失效不会计入,默认 0 秒,需要一定启动时间的服务最好设置;
vim Dockerfile #;类似如下
FROM nginx
HEALTHCHECK --interval=5s --timeout=3s CMD curl http://localhost/ || exit 1 #设置了每 5 秒检查一次,如果健康检查命令超过 3 秒没响应,并且重试 3 次都没响应就视为失败,并且使用curl http://localhost/ || exit 1,其中,exit 1只能让容器的状态为 unhealthy
EALTHCHECK NONE #禁用从基本镜像继承的任何健康检查
HEALTHCHECK --interval=5s --timeout=3s --retries=3 CMD curl --fail http://localhost:$EXPORTER_PORT || bash -c 'kill -s 15 -1 && (sleep 10; kill -s 9 -1)' #检测监控异常后配合--restart=always能让容器重启
#启动后
docker inspect --format '{{json .State.Health}}' web | python -m json.tool
# docker-composer 方式,配置yml文件
version: '3'
services:
myapp:
image: nginx
container_name: healthcheck
healthcheck:
test: ["CMD", "curl", "-fs", "http://localhost/"]
interval: 6s
timeout: 3s
retries: 3
#验证,在 docker ps 的 STATUS 栏显示 healthy/unhealthy
docker ps -l #如下所示
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
43e1f11e2131 nginx "/docker-entrypoint.…" 3 seconds ago Up 3 seconds (health: starting) 80/tcp healthcheck
3、查看异常状态容器的日志和报错处理
docker ps
docker logs --tail=1000 容器ID/名称 #检查容器日志,当容器卡死时可能没有任何日志输出
docker top <container-id>|<contianer-name> #也能确认docker容器是否运行正常,尤其是up状态的容器
docker stats <container-id>|<contianer-name> #查看容器的性能监控信息
#如果无法查看,尝试手动start
docker start containerName #这时一般会给出报错,比如:
can't create unix socket /var/run/docker.sock: is a directory
#如果提示docker.sock不能创建:可
rm -rf /var/run/docker.sock,然后重新启动docker
#报错
docker: Error response from daemon:/var/lib/docker/overlay/XXXXXXXXXXXXXXXXXXXXXXX: no such file or directory.
//原因:docker没有指定目录或文件,或nfs远程挂载异常导致的找不到指定目录或文件
systemctl stop docker
rm -rf /var/lib/docker/*
systemctl start docker
或检查恢复nfs-server后,重启容器
4、如果容器停止的原因是容器本身被限制了资源,可以尝试去除这些限制来解决问题
docker inspect|grep ^Limits
ps auxw | sort -rn -k3 | head -10
ps auxw | head -1;ps auxw|sort -rn -k4|head -10 #内存消耗最多的前10个进程
ps auxw|head -1;ps auxw|sort -rn -k5|head -10 #虚拟内存使用最多的前10个进程
#调整资源限制
docker update --cpus=<cpu_num> --memory=<mem_size> <container_id>
5、或者是容器的重启策略总是always,导致未解决问题前容器频繁重启
更多Docker容器的重启策略如下:
no,默认策略,在容器退出时不重启容器
on-failure,在容器非正常退出时(退出状态非0),才会重启容器
on-failure:3,在容器非正常退出时重启容器,最多重启3次
always,在容器退出时总是重启容器
unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
6、网络经验
在centos7中,内核跟docker版本之间的一个bug,过于频繁create/destory container、
pull/push image的时候,当thin pool满时,DeviceMapper后端默认文件系统xfs会不断retry
失败的IO,导致进程挂起。重启docker,那些挂起的进程也会不断地跑,导致docker进程卡死,这是需要在启动参数上面增加dm.xfs_nospace_max_retries=0。另有时ptables卡住也会导致docker卡住;