這篇文章主要為大家展示了“Docker容器端口映射后突然無(wú)法連接怎么辦”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Docker容器端口映射后突然無(wú)法連接怎么辦”這篇文章吧。

一、背景
一般需要對(duì)外提供服務(wù)的Docker容器,我們?cè)趩?dòng)時(shí)后使用-p命令將對(duì)外訪問(wèn)端口暴露給外部,例如啟動(dòng)Docker Registry,我們將5000端口映射出來(lái)供外部訪問(wèn):
docker run -d -p 5000:5000 registry
但最近碰到一個(gè)非常奇怪的情況:研發(fā)組里一個(gè)CentOS 7測(cè)試環(huán)境里部署有Docker Registry,并對(duì)外暴露了端口。啟動(dòng)容器后一段時(shí)間內(nèi)都是可以正常工作的,但在不定時(shí)間間隔后,外部主機(jī)就會(huì)出現(xiàn)無(wú)法從倉(cāng)庫(kù)中拉取鏡像的情況,提示TimeOut:

然而在Docker宿主機(jī)上訪問(wèn)倉(cāng)庫(kù)則可以正常訪問(wèn):

至于這個(gè)問(wèn)題,只有手動(dòng)重啟出問(wèn)題的Docker daemon服務(wù)后,外部才可以重新訪問(wèn),但只要再過(guò)一段時(shí)間又會(huì)出現(xiàn)這樣的問(wèn)題。
二、問(wèn)題排查
碰到這個(gè)問(wèn)題我第一反應(yīng)就是問(wèn)組里的人,是不是有人重啟過(guò)CentOS 7 自己的firewallD了。
因?yàn)檫@臺(tái)服務(wù)器是我配置的,防火墻雖然開(kāi)著但我已經(jīng)開(kāi)啟端口訪問(wèn)了,所以肯定不是因?yàn)榉阑饓ψ钄噙B接的緣故。但由于這篇文章是篇踩坑排查文檔,所以還是把這種情況寫(xiě)出來(lái)了
情況一:開(kāi)著防火墻但沒(méi)有開(kāi)放端口
CentOS 7自帶并啟用了防火墻FirewallD,我們可以通過(guò)下面的命令檢查FirewallD的狀態(tài):
firewall-cmd --state

如果輸出的是“not running”則FirewallD沒(méi)有在運(yùn)行,且所有的防護(hù)策略都沒(méi)有啟動(dòng),那么可以排除防火墻阻斷連接的情況了。
如果輸出的是“running”,表示當(dāng)前FirewallD正在運(yùn)行,需要再輸入下面的命令查看現(xiàn)在開(kāi)放了哪些端口和服務(wù):
firewall-cmd --list-ports firewall-cmd --list-services

可以看到當(dāng)前防火墻只開(kāi)放了80/tcp端口、ssh服務(wù)(22/tcp)和dhcpv6-client服務(wù),并沒(méi)有打開(kāi)Docker容器映射的5000/tcp端口。
解決方案有兩種:
1.關(guān)閉FirewallD服務(wù):
如果您不需要防火墻,那直接關(guān)掉FirewallD服務(wù)就好了
systemctl stop firewalld.service
2.添加策略對(duì)外打開(kāi)指定的端口:
比如我們現(xiàn)在要打開(kāi)對(duì)外5000/tcp端口,可以使用下面的命令:
firewall-cmd --add-port=5000/tcp --permanent firewall-cmd --reload
如果只是臨時(shí)打開(kāi)端口,去掉第一行命令中的“--permanent”參數(shù),那么當(dāng)再次重啟FirewallD服務(wù)時(shí),本策略將失效。
情況二:人為重啟CentOS 7的FirewallD服務(wù)
FirewallD是CentOS系統(tǒng)在7版本引入的新組件,簡(jiǎn)單的說(shuō)就是iptables的包裝,用于簡(jiǎn)化防火墻相關(guān)的設(shè)置。
然而FirewallD和Docker相處的并不是特別好,當(dāng)FirewallD啟動(dòng)(或重新啟動(dòng))時(shí),會(huì)從iptables中刪除DOCKER鏈,造成Docker不能正常工作:
FirewallD
CentOS-7 introduced firewalld, which is a wrapper around iptables and can conflict with Docker.
When firewalld is started or restarted it will remove the DOCKER chain from iptables, preventing Docker from working properly.
When using Systemd, firewalld is started before Docker, but if you start or restart firewalld after Docker, you will have to restart the Docker daemon.
摘自Docker官方文檔《CentOS - Docker Documentation》
在CentOS 7中,如果設(shè)置使用systemd開(kāi)機(jī)自啟動(dòng)Docker服務(wù)是不會(huì)有問(wèn)題的,因?yàn)镈ocker在systemd配置文件中明確注明了“After= firewalld.service”,以保證Docker daemon 在FirewallD啟動(dòng)后再啟動(dòng)。

(Docker:惹不起我還躲不起嗎)
但每當(dāng)用戶手動(dòng)重啟過(guò)FirewallD服務(wù)之后,F(xiàn)irewallD服務(wù)會(huì)將Docker daemon寫(xiě)入iptables的DOCKER鏈刪除,所以需要手動(dòng)重新啟動(dòng)一次Docker daemon服務(wù),讓Docker daemon服務(wù)重建DOCKER鏈。
不過(guò)問(wèn)了組里另外兩個(gè)研發(fā),都說(shuō)沒(méi)有動(dòng)過(guò)。查看了shell的history也沒(méi)找到對(duì)應(yīng)的記錄。
這就很奇怪了。不過(guò)經(jīng)過(guò)一段時(shí)間的蹲點(diǎn)排查之后,我終于發(fā)現(xiàn)了一個(gè)新的原因:
情況三:沒(méi)有啟用IP_FORWARD
因?yàn)橐恢睕](méi)法定位出問(wèn)題的所在,所以我們研發(fā)組都是發(fā)現(xiàn)不能正常訪問(wèn)倉(cāng)庫(kù)時(shí),手動(dòng)登陸宿主機(jī)重啟Docker daemon服務(wù)。
在有一次登錄到宿主服務(wù)器上準(zhǔn)備重啟Docker daemon服務(wù)前,我突然想起之前在用Docker的時(shí)候還碰到過(guò)另一個(gè)問(wèn)題:如果宿主機(jī)沒(méi)有啟用IP_FORWARD功能,那Docker容器在啟動(dòng)時(shí)會(huì)輸出一條警告消息:
WARNING: IPv4 forwarding is disabled. Networking will not work.
并且將不能在啟動(dòng)的容器中訪問(wèn)外部網(wǎng)絡(luò),容器對(duì)外暴露的端口外部也不能正常訪問(wèn):


會(huì)不會(huì)是因?yàn)樗拗鳈C(jī)的IP_FORWARD功能沒(méi)有啟用所以才引起的這個(gè)故障呢?
sysctl net.ipv4.ip_forward

果然,輸出表示當(dāng)前系統(tǒng)的IP_FORWARD功能處于停用狀態(tài)!
可是問(wèn)題來(lái)了,當(dāng)時(shí)啟動(dòng)容器的時(shí)候都是好的啊,什么都沒(méi)有輸出,怎么用著用著IP_FORWARD功能就被禁用了呢?
等等,Docker daemon服務(wù)在啟動(dòng)的時(shí)候會(huì)自動(dòng)設(shè)置iptables設(shè)置,難不成它還會(huì)檢查IP_FORWARD設(shè)置,并幫我臨時(shí)啟用嗎?
帶著這個(gè)假設(shè),我手動(dòng)重啟了一下Docker daemon服務(wù):

果然,Docker daemon服務(wù)在啟動(dòng)過(guò)程中會(huì)檢查系統(tǒng)的IP_FORWARD配置項(xiàng),如果當(dāng)前系統(tǒng)的IP_FORWARD功能處于停用狀態(tài),會(huì)幫我們臨時(shí)啟用IP_FORWARD功能,然而臨時(shí)啟用的IP_FORWARD功能會(huì)因?yàn)槠渌鞣N各樣的原因失效…
雖然具體造成本次故障的原因現(xiàn)在還沒(méi)有確鑿的證據(jù)定位出,但我現(xiàn)在嚴(yán)重懷疑是因?yàn)橹貑⒕W(wǎng)絡(luò)服務(wù)造成的。因?yàn)槌鰡?wèn)題的服務(wù)器宿主機(jī)上運(yùn)行著我們研發(fā)組正在開(kāi)發(fā)的Web項(xiàng)目,其中有一個(gè)功能是修改網(wǎng)卡IP地址,這個(gè)功能在修改完網(wǎng)卡IP后,會(huì)自動(dòng)調(diào)用下面的命令重啟網(wǎng)絡(luò)服務(wù):
systemctl restart network.service
而重啟網(wǎng)絡(luò)服務(wù)正會(huì)使Docker daemon服務(wù)自動(dòng)設(shè)置的臨時(shí)啟用IP_FORWARD配置失效:

另外因?yàn)槭浅绦蛑苯诱{(diào)用命令,所以不會(huì)在history命令中留下痕跡。
至于修復(fù)方案倒非常簡(jiǎn)單,只要一行命令就可以了:
echo 'net.ipv4.ip_forward = 1' >> /usr/lib/sysctl.d/50-default.conf
執(zhí)行完成后,重啟服務(wù)器或使用下面的命令從文件中加載配置:
sysctl -p /usr/lib/sysctl.d/50-default.conf

就可以了。
三、小結(jié)
Docker daemon服務(wù)在啟動(dòng)的時(shí)候會(huì)幫幫我們調(diào)整很多的配置項(xiàng),比如這次出事兒的IP_FORWARD配置。
Docker daemon啟用IP_FORWARD功能是因?yàn)镈ocker容器默認(rèn)的網(wǎng)絡(luò)模式(bridge/網(wǎng)橋模式)會(huì)給每個(gè)容器分配一個(gè)私有IP,如果容器需要和外部通信,就需要使用到NAT。NAT需要IP_FORWARD功能支持,否則無(wú)法使用。這也解釋了為什么會(huì)出現(xiàn)在IP_FORWARD功能停用的情況下,使用bridge模式的容器內(nèi)外均無(wú)法訪問(wèn)的情況。
只是在Linux下,出于安全考慮,默認(rèn)是停用IP_FORWARD功能的,Docker daemon服務(wù)在啟動(dòng)時(shí)會(huì)檢查IP_FORWARD功能是否已經(jīng)啟用,如果沒(méi)有啟用的話,Docker daemon會(huì)悄無(wú)聲息的臨時(shí)啟用此功能,然而臨時(shí)啟用的IP_FORWARD功能并不能持久化,會(huì)因?yàn)槠渌畹母蓴_導(dǎo)致失效。
不過(guò)這次的事情告訴了我一個(gè)小道理:當(dāng)出現(xiàn)問(wèn)題的時(shí)候,不要慌,要結(jié)合經(jīng)驗(yàn)大膽的做出假設(shè)并驗(yàn)證,治標(biāo)治本。
以上是“Docker容器端口映射后突然無(wú)法連接怎么辦”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)站題目:Docker容器端口映射后突然無(wú)法連接怎么辦-創(chuàng)新互聯(lián)
新聞來(lái)源:http://chinadenli.net/article8/dgphop.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、動(dòng)態(tài)網(wǎng)站、虛擬主機(jī)、企業(yè)網(wǎng)站制作、網(wǎng)站設(shè)計(jì)公司、App設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容