當Docker啟動時,宿主機端上會自動建立一組docker0的Birdge網路
,此Birdge網路可以視同一個虛擬交換機。它會把掛載到此docker0上的網路介面互相可以進行通訊轉發。
依據RFC1918
定義,Docker隨機分配一個docker0私有網路中尚未佔用的一個IP位址來分配給網卡,如: 172.17.0.0/16
下的網路,而之後容器內的網卡也會自動分配同一網段下給予一組IP位址。
當開始建立Docker容器時,會同時建立一對veth pair
介面,此介面作用是當封包發送到A介面時,B介面也會收到相同的封包。
這對介面一端在容器內屬eth0
,而另一端在本地並被掛載到docker0 Bridge則是以veth
作為開頭的一串隨機碼,如:vethxxxxxx。透過此方式,宿主機就可以與容器進行溝通,容器間也可以相互連通。也就是宿主和容器間一組虛擬共享網路。
不過透過上述的虛擬共享網路橋接器,真實狀態下預設並不能讓容器直接透過宿主機對外以及容器之間讓網卡互通,最後一項武器還是要利用iptables來實踐連接埠的Mapping,這樣才能讓外面或彼此容器間存取通訊。
所以重整思緒一下,Docker基本網路結構主要由以下四種元件組成:
Netwoek Namespace
:網路資源之間完整隔離。Veth Pair
:隔離容器與對外傳輸通訊的橋樑。Linux Brigde
:宿主機上的橋接器,作為交換機之用。由於容器均透過Veth Pair連至橋接器上,故可在容器間進行網路通訊行為。Iptables
:提供網路通訊NAT以及防火牆開通連接埠的功能。在容器中使用mount指令可以看到以下資訊,可以讓宿主機的DNS在發生更新後所有Docker容器的DNS都透過 /etc/resolv.conf偵測參照並自動更新。
我們隨機執行一個Ubuntu容器檢視他的DNS紀錄狀態
修改daemon.json
,如果沒有就自行建立,修改完畢後一定要重啟daemon服務並透過檢視docker info是否正常顯示資訊,如果有問題會顯示狀態失敗,一定要預先排除。
vi daemon.json
{
"dns" : [
"168.95.1.1",
"8.8.8.8"
]
}
cat daemon.json
systemctl start docker
service docker start
systemctl daemon-reload
systemctl restart docker
docker info
docker run -it ubuntu cat etc/resolv.conf
就看到已經套用我這邊指定解析的DNS伺服器了。
觀念一提到容器存取控制主要是借助Linux本身iptables來進行網路進出管理,預設Linux系統都有內建。
容器如想要存取外部網路,則會需要本地端Linux系統的轉發支援,以下檢查轉發是否開啟。
如果顯示"0"則未開啟轉發
,需要手動設置
sysctl -w net.ipv4.ip_forward=1
sysctl net.ipv4.ip_forward
補充一下,如果啟動Docker服務時設置 --ip-forward=true
, Docker就會自動設定系統ip_forward參數=1
而達到自動轉發存取外部網路的機制。
容器間要能彼此存取,會需以下兩項條件成立:
docker0
橋接器上。iptables
是否允許通過。存取所有連接埠
當Docker服務被啟動時,預設會新增一轉發規則到iptables的FORWARD上。規則中ACCEPT / DROP取決於預設值--icc=true或是--icc=false
。
而如果手動指定 --iptables=false則不會再新增iptables規則。故預設不同容器間是允許網路互通的。故安全考量下,可在 /etc/default/docker檔案設定DOCKER_OPTS=--icc=false強制禁止。
存取指定連接埠
繼續上述透過-icc=false禁止網路存取後,是可透過 --link=CONTAINER_NAME:ALIAS 來存取容器的開放連接埠。如:啟動Docker服務時,可同時使用icc=false --iptables=true來禁止網路間存取,並讓Docker修改系統中的iptables規則。
iptables -nL(無Link
)
iptables -nL(有Link
)
詳細針對Docker防火牆規則語法,請參考Docker and iptables