Docker學(xué)習(xí)筆記(四)Docker 網(wǎng)絡(luò)配置
六、Docker 網(wǎng)絡(luò)配置
圖: Docker - container and lightweight virtualization
Dokcer 通過使用 Linux 橋接提供容器之間的通信,docker0 橋接接口的目的就是方便 Docker 管理。當(dāng) Docker daemon 啟動時需要做以下操作:
- creates the docker0 bridge if not present
- # 如果 docker0 不存在則創(chuàng)建
- searches for an IP address range which doesn’t overlap with an existing route
- # 搜索一個與當(dāng)前路由不沖突的 ip 段
- picks an IP in the selected range
- # 在確定的范圍中選擇 ip
- assigns this IP to the docker0 bridge
- # 綁定 ip 到 docker0
6.1 Docker 四種網(wǎng)絡(luò)模式
四種網(wǎng)絡(luò)模式摘自 Docker 網(wǎng)絡(luò)詳解及 pipework 源碼解讀與實(shí)踐
docker run 創(chuàng)建 Docker 容器時,可以用 --net 選項(xiàng)指定容器的網(wǎng)絡(luò)模式,Docker 有以下 4 種網(wǎng)絡(luò)模式:
- host 模式,使用 --net=host 指定。
- container 模式,使用 --net=container:NAMEorID 指定。
- none 模式,使用 --net=none 指定。
- bridge 模式,使用 --net=bridge 指定,默認(rèn)設(shè)置。
host 模式
如果啟動容器的時候使用 host 模式,那么這個容器將不會獲得一個獨(dú)立的 Network Namespace,而是和宿主機(jī)共用一個 Network Namespace。容器將不會虛擬出自己的網(wǎng)卡,配置自己的 IP 等,而是使用宿主機(jī)的 IP 和端口。
例如,我們在 10.10.101.105/24 的機(jī)器上用 host 模式啟動一個含有 web 應(yīng)用的 Docker 容器,監(jiān)聽 tcp 80 端口。當(dāng)我們在容器中執(zhí)行任何類似 ifconfig 命令查看網(wǎng)絡(luò)環(huán)境時,看到的都是宿主機(jī)上的信息。而外界訪問容器中的應(yīng)用,則直接使用 10.10.101.105:80 即可,不用任何 NAT 轉(zhuǎn)換,就如直接跑在宿主機(jī)中一樣。但是,容器的其他方面,如文件系統(tǒng)、進(jìn)程列表等還是和宿主機(jī)隔離的。
container 模式
這個模式指定新創(chuàng)建的容器和已經(jīng)存在的一個容器共享一個 Network Namespace,而不是和宿主機(jī)共享。新創(chuàng)建的容器不會創(chuàng)建自己的網(wǎng)卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口范圍等。同樣,兩個容器除了網(wǎng)絡(luò)方面,其他的如文件系統(tǒng)、進(jìn)程列表等還是隔離的。兩個容器的進(jìn)程可以通過 lo 網(wǎng)卡設(shè)備通信。
none模式
這個模式和前兩個不同。在這種模式下,Docker 容器擁有自己的 Network Namespace,但是,并不為 Docker容器進(jìn)行任何網(wǎng)絡(luò)配置。也就是說,這個 Docker 容器沒有網(wǎng)卡、IP、路由等信息。需要我們自己為 Docker 容器添加網(wǎng)卡、配置 IP 等。
bridge模式
圖:The Container World | Part 2 Networking
bridge 模式是 Docker 默認(rèn)的網(wǎng)絡(luò)設(shè)置,此模式會為每一個容器分配 Network Namespace、設(shè)置 IP 等,并將一個主機(jī)上的 Docker 容器連接到一個虛擬網(wǎng)橋上。當(dāng) Docker server 啟動時,會在主機(jī)上創(chuàng)建一個名為 docker0 的虛擬網(wǎng)橋,此主機(jī)上啟動的 Docker 容器會連接到這個虛擬網(wǎng)橋上。虛擬網(wǎng)橋的工作方式和物理交換機(jī)類似,這樣主機(jī)上的所有容器就通過交換機(jī)連在了一個二層網(wǎng)絡(luò)中。接下來就要為容器分配 IP 了,Docker 會從 RFC1918 所定義的私有 IP 網(wǎng)段中,選擇一個和宿主機(jī)不同的IP地址和子網(wǎng)分配給 docker0,連接到 docker0 的容器就從這個子網(wǎng)中選擇一個未占用的 IP 使用。如一般 Docker 會使用 172.17.0.0/16 這個網(wǎng)段,并將 172.17.42.1/16 分配給 docker0 網(wǎng)橋(在主機(jī)上使用 ifconfig 命令是可以看到 docker0 的,可以認(rèn)為它是網(wǎng)橋的管理接口,在宿主機(jī)上作為一塊虛擬網(wǎng)卡使用)
6.2 列出當(dāng)前主機(jī)網(wǎng)橋
$ sudo brctl show # brctl 工具依賴 bridge-utils 軟件包 bridge name bridge id STP enabled interfaces docker0 8000.000000000000 no
6.3 查看當(dāng)前 docker0 ip
$ sudo ifconfig docker0 docker0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.0
在容器運(yùn)行時,每個容器都會分配一個特定的虛擬機(jī)口并橋接到 docker0。每個容器都會配置同 docker0 ip 相同網(wǎng)段的專用 ip 地址,docker0 的 IP 地址被用于所有容器的默認(rèn)網(wǎng)關(guān)。
6.4 運(yùn)行一個容器
$ sudo docker run -t -i -d ubuntu /bin/bash 52f811c5d3d69edddefc75aff5a4525fc8ba8bcfa1818132f9dc7d4f7c7e78b4 $ sudo brctl show bridge name bridge id STP enabled interfaces docker0 8000.fef213db5a66 no vethQCDY1N
以上, docker0 扮演著 52f811c5d3d6 container 這個容器的虛擬接口 vethQCDY1N interface 橋接的角色。
使用特定范圍的 IP
Docker 會嘗試尋找沒有被主機(jī)使用的 ip 段,盡管它適用于大多數(shù)情況下,但是它不是萬能的,有時候我們還是需要對 ip 進(jìn)一步規(guī)劃。Docker 允許你管理 docker0 橋接或者通過-b選項(xiàng)自定義橋接網(wǎng)卡,需要安裝bridge-utils軟件包。
基本步驟如下:
- ensure Docker is stopped
- # 確保 docker 的進(jìn)程是停止的
- create your own bridge (bridge0 for example)
- # 創(chuàng)建自定義網(wǎng)橋
- assign a specific IP to this bridge
- # 給網(wǎng)橋分配特定的 ip
- start Docker with the -b=bridge0 parameter
- # 以 -b 的方式指定網(wǎng)橋
# Stopping Docker and removing docker0 $ sudo service docker stop $ sudo ip link set dev docker0 down $ sudo brctl delbr docker0 # Create our own bridge $ sudo brctl addbr bridge0 $ sudo ip addr add 192.168.5.1/24 dev bridge0 $ sudo ip link set dev bridge0 up # Confirming that our bridge is up and running $ ip addr show bridge0 4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff inet 192.168.5.1/24 scope global bridge0 valid_lft forever preferred_lft forever # Tell Docker about it and restart (on Ubuntu) $ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker $ sudo service docker start
參考文檔: Network Configuration
6.5 不同主機(jī)間容器通信
不同容器之間的通信可以借助于 pipework 這個工具:
$ git clone https://github.com/jpetazzo/pipework.git $ sudo cp -rp pipework/pipework /usr/local/bin/
安裝相應(yīng)依賴軟件
$ sudo apt-get install iputils-arping bridge-utils -y
橋接網(wǎng)絡(luò)
橋接網(wǎng)絡(luò)可以參考 日常問題處理 Tips 關(guān)于橋接的配置說明,這里不再贅述。
# brctl show bridge name bridge id STP enabled interfaces br0 8000.000c291412cd no eth0 docker0 8000.56847afe9799 no vetheb48029
可以刪除 docker0,直接把 docker 的橋接指定為 br0。也可以保留使用默認(rèn)的配置,這樣單主機(jī)容器之間的通信可以通過 docker0,而跨主機(jī)不同容器之間通過 pipework 新建 docker 容器的網(wǎng)卡橋接到 br0,這樣跨主機(jī)容器之間就可以通信了。
- ubuntu
$ sudo service docker stop $ sudo ip link set dev docker0 down $ sudo brctl delbr docker0 $ echo 'DOCKER_OPTS="-b=br0"' >> /etc/default/docker $ sudo service docker start
- CentOS 7/RHEL 7
$ sudo systemctl stop docker $ sudo ip link set dev docker0 down $ sudo brctl delbr docker0 $ cat /etc/sysconfig/docker | grep 'OPTIONS=' OPTIONS=--selinux-enabled -b=br0 -H fd:// $ sudo systemctl start docker
pipework
不同容器之間的通信可以借助于 pipework 這個工具給 docker 容器新建虛擬網(wǎng)卡并綁定 IP 橋接到 br0
$ git clone https://github.com/jpetazzo/pipework.git $ sudo cp -rp pipework/pipework /usr/local/bin/ $ pipework Syntax: pipework <hostinterface> [-i containerinterface] <guest> <ipaddr>/<subnet>[@default_gateway] [macaddr][@vlan] pipework <hostinterface> [-i containerinterface] <guest> dhcp [macaddr][@vlan] pipework --wait [-i containerinterface]
如果刪除了默認(rèn)的 docker0 橋接,把 docker 默認(rèn)橋接指定到了 br0,則最好在創(chuàng)建容器的時候加上--net=none,防止自動分配的 IP 在局域網(wǎng)中有沖突。
$ sudo docker run --rm -ti --net=none ubuntu:14.04 /bin/bash root@a46657528059:/# $ # Ctrl-P + Ctrl-Q 回到宿主機(jī) shell,容器 detach 狀態(tài) $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a46657528059 ubuntu:14.04 "/bin/bash" 4 minutes ago Up 4 minutes hungry_lalande $ sudo pipework br0 -i eth0 a46657528059 192.168.115.10/24@192.168.115.2 # 默認(rèn)不指定網(wǎng)卡設(shè)備名,則默認(rèn)添加為 eth1 # 另外 pipework 不能添加靜態(tài)路由,如果有需求則可以在 run 的時候加上 --privileged=true 權(quán)限在容器中手動添加, # 但這種安全性有缺陷,可以通過 ip netns 操作 $ sudo docker attach a46657528059 root@a46657528059:/# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 86:b6:6b:e8:2e:4d inet addr:192.168.115.10 Bcast:0.0.0.0 Mask:255.255.255.0 inet6 addr: fe80::84b6:6bff:fee8:2e4d/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:9 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:690 (690.0 B) root@a46657528059:/# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.115.2 0.0.0.0 UG 0 0 0 eth0 192.168.115.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
使用ip netns添加靜態(tài)路由,避免創(chuàng)建容器使用--privileged=true選項(xiàng)造成一些不必要的安全問題:
$ docker inspect --format="{{ .State.Pid }}" a46657528059 # 獲取指定容器 pid 6350 $ sudo ln -s /proc/6350/ns/net /var/run/netns/6350 $ sudo ip netns exec 6350 ip route add 192.168.0.0/16 dev eth0 via 192.168.115.2 $ sudo ip netns exec 6350 ip route # 添加成功 192.168.0.0/16 via 192.168.115.2 dev eth0 ... ...
在其它宿主機(jī)進(jìn)行相應(yīng)的配置,新建容器并使用 pipework 添加虛擬網(wǎng)卡橋接到 br0,測試通信情況即可。
另外,pipework 可以創(chuàng)建容器的 vlan 網(wǎng)絡(luò),這里不作過多的介紹了,官方文檔已經(jīng)寫的很清楚了,可以查看以下兩篇文章:
posted on 2016-12-27 21:34 做強(qiáng)大的自己 閱讀(181) 評論(0) 編輯 收藏