dokcer0 網(wǎng)橋
在 Ubuntn 上安裝 docker 后,宿主機(jī)上默認(rèn)被創(chuàng)建了一個(gè)名為 docker0 的網(wǎng)卡,其 IP 為 172.17.0.1/16:
有了這個(gè)網(wǎng)卡,宿主機(jī)還會(huì)在內(nèi)核的路由表中添加一條到達(dá)相應(yīng)網(wǎng)絡(luò)的靜態(tài)路由記錄:
這條路由信息表示所有目的 IP 為 172.17.0.0/16 的數(shù)據(jù)包都會(huì)從 docker0 網(wǎng)卡發(fā)出。接下來我們創(chuàng)建一個(gè)名為 mycon 的容器,并觀察其網(wǎng)絡(luò)配置:
在 mycon 容器內(nèi)可以看到兩塊網(wǎng)卡:lo 和 eth0。其中 lo 是容器的回環(huán)網(wǎng)卡,eth0 是容器與外界通信的網(wǎng)卡,eth0 的 IP 信息為 172.17.0.2/16,和宿主機(jī)上的網(wǎng)卡 bridge0 在同一網(wǎng)段中。查看 mycon 的路由信息:
mycon 容器的默認(rèn)網(wǎng)關(guān)正是宿主機(jī)的 docker0 網(wǎng)卡。通過 ping 命令測(cè)試與外網(wǎng)的連通性,此時(shí)容器 mycon 是可以連通外網(wǎng)的,這就說明 mycon 的 eth0 網(wǎng)卡與宿主機(jī)的 docker0 網(wǎng)卡是連通的。
下面我們來查看宿主機(jī)的網(wǎng)絡(luò)設(shè)備:
發(fā)現(xiàn)多了一個(gè)以 "veth" 開頭的網(wǎng)卡,這是一個(gè) veth 設(shè)備。而 veth 設(shè)備總是成對(duì)出現(xiàn)的,那么與 veth7537a16 配對(duì)的就應(yīng)該是 mycon 容器中的 eth0 了。既然 mycon 容器中的 eth0 是與 docker0 連通的,那么 veth7537a16 也應(yīng)該是與 docker0 連通的。因此docker0 并不是一個(gè)簡(jiǎn)單的網(wǎng)卡設(shè)備,而是一個(gè)網(wǎng)橋!下圖展示了 docker bridge 網(wǎng)絡(luò)模式的拓?fù)鋱D:
事實(shí)上,docker 創(chuàng)建了 docker0 網(wǎng)橋,并以 veth pair 連接各個(gè)容器的網(wǎng)絡(luò),容器中的數(shù)據(jù)通過 eth0 發(fā)送到 docker0 網(wǎng)橋上,并由 docker0 網(wǎng)橋完成轉(zhuǎn)發(fā)。這里網(wǎng)橋的概念等同于交換機(jī),為連在其上的設(shè)備轉(zhuǎn)發(fā)數(shù)據(jù)幀。網(wǎng)橋上的 veth 網(wǎng)卡設(shè)備相當(dāng)于交換機(jī)上的端口,可以將多個(gè)容器連接在它們上面,這些端口工作在二層,所以是不需要配置 IP 信息的。上圖中的 docker0 網(wǎng)橋就為連在其上的容器轉(zhuǎn)發(fā)數(shù)據(jù)幀,使得同一臺(tái)宿主機(jī)上的 docker 容器之間可以相互通信。既然 docker0 是二層設(shè)備,那么它為什么還需要 IP 呢?其實(shí),docker0 是一個(gè)普通的 linux 網(wǎng)橋,是可以為它配置 IP 的,我們可以認(rèn)為它的內(nèi)部有一個(gè)可以用于配置 IP 的網(wǎng)卡。Docker0 的 IP 地址作為所連接的容器的默認(rèn)網(wǎng)關(guān)地址!
docker0 網(wǎng)橋是在 docker daemon 啟動(dòng)時(shí)自動(dòng)創(chuàng)建的,其默認(rèn) IP 為 172.17.0.1/16,之后通過 bridge 驅(qū)動(dòng)創(chuàng)建的容器都會(huì)在 docker0 的子網(wǎng)范圍內(nèi)選取一個(gè)未占用的 IP 使用,并連接到 docker0 網(wǎng)橋上。Docker daemon 提供了如下參數(shù)可以幫助用戶自定義 docker0 的設(shè)置。
--bip=CIDR:設(shè)置 docker0 的 IP 地址和子網(wǎng)范圍,使用 CIDR 格式,如 192.168.1.0/24。這個(gè)參數(shù)僅僅是配置 docker0 的,對(duì)用戶自定義的網(wǎng)橋無效。
--fixed-cidr=CIDR:限制 docker 容器可以獲取的 IP 地址范圍。Docker 容器默認(rèn)可以獲取的 IP 范圍為 docker 網(wǎng)橋的整個(gè)子網(wǎng)范圍,此參數(shù)可以將其縮小到某個(gè)子網(wǎng)范圍內(nèi),所以這個(gè)參數(shù)必須在 docker 網(wǎng)橋的子網(wǎng)范圍內(nèi)。
--mtu=BYTES:指定 docker0 網(wǎng)橋的最大傳輸單元(MTU)。
除了使用 docker0 網(wǎng)橋外,用戶還可以使用自定義的網(wǎng)橋,然后通過 --bridge=BRIDGE 參數(shù)傳遞給 docker daemon。比如我們可以創(chuàng)建一個(gè)自定義網(wǎng)橋 br0:
$ sudo ip link add name br0 type bridge $ sudo ifconfig br0 188.18.0.1
然后在啟動(dòng) docker daemon 時(shí)設(shè)置參數(shù) --bridge=br0 即可。
iptables 規(guī)則
在安裝 docker 時(shí),會(huì)默認(rèn)在宿主機(jī)中添加一些 iptables 規(guī)則,用于 docker 容器之間已經(jīng)容器與外界的通信。我們可以通過 iptables-save 命令查看到 nat 表上 POSTROUTING 鏈上的有這么一條規(guī)則:
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
這條規(guī)則關(guān)系著 docker 容器與外界的通信,其含義是將不是從網(wǎng)卡 docker0 發(fā)出的且源地址為 172.17.0.0/16 的數(shù)據(jù)包(容器中發(fā)出的數(shù)據(jù)包)做 SNAT。這樣一來,從 docker 容器中訪問外網(wǎng)的流量,在外部看來就是從宿主機(jī)上發(fā)出的,外部感覺不到 docker 容器的存在。
當(dāng)外界想要訪問 docker 容器運(yùn)行的服務(wù)時(shí)該怎么辦呢?接下來我們將啟動(dòng)一個(gè)簡(jiǎn)單的 web 服務(wù)器:
$ docker run -d -p 3000:3000 --name=myweb ljfpower/nodedemo
然后觀察 iptables 規(guī)則的變化:
$ sudo iptables-save … *nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 3000 -j DNAT --to-destination 172.17.0.3:3000 … *filter -A DOCKER -d 172.17.0.3/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 3000 -j ACCEPT …
可以看到,在 nat 表和 filter 表中的 DOCKER 鏈中分別增加來一條規(guī)則,這兩條規(guī)則將訪問宿主機(jī) 3000 端口的請(qǐng)求轉(zhuǎn)發(fā)到 172.17.0.3 的 3000 端口上(提供服務(wù)的 docker 容器的 IP 和端口),所以外界訪問 docker 容器是通過 iptables 做 DNAT 實(shí)現(xiàn)的。
Docker 默認(rèn)的 forward 規(guī)則允許所有的外部 IP 訪問容器,我們可以通過在 filter 的 DOCKER 鏈上添加規(guī)則來對(duì)外部的 IP 訪問做出限制,比如只允許源 IP 為 192.168.21.212(筆者是在局域網(wǎng)內(nèi)演示的)的數(shù)據(jù)包訪問容器,添加的規(guī)則如下:
$ sudo iptables -I DOCKER -i docker0 ! -s 192.168.21.212 -j DROP
不僅僅是與外界通信,docker 容器之間相互通信也受到 iptables 規(guī)則的限制。同一臺(tái)宿主機(jī)上的 docker 容器默認(rèn)都連在 docker0 網(wǎng)橋上,它們屬于同一個(gè)子網(wǎng),這是滿足通信的第一步。同時(shí),docker daemon 會(huì)在 filter 表的 FORWARD 鏈中增加一條 ACCEPT 的規(guī)則(--icc=true):
-A FORWARD -i docker0 -o docker0 -j ACCEPT
這是滿足容器間相互通信的第二步。當(dāng) docker daemon 的啟動(dòng)參數(shù) -icc(icc 參數(shù)表示是否允許容器間相互通信) 設(shè)置為 false 時(shí),上面的規(guī)則被設(shè)置為 DROP,容器間的相互通信就被禁止了,這時(shí)如果想讓兩個(gè)容器通信就需要在 docker run 命令中使用 --link 選項(xiàng)。
在 docker 容器和外界的通信過程中,還涉及了數(shù)據(jù)包在多個(gè)網(wǎng)卡之間的轉(zhuǎn)發(fā)(比如從 docker0 網(wǎng)卡到宿主機(jī) eth0 網(wǎng)卡),這需要內(nèi)核將 ip forward 功能打開,就是把內(nèi)核參數(shù) ip_forward 設(shè)置為 1。Docker daemon 在啟動(dòng)的時(shí)候會(huì)執(zhí)行這個(gè)操作,我們可以通過下面的命令進(jìn)行檢查:
$ cat /proc/sys/net/ipv4/ip_forward
返回的結(jié)果為 1,表示內(nèi)核的 ip forward 功能已經(jīng)打開。
容器的 DNS 和主機(jī)名(hostname)
使用同一個(gè) docker 鏡像可以創(chuàng)建很多個(gè) docker 容器,但是這些容器的 hostname 并不相同,也就是說 hostname 并沒有被寫入到鏡像中。實(shí)際上容器中的 /etc 目錄下有 3 個(gè)文件是在容器啟動(dòng)后被虛擬文件覆蓋掉的,分別是 /etc/hostname、/etc/hosts 和 /etc/resolv.conf,通過在容器中運(yùn)行 mount 命令可以看到它們:
# mount … /dev/mapper/ubuntu--vg-root on /etc/resolv.conf type ext4 (rw,relatime,errors=remount-ro,data=ordered) /dev/mapper/ubuntu--vg-root on /etc/hostname type ext4 (rw,relatime,errors=remount-ro,data=ordered) /dev/mapper/ubuntu--vg-root on /etc/hosts type ext4 (rw,relatime,errors=remount-ro,data=ordered) …
這種方式既能解決主機(jī)名的問題,同時(shí)也能讓 DNS 及時(shí)更新(改變 resolv.conf)。由于這些文件的維護(hù)方法會(huì)隨著 docker 版本的升級(jí)而不斷變化,所以盡量不要修改這些文件,而是通過 docker 提供的相關(guān)參數(shù)進(jìn)行設(shè)置,其參數(shù)配置方式如下。
-h HOSTNAME 或者 --hostname=HOSTNAME:設(shè)置容器的 hostname,此名稱會(huì)寫入到 /etc/hostname 和 /etc/hosts 文件中,也可以在容器的 bash 提示符中看到。
--dns=IP_ADDRESS…:為容器配置 DNS,會(huì)被寫入到 /etc/resolv.conf 文件中。
這兩個(gè)參數(shù)都是針對(duì)容器的需要在創(chuàng)建容器時(shí)進(jìn)行設(shè)置。比如下面的 demo:
$ docker run -it --name mycon -h lion --dns=8.8.8.8 ubuntu:14.04
總結(jié)
本文主要通過演示 docker0 網(wǎng)橋相關(guān)的功能來探索 docker 網(wǎng)絡(luò)中的 bridge 驅(qū)動(dòng)的實(shí)現(xiàn)機(jī)制。從本文中不難看出,linux 系統(tǒng)中,docker 的 bridge 驅(qū)動(dòng)是依賴于系統(tǒng)的 ip forward 以及 iptables 等核心功能的。因此在學(xué)習(xí) docker 的過程中,適當(dāng)?shù)难a(bǔ)充 linux 相關(guān)的知識(shí)也是十分必要的!
審核編輯:黃飛
-
網(wǎng)橋
+關(guān)注
關(guān)注
0文章
129瀏覽量
16923 -
容器
+關(guān)注
關(guān)注
0文章
490瀏覽量
22013 -
Bridge
+關(guān)注
關(guān)注
0文章
15瀏覽量
11867 -
Docker
+關(guān)注
關(guān)注
0文章
446瀏覽量
11773
原文標(biāo)題:拿捏Docker 網(wǎng)絡(luò) bridge 驅(qū)動(dòng)
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論