一、背景
生產環境與版本
主機: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
至此,業務恢復正常。
