问题描述:
以Docker
运行的web
服务正常运行,配置服务器重启自启动Docker和容器。但是机房断电重启后,web
服务无法正常访问。telnet
服务器的端口不通。
环境:
Application | Version |
---|---|
OS | centos7 |
Docker | 19.03.1 |
docker-compose | 1.24.0 |
$ docker-compose ps
发现web
服务器与php
容器都已正常启动
$ docker-composer up -d
重启后,访问web
服务是否正常,服务启动可能会需要一些时间,一般能telnet
通端口基本就不会有什么问题。
服务容器正常启动依然无法访问,就需要检查一下防火墙了,先查看防火墙状态
$ firewall-cmd --state
not running
发现防火墙未运行,可以排除防火墙的影响
如果是running
则需要进一步排查,端口是否开放
firewall-cmd --list-ports
firewall-cmd --list-services
$ sudo systemctl stop firewalld.service
$ sudo firewall-cmd --add-port=80/tcp --permanent
$ firewall-cmd --reload
完成后访问web
服务看是否正常
前两步的影响排出后,最后检查IP转发是否开启,一般问题出在这里
$ sysctl net.ipv4.ip_forward
$ echo 'net.ipv4.ip_forward = 1' | sudo tee -a /usr/lib/sysctl.d/50-default.conf
重新加载配置文件(也可以重启network服务)
$ sudo sysctl -p /usr/lib/sysctl.d/50-default.conf
查看IP转发是否开启
IP转发已开启,访问web
服务看是否正常了。
Docker
与宿主机的端口映射是通过iptables
实现的,容器启动时会在iptables
中添加DOCKER
链和n
条DNAT
规则
简单来了解一下,查看一下nat
表的DOCKER
链
$ sudo iptables -t nat -nvL DOCKER
从图中可以看到有两条DNAT
规则,这两条规则分别将宿主机443
、80
端口的报文转发到172.17.3.2
的443
和80
端口上,而172.17.3.2
是分配给nginx
容器的ip
(可以通过docker inspect 容器ID
命令查看)
而这个DNAT
规则需要宿主机开启内核IP转发功能,所以IP转发未开启会导致服务访问失败。
问题的根源找到了,但是产生的原因还没找到。
DOCKER
服务依然能正常运行?这是因为Docker daemon
启动时会检查IP_FORWARD
是否开启,如果未开启则临时开启,因为是临时开启所以在network
服务重启后就会失效。服务器断电重启后network服务自然会重启,就有可能导致IP_FORWARD
失效。一般docker
服务正常运行一段时间后却突然访问不了,大不多是因此引起的,可以从这里开始排查。
当然不妨自己来做个试验
web
服务失败docker
$ sudo systemctl restart docker
访问web
服务成功,查看IP转发功能是已开启状态。所以docke
r服务访问失败时往往能够通过重启docker
解决,但是不推荐这么做,因为既没真正解决问题容器重启还比较费时。
network
$ sudo systemctl restart network
访问web
服务成功,查看IP转发功能是已关闭状态
最后记得将IP转发功能恢复