Docker容器埠映射后Hadoop突然無法連接
一、背景
? 一般需要對外提供服務的Docker容器,我們在啟動時后使用-p命令將對外訪問埠暴露給外部,故在創建容器是,我們將Hadoop的埠隱射出來供外部訪問:
docker run -itd --privileged --name singleNode -h singleNode \
-p 2222:22 \
-p 3306:3306 \
-p 8020:8020 \
-p 9870:9870 \
-p 19888:19888 \
-p 8088:8088 \
-p 9083:9083 \
-p 10000:10000 \
-p 2181:2181 \
-p 9092:9092 \
-p 8091:8091 \
-p 8080:8080 \
-p 16010:16010 \
-p 4000:4000 \
-p 3000:3000 \
centos:7 /usr/sbin/init
# 其中埠號解釋
2222:22# SSH
3306:3306 #MySQL
8020:8020 # HDFS RPC
9870:9870 # HDFS web UI
19888:19888 # Yarn job history
8088:8088 # Yarn web UI
9083:9083 # Hive metastore
10000:10000 # HiveServer2
2181:2181 # zk
9092:9092 # kafka
8091:8091 # flink
? 但最近碰到一個非常奇怪的情況:在一個CentOS 7測驗環境里部署有Docker Hadoop,并對外暴露了埠,啟動容器后一段時間內都是可以正常作業的,但在不定時間間隔后,Hadoop的web端就訪問不了:

? 原本以為是我們的Hadoop服務沒有正常啟動,但是Jps查看時,卻發現正常:

? 至于這個問題,只有手動重啟出問題的Docker,然后在重啟Hadoop服務后,外部才可以重新訪問,但只要再過一段時間又會出現這樣的問題,
二、問題排查
情況一:開著防火墻但沒有開放埠
? CentOS 7自帶并啟用了防火墻FirewallD,我們可以通過下面的命令檢查FirewallD的狀態:
firewall-cmd --state

? 如果輸出的是“not running”則FirewallD沒有在運行,且所有的防護策略都沒有啟動,那么可以排除防火墻阻斷連接的情況了,
? 如果輸出的是“running”,表示當前FirewallD正在運行,需要再輸入下面的命令查看現在開放了哪些埠和服務:
firewall-cmd --list-ports
firewall-cmd --list-services

? 可以看到當前防火墻只開放了ssh服務(22/tcp)和dhcpv6-client服務,并沒有打開Docker容器映射的Hadoop埠,
解決方案有兩種:
1.關閉FirewallD服務:
? 如果您不需要防火墻,那直接關掉FirewallD服務就好了
systemctl stop firewalld.service
? 但是在部署Hadoop服務之前,就已經將firewalld服務禁用了,故此問題的根源不在這
2.添加策略對外打開指定的埠:
? 比如我們現在要打開對外9870/tcp埠,可以使用下面的命令:
firewall-cmd --add-port=9870/tcp --permanent
firewall-cmd --reload
? 如果只是臨時打開埠,去掉第一行命令中的“–permanent”引數,那么當再次重啟FirewallD服務時,本策略將失效, 此命令不建議執行,畢竟Hadoop服務埠那么多…
情況二:沒有啟用IP_FORWARD
? 因為一直沒法定位出問題的所在,所以不能正常訪問HadoopWeb端時,手動登陸宿主機重啟Docker,再重啟 Hadoop服務,
? 在有一次登錄到宿主服務器上準備重啟Docker daemon服務前,我突然想起之前在用Docker的時候還碰到過另一個問題:如果宿主機沒有啟用IP_FORWARD功能,那Docker容器在啟動時會輸出一條警告訊息:
WARNING: IPv4 forwarding is disabled. Networking will not work.
? 會不會是因為宿主機的IP_FORWARD功能沒有啟用所以才引起的這個故障呢?
sysctl net.ipv4.ip_forward

? 因為,我這里是設定過的,原本的結果為:net.ipv4.ip_forward = 0,表示當前系統的IP_FORWARD功能處于停用狀態!
? 可是問題來了,當時啟動容器的時候都是好的啊,什么都沒有輸出,怎么用著用著IP_FORWARD功能就被禁用了呢?
? Docker daemon服務在啟動的時候會自動設定iptables設定,難不成它還會檢查IP_FORWARD設定,并幫我臨時啟用嗎?
? 帶著這個假設,我手動重啟了一下Docker Hadoop服務
[root@singlenode /]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
[root@singlenode /]# systemctl restart docker
[root@singlenode /]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
? 果然,Docker 服務在啟動程序中會檢查系統的IP_FORWARD配置項,如果當前系統的IP_FORWARD功能處于停用狀態,會幫我們臨時啟用IP_FORWARD功能,然而臨時啟用的IP_FORWARD功能會因為其他各種各樣的原因失效…
? 問題找到,至于修復方案倒非常簡單,只要一行命令就可以了:
echo 'net.ipv4.ip_forward = 1' >> /usr/lib/sysctl.d/50-default.conf
? 執行完成后,重啟服務器或使用下面的命令從檔案中加載配置:
sysctl -p /usr/lib/sysctl.d/50-default.conf

? 就OK了,Hadoop正常訪問咯!

三、小結
? Docker 服務在啟動的時候會幫幫我們調整很多的配置項,比如這次出事兒的IP_FORWARD配置,
? Docker 啟用IP_FORWARD功能是因為Docker容器默認的網路模式(bridge/網橋模式)會給每個容器分配一個私有IP,如果容器需要和外部通信,就需要使用到NAT,NAT需要IP_FORWARD功能支持,否則無法使用,這也解釋了為什么會出現在IP_FORWARD功能停用的情況下,使用bridge模式的容器內外均無法訪問的情況,
? 只是在Linux下,出于安全考慮,默認是停用IP_FORWARD功能的,Docker 服務在啟動時會檢查IP_FORWARD功能是否已經啟用,如果沒有啟用的話,Docker 會悄無聲息的臨時啟用此功能,然而臨時啟用的IP_FORWARD功能并不能持久化,會因為其他命令的干擾導致失效,
Author:洋群滿滿
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291811.html
標籤:其他
