1. 程式人生 > >Docker學習筆記:Docker 網路配置

Docker學習筆記:Docker 網路配置

非常詳細的 Docker 學習筆記

Dokcer 通過使用 Linux 橋接提供容器之間的通訊,docker0 橋接介面的目的就是方便 Docker 管理。當 Docker daemon 啟動時需要做以下操作:

  • creates the docker0 bridge if not present
    • # 如果 docker0 不存在則建立
  • searches for an IP address range which doesn’t overlap with an existing route
    • # 搜尋一個與當前路由不衝突的 ip 段
  • picks an IP in the selected range
    • # 在確定的範圍中選擇 ip
  • assigns this IP to the docker0 bridge
    • # 繫結 ip 到 docker0

 6.1 Docker 四種網路模式

docker run 建立 Docker 容器時,可以用 --net 選項指定容器的網路模式,Docker 有以下 4 種網路模式:

  • host 模式,使用 --net=host 指定。
  • container 模式,使用 --net=container:NAMEorID 指定。
  • none 模式,使用 --net=none 指定。
  • bridge 模式,使用 --net=bridge 指定,預設設定。

host 模式

如果啟動容器的時候使用 host 模式,那麼這個容器將不會獲得一個獨立的 Network Namespace,而是和宿主機共用一個 Network Namespace。容器將不會虛擬出自己的網絡卡,配置自己的 IP 等,而是使用宿主機的 IP 和埠。

例如,我們在 10.10.101.105/24 的機器上用 host 模式啟動一個含有 web 應用的 Docker 容器,監聽 tcp 80 埠。當我們在容器中執行任何類似 ifconfig 命令檢視網路環境時,看到的都是宿主機上的資訊。而外界訪問容器中的應用,則直接使用 10.10.101.105:80 即可,不用任何 NAT 轉換,就如直接跑在宿主機中一樣。但是,容器的其他方面,如檔案系統、程序列表等還是和宿主機隔離的。

container 模式

這個模式指定新建立的容器和已經存在的一個容器共享一個 Network Namespace,而不是和宿主機共享。新建立的容器不會建立自己的網絡卡,配置自己的 IP,而是和一個指定的容器共享 IP、埠範圍等。同樣,兩個容器除了網路方面,其他的如檔案系統、程序列表等還是隔離的。兩個容器的程序可以通過 lo 網絡卡裝置通訊。

none模式

這個模式和前兩個不同。在這種模式下,Docker 容器擁有自己的 Network Namespace,但是,並不為 Docker容器進行任何網路配置。也就是說,這個 Docker 容器沒有網絡卡、IP、路由等資訊。需要我們自己為 Docker 容器新增網絡卡、配置 IP 等。

bridge模式

非常詳細的 Docker 學習筆記

bridge 模式是 Docker 預設的網路設定,此模式會為每一個容器分配 Network Namespace、設定 IP 等,並將一個主機上的 Docker 容器連線到一個虛擬網橋上。當 Docker server 啟動時,會在主機上建立一個名為 docker0 的虛擬網橋,此主機上啟動的 Docker 容器會連線到這個虛擬網橋上。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網路中。接下來就要為容器分配 IP 了,Docker 會從 RFC1918 所定義的私有 IP 網段中,選擇一個和宿主機不同的IP地址和子網分配給 docker0,連線到 docker0 的容器就從這個子網中選擇一個未佔用的 IP 使用。如一般 Docker 會使用 172.17.0.0/16 這個網段,並將 172.17.42.1/16 分配給 docker0 網橋(在主機上使用 ifconfig 命令是可以看到 docker0 的,可以認為它是網橋的管理介面,在宿主機上作為一塊虛擬網絡卡使用)

6.2 列出當前主機網橋

$ sudo brctl show # brctl 工具依賴 bridge-utils 軟體包 bridge name bridge id STP enabled interfaces
docker0 8000.000000000000 no

6.3 檢視當前 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

在容器執行時,每個容器都會分配一個特定的虛擬機器口並橋接到 docker0。每個容器都會配置同 docker0 ip 相同網段的專用 ip 地址,docker0 的 IP 地址被用於所有容器的預設閘道器。

6.4 執行一個容器

$ 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 會嘗試尋找沒有被主機使用的 ip 段,儘管它適用於大多數情況下,但是它不是萬能的,有時候我們還是需要對 ip 進一步規劃。Docker 允許你管理 docker0 橋接或者通過-b選項自定義橋接網絡卡,需要安裝bridge-utils軟體包。

基本步驟如下:

  • ensure Docker is stopped
    • # 確保 docker 的程序是停止的
  • create your own bridge (bridge0 for example)
    • # 建立自定義網橋
  • assign a specific IP to this bridge
    • # 給網橋分配特定的 ip
  • start Docker with the -b=bridge0 parameter
    • # 以 -b 的方式指定網橋
# 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

 6.5 不同主機間容器通訊

不同容器之間的通訊可以藉助於 pipework 這個工具:

$ git clone https://github.com/jpetazzo/pipework.git
$ sudo cp -rp pipework/pipework /usr/local/bin/

安裝相應依賴軟體

$ sudo apt-get install iputils-arping bridge-utils -y

橋接網路

橋接網路可以參考  日常問題處理 Tips 關於橋接的配置說明,這裡不再贅述。

# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.000c291412cd       no              eth0
docker0         8000.56847afe9799       no              vetheb48029

可以刪除 docker0,直接把 docker 的橋接指定為 br0。也可以保留使用預設的配置,這樣單主機容器之間的通訊可以通過 docker0,而跨主機不同容器之間通過 pipework 新建 docker 容器的網絡卡橋接到 br0,這樣跨主機容器之間就可以通訊了。

  • 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

非常詳細的 Docker 學習筆記

不同容器之間的通訊可以藉助於 pipework 這個工具給 docker 容器新建虛擬網絡卡並繫結 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]

如果刪除了預設的 docker0 橋接,把 docker 預設橋接指定到了 br0,則最好在建立容器的時候加上--net=none,防止自動分配的 IP 在區域網中有衝突。

$ sudo docker run --rm -ti --net=none ubuntu:14.04 /bin/bash
[email protected]:/#
$                  # Ctrl-P + Ctrl-Q 回到宿主機 shell,容器 detach 狀態
$ 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/[email protected] 
# 預設不指定網絡卡裝置名,則預設新增為 eth1
# 另外 pipework 不能新增靜態路由,如果有需求則可以在 run 的時候加上 --privileged=true 許可權在容器中手動新增,
# 但這種安全性有缺陷,可以通過 ip netns 操作
$ sudo docker attach a46657528059
[email protected]:/# 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)

[email protected]:/# 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新增靜態路由,避免建立容器使用--privileged=true選項造成一些不必要的安全問題:

$ 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 
... ...

在其它宿主機進行相應的配置,新建容器並使用 pipework 新增虛擬網絡卡橋接到 br0,測試通訊情況即可。

另外,pipework 可以建立容器的 vlan 網路,這裡不作過多的介紹了,官方文件已經寫的很清楚了,可以檢視以下兩篇文章: