Docker網(wǎng)絡(luò)

  • docker0網(wǎng)橋
    當(dāng)在一臺未經(jīng)過特殊網(wǎng)絡(luò)配置的centos 或 ubuntu機(jī)器上安裝完docker之后,在宿主機(jī)上通過ifconfig命令可以看到多了一塊名為docker0的網(wǎng)卡,假設(shè)IP為 172.17.0.1/16。有了這樣一塊網(wǎng)卡,宿主機(jī)也會在內(nèi)核路由表上添加一條到達(dá)相應(yīng)網(wǎng)絡(luò)的靜態(tài)路由,可通過route -n查看:

    # route -n
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags   Metric   Ref         Use Iface
    ...
    172.17.0.0      0.0.0.0         255.255.0.0          U           0      0        0         docker0
    ...
    

    此條路由表示所有目的IP地址為172.17.0.0/16的數(shù)據(jù)包從docker0網(wǎng)卡轉(zhuǎn)發(fā)。

然后使用docker run命令創(chuàng)建一個執(zhí)行shell(/bin/bash)的Docker容器,假設(shè)容器名稱為con1。
?在con1容器中可以看到它有兩個網(wǎng)卡lo和eth0。lo設(shè)備不必多說,是容器的回環(huán)網(wǎng)卡;eth0即為容器與外界通信的網(wǎng)卡,eth0的ip 為 172.17.0.2/16,和宿主機(jī)上的網(wǎng)橋docker0在同一個網(wǎng)段。

查看con1的路由表,可以發(fā)現(xiàn)con1的默認(rèn)網(wǎng)關(guān)正是宿主機(jī)的docker0網(wǎng)卡,通過測試, con1可以順利訪問外網(wǎng)和宿主機(jī)網(wǎng)絡(luò),因此表明con1的eth0網(wǎng)卡與宿主機(jī)的docker0網(wǎng)卡是相互連通的。

這時在來查看(ifconfig)宿主機(jī)的網(wǎng)絡(luò)設(shè)備,會發(fā)現(xiàn)有一塊以“veth”開頭的網(wǎng)卡,如veth60b16bd,我們可以大膽猜測這塊網(wǎng)卡肯定是veth設(shè)備了,而veth pair總是成對出現(xiàn)的。veth pair通常用來連接兩個network namespace,那么另一個應(yīng)該是Docker容器con1中的eth0了。之前已經(jīng)判斷con1容器的eth0和宿主機(jī)的docker0是相連的,那么veth60b16bd也應(yīng)該是與docker0相連的,不難想到,docker0就不只是一個簡單的網(wǎng)卡設(shè)備了,而是一個網(wǎng)橋。

真實情況正是如此,下圖即為Docker默認(rèn)網(wǎng)絡(luò)模式(bridge模式)下的網(wǎng)絡(luò)環(huán)境拓?fù)鋱D,創(chuàng)建了docker0網(wǎng)橋,并以eth pair連接各容器的網(wǎng)絡(luò),容器中的數(shù)據(jù)通過docker0網(wǎng)橋轉(zhuǎn)發(fā)到eth0網(wǎng)卡上。


“深入淺出”來解讀Docker網(wǎng)絡(luò)核心原理

這里的網(wǎng)橋概念等同于交換機(jī),為連在其上的設(shè)備轉(zhuǎn)發(fā)數(shù)據(jù)幀。網(wǎng)橋上的veth網(wǎng)卡設(shè)備相當(dāng)于交換機(jī)上的端口,可以將多個容器或虛擬機(jī)連接在上面,這些端口工作在二層,所以是不需要配置IP信息的。圖中docker0網(wǎng)橋就為連在其上的容器轉(zhuǎn)發(fā)數(shù)據(jù)幀,使得同一臺宿主機(jī)上的Docker容器之間可以相互通信。
?大家應(yīng)該注意到docker0既然是二層設(shè)備,它上面怎么設(shè)置了IP呢?docker0是普通的linux網(wǎng)橋,它是可以在上面配置IP的,可以認(rèn)為其內(nèi)部有一個可以用于配置IP信息的網(wǎng)卡接口(如同每一個Open vSwitch網(wǎng)橋都有一個同名的內(nèi)部接口一樣)。在Docker的橋接網(wǎng)絡(luò)模式中,docker0的IP地址作為連于之上的容器的默認(rèn)網(wǎng)關(guān)地址存在。

在Linux中,可以使用brctl命令查看和管理網(wǎng)橋(需要安裝bridge-utils軟件包),比如查看本機(jī)上的Linux網(wǎng)橋以及其上的端口:

# brctl show
bridge   name   bridge id                       STP enabled        interfaces
docker0          8000.02420b69b449        no                    veth1b11267

更多關(guān)于brctl命令的功能和用法,大家通過man brctl或brctl --help查閱。

docker0網(wǎng)橋是在Docker daemon啟動時自動創(chuàng)建的,其IP默認(rèn)為172.17.0.1/16,之后創(chuàng)建的Docker容器都會在docker0子網(wǎng)的范圍內(nèi)選取一個未占用的IP使用,并連接到docker0網(wǎng)橋上。

除了使用docker0網(wǎng)橋外,還可以使用自己創(chuàng)建的網(wǎng)橋,比如創(chuàng)建一個名為br0的網(wǎng)橋,配置IP:

# brctl  addbr br0
# ifconfig  br0 18.18.0.1
  • iptables規(guī)則
    ?Docker安裝完成后,將默認(rèn)在宿主機(jī)系統(tǒng)上增加一些iptables規(guī)則,以用于Docker容器和容器之間以及和外界的通信,可以使用iptables-save命令查看。其中nat表中的POSTROUTING鏈有這么一條規(guī)則:

    -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
    

    參數(shù)說明:
    -s :源地址172.17.0.0/16
    -o:指定數(shù)據(jù)報文流出接口為docker0
    -j :動作為MASQUERADE(地址偽裝)

上面這條規(guī)則關(guān)系著Docker容器和外界的通信,含義是:將源地址為172.17.0.0/16的數(shù)據(jù)包(即Docker容器發(fā)出的數(shù)據(jù)),當(dāng)不是從docker0網(wǎng)卡發(fā)出時做SNAT。這樣一來,從Docker容器訪問外網(wǎng)的流量,在外部看來就是從宿主機(jī)上發(fā)出的,外部感覺不到Docker容器的存在。
?那么,外界想到訪問Docker容器的服務(wù)時該怎么辦呢?我們啟動一個簡單的web服務(wù)容器,觀察iptables規(guī)則有何變化。

1、首先啟動一個 tomcat容器,將其8080端口映射到宿主機(jī)上的8080端口上:

#docker run -itd --name  tomcat01 -p 8080:8080 tomcat:latest 

2、然后查看iptabels規(guī)則,省略部分無用信息:

#iptables-save
*nat
-A POSTROUTING -s 172.17.0.4/32 -d 172.17.0.4/32 -p tcp -m tcp --dport 8080 -j MASQUERADE
...

*filter
-A DOCKER -d 172.17.0.4/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -j ACCEPT

可以看到,在nat、filter的Docker鏈中分別增加了一條規(guī)則,這兩條規(guī)則將訪問宿主機(jī)8080端口的流量轉(zhuǎn)發(fā)到了172.17.0.4的8080端口上(真正提供服務(wù)的Docker容器IP和端口),所以外界訪問Docker容器是通過iptables做DNAT(目的地址轉(zhuǎn)換)實現(xiàn)的。
?此外,Docker的forward規(guī)則默認(rèn)允許所有的外部IP訪問容器,可以通過在filter的DOCKER鏈上添加規(guī)則來對外部的IP訪問做出限制,比如只允許源IP192.168.0.0/16的數(shù)據(jù)包訪問容器,需要添加如下規(guī)則:

iptables -I DOCKER -i docker0 ! -s 192.168.0.0/16 -j DROP

不僅僅是與外界間通信,Docker容器之間互個通信也受到iptables規(guī)則限制。同一臺宿主機(jī)上的Docker容器默認(rèn)都連在docker0網(wǎng)橋上,它們屬于一個子網(wǎng),這是滿足相互通信的第一步。同時,Docker daemon會在filter的FORWARD鏈中增加一條ACCEPT的規(guī)則(--icc=true):

-A FORWARD -i docker0 -o docker0 -j ACCEPT

這是滿足相互通信的第二步。當(dāng)Docker datemon啟動參數(shù)--icc(icc參數(shù)表示是否允許容器間相互通信)設(shè)置為false時,以上規(guī)則會被設(shè)置為DROP,Docker容器間的相互通信就被禁止,這種情況下,想讓兩個容器通信就需要在docker run時使用 --link選項。

在Docker容器和外界通信的過程中,還涉及了數(shù)據(jù)包在多個網(wǎng)卡間的轉(zhuǎn)發(fā)(如從docker0網(wǎng)卡轉(zhuǎn)發(fā)到宿主機(jī)ens160網(wǎng)卡),這需要內(nèi)核將ip-forward功能打開,即將ip_forward系統(tǒng)參數(shù)設(shè)1。Docker daemon啟動的時候默認(rèn)會將其設(shè)為1(--ip-forward=true),也可以通過命令手動設(shè)置:

# echo 1 > /proc/sys/net/ipv4/ip_forward
# cat /proc/sys/net/ipv4/ip_forward
1
  • Docker容器的DNS和主機(jī)名
    ?同一個Docker鏡像可以啟動很多Docker容器,通過查看,它們的主機(jī)名并不一樣,也即是說主機(jī)名并非是被寫入鏡像中的。實際上容器中/etc/目錄下有3個文件是容器啟動后被虛擬文件覆蓋的,分別是/etc/hostname、/etc/hosts、/etc/resolv.conf,通過在容器中運(yùn)行mount命令可以查看:

    # docker exec -it tomcat01 bash
    root@3d95d30c69d3:/usr/local/tomcat# mount
    ...
    /dev/mapper/centos-root on /etc/resolv.conf type xfs (rw,relatime,attr2,inode64,noquota)
    /dev/mapper/centos-root on /etc/hostname type xfs (rw,relatime,attr2,inode64,noquota)
    /dev/mapper/centos-root on /etc/hosts type xfs (rw,relatime,attr2,inode64,noquota)
    ...
    

    這樣能解決主機(jī)名的問題,同時也能讓DNS及時更新(改變resolv.conf)。由于這些文件的維護(hù)方法隨著Docker版本演進(jìn)而不斷變化,因此盡量不修改這些文件,而是通過Docker提供的參數(shù)進(jìn)行相關(guān)設(shè)置,配置方式如下:

  • -h HOSTNAME 或 --hostname=HOSTNAME:設(shè)置容器的主機(jī)名,此名稱會寫在/etc/hostname和/etc/hosts文件中,也會在容器的bash提示符看到。但是在外部,容器的主機(jī)名是無法查看的,不會出現(xiàn)在其他容器的hosts文件中,即使使用docker ps命令也查看不到。此參數(shù)是docker run命令的參數(shù),而非docker daemon的啟動參數(shù)。

  • --dns=IP_ADDRESS...:為容器配置DNS,寫在/etc/resolv.conf中。該參數(shù)即可以在docker daemon 啟動的時候設(shè)置,也可以在docker run時設(shè)置,默認(rèn)為8.8.8或8.8.4.4。

注意:對以上3個文件的修改不會被docker commit保存,也就是不會保存在鏡像中,重啟容器也會導(dǎo)致修改失效。另外,在不穩(wěn)定的網(wǎng)絡(luò)環(huán)境下使用需要特別注意DNS的設(shè)置。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容