Docker容器不定时出现无法连接的问题
一、背景
生产环境与版本
主机:centos8 docker:20.0 mysql:5.7
一般需要对外提供服务的Docker容器,我们在启动时后使用-p命令将对外访问端口暴露给外部,例如启动Docker Mysql,我们将3306端口映射出来供外部访问:
docker run -it -d -p 3376:3306 docker.io/centos:latest /bin/bash
但最近碰到一个非常奇怪的情况:ECS主机中一个CentOS 8生产环境里部署有Docker Mysql,并对外暴露了端口。启动容器后一段时间内都是可以正常工作的,但在不定时间间隔后,外部主机就会出现无法从访问的情况:
二,问题排查
1、排查端口
碰到此问题问询开发、运维人员是不是有人重启过CentOS 8 自己的firewallD了。
查看防火墙的状态
systemctl status firewalld.service
然后排查对应的端口是否开放
iptables -nL
如果是防火墙问题:解决方案有两种:
1)关闭FirewallD服务:
如果您不需要防火墙,那直接关掉FirewallD服务就好了
systemctl stop firewalld.service
2)添加策略对外打开指定的端口:
比如我们现在要打开对外5000/tcp端口,可以使用下面的命令:
iptables -A INPUT -p tcp --dport 5000 -j ACCEPT
2、查看容器日志
命令格式:
$ docker logs [OPTIONS] CONTAINER
Options:
--details 显示更多的信息
-f, --follow 跟踪实时日志
--since string 显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟)
--tail string 从日志末尾显示多少行日志, 默认是all
-t, --timestamps 显示时间戳
--until string 显示自某个timestamp之前的日志,或相对时间,如42m(即42分钟)
例子:
查看指定时间后的日志,只显示最后100行:
$ docker logs -f -t --since="2022-04-08" --tail=100 CONTAINER_ID
查看某时间之后的日志:
$ docker logs -t --since="2022-04-08T13:23:37" CONTAINER_ID
经过日志排查,发现容器日志无错误日志
3、排查网络
A:查看容器运行状态正常如图:
由上图可知,容器运行正常。
B:查看容器对外网之间的网络:
由上图所知,容器对外网不通
C:查看容器与docker0网卡之间网络
由上图所知容器与docker0网卡之间通信正常
D:查看容器与宿主机之间网络
由上图所知,容器与宿主机之间的通信正常
. Docker容器实例中解析DNS的顺序
1) 首先,查找Docker daemon内置的DNS服务器127.0.0.11
2) 其次,查找docker run创建容器实例时通过--dns参数设置的DNS服务器
3) 再次,查找Docker daemon通过--dns参数,或/etc/docker/daemon.json文件设置的DNS服务器
4) 又次,查找Docker宿主机上/etc/resolv.conf文件中配置的DNS服务器
5) 最后,查找Google的DNS服务器,如8.8.8.8和8.8.4.4,2001:4860:4860::8888和2001:4860:4860::8844
4、没有启用IP_FORWARD
因为网络通正常,一直没法定位出问题的所在,发现不能正常访问容器时,手动登陆宿主机重启Docker daemon服务。如果宿主机没有启用IP_FORWARD功能,那Docker容器在启动时会输出一条警告消息:
WARNING: IPv4 forwarding is disabled. Networking will not work.
会不会是因为宿主机的IP_FORWARD功能没有启用所以才引起的这个故障呢?
sysctl net.ipv4.ip_forward
果然,输出表示当前系统的IP_FORWARD功能处于停用状态!
可是问题来了,当时启动容器的时候都是好的啊,什么都没有输出,怎么用着用着IP_FORWARD功能就被禁用了呢?Docker daemon服务在启动的时候会自动设置iptables设置,难不成它还会检查IP_FORWARD设置,并帮我临时启用吗?
带着这个假设,我手动重启了一下Docker daemon服务:
果然,Docker daemon服务在启动过程中会检查系统的IP_FORWARD配置项,如果当前系统的IP_FORWARD功能处于停用状态,会帮我们临时启用IP_FORWARD功能,然而临时启用的IP_FORWARD功能会因为其他各种各样的原因失效…
echo 'net.ipv4.ip_forward = 1' >> /usr/lib/sysctl.d/50-default.conf
or
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
然后使配置生效
sysctl -p
至此,业务恢复正常。