docker(四):容器虛擬化網絡概述


一、docker網絡介紹

  在開始的博客中就有提過,現在的linux內核已經支持六種名稱空間:user、uts,mount,ipc,pid,net,而net主要就是用於網絡設備、協議棧的隔離。inux內核支持二層和三層設備的模擬,宿主機的docker0就是用軟件來實現的具有交換功能的虛擬二層設備,docker中的網卡設備是成對出現的,好比網線的兩頭,一頭處於docker中,另外一頭在docker0橋上,這個使用brctl工具就能實現。所以

[root@docker1 ~]# ip a | grep docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

  下面我們使用ip命令操作網絡名稱空間,簡單模擬容器間的網絡通信(當我們使用ip命令去管理網絡名稱空間的時候,只有網絡名稱空間是被隔離的,其它名稱空間都是共享的。),這里使用一台沒有安裝docker的主機,避免混淆。

# 首先確定系統中是否有iproute的包,ip命令就包含在這個包中
[root@docker3 ~]# rpm -qa iproute
iproute-3.10.0-87.el7.x86_64
# 添加網絡名稱空間
[root@docker3 ~]# ip netns help
[root@docker3 ~]# ip netns add ns1
[root@docker3 ~]# ip netns add ns2
[root@docker3 ~]# ip netns ls
ns2
ns1
# 如果我們沒有單獨給這兩個名稱空間創建網卡的話,默認是只有一個lo的。
[root@docker3 ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
[root@docker3 ~]# ip netns exec ns2 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 創建網卡對
[root@docker3 ~]# ip link help
[root@docker3 ~]# ip link add name veth1.1 type veth peer name veth1.2
[root@docker3 ~]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 00:0c:29:c4:4a:ca brd ff:ff:ff:ff:ff:ff
3: veth1.2@veth1.1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 5e:b2:bb:e4:bc:a7 brd ff:ff:ff:ff:ff:ff
4: veth1.1@veth1.2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 06:5f:16:be:a1:56 brd ff:ff:ff:ff:ff:ff
# 可以看到veth1.1的另一半是veth1.2,veth1.2的另一半是veth1.1,此時這兩塊網卡存在於我們的物理機上,但是處於未激活狀態,現在我們把veth1.2放到ns1名稱空間中
[root@docker3 ~]# ip link set dev veth1.2 netns ns1
# 一個虛擬網卡只能屬於一個網絡名稱空間,所以在物理機上只剩veth1.1了。而ns1網絡名稱空間中已經多了一個veth1.2。
[root@docker3 ~]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
    link/ether 00:0c:29:c4:4a:ca brd ff:ff:ff:ff:ff:ff
4: veth1.1@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT qlen 1000
    link/ether 06:5f:16:be:a1:56 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@docker3 ~]# ip netns exec ns1 ip a 
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: veth1.2@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 5e:b2:bb:e4:bc:a7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 當然,也可以給網卡改名字,這里為了方便查看就不修改了。命令如下:
[root@docker3 ~]# ip netns exec ns1 ip link set dev veth1.2 name eth0
# 配置地址並激活網卡使宿主機能與ns1通信
[root@docker3 ~]# ifconfig veth1.1 10.0.0.1/24 up
[root@docker3 ~]# ip netns exec ns1 ifconfig veth1.2 10.0.0.2/24 up
[root@docker3 ~]# ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.047 ms
# 接下來我們再把veth1.1放到ns2為網絡名稱空間中,並實現ns1和ns2的通信
[root@docker3 ~]# ip link set dev veth1.1 netns ns2
[root@docker3 ~]# ip netns exec ns2 ifconfig veth1.1 10.0.0.3/24 up
[root@docker3 ~]# ip netns exec ns2 ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.027 ms

二、docker網絡類型

  docker支持五種網絡類型,但是安裝后只默認提供三種,如下:

[root@docker2 ~]# docker info | grep -w Network
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
 Network: bridge host macvlan null overlay
# 兩條命令解除上面的警告信息
[root@docker2 ~]# echo -e 'bridge-nf-call-iptables = 1\nbridge-nf-call-ip6tables = 1' >>/etc/sysctl.conf 
[root@docker2 ~]# reboot
# 安裝docker后,默認提供的三種網絡類型
[root@docker2 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
4784b8e4f640        bridge              bridge              local
f5a426943455        host                host                local
61be1051e1fe        none                null                local
# bridge是默認的網絡類型
[root@docker2 ~]# docker network inspect bridge | grep bridge.name
            "com.docker.network.bridge.name": "docker0"

三、docker容器類型

  docker的網絡類型和容器模型是相關聯的,所以就都放在下面說吧。

  • 封閉式容器
      使用名稱空間,但是不創建網路設備,只有一個lo接口。實現如下:
[root@docker2 ~]# docker run --name busy01 -it --network none --rm busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
  • 橋接式容器
      默認的容器類型,故可以省去network的參數。創建網絡設備時,一半在容器內部,一半在宿主機的docker0上。實現如下:
[root@docker2 ~]# docker run --name busy01 -it --network bridge --rm busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 10.0.255.255 scope global eth0
       valid_lft forever preferred_lft forever
  • 聯盟式容器
      創建一個容器加入另一個容器,共享net、uts、ipc名稱空間,獨享其它名稱空間。
[root@docker2 ~]# docker run --name busy01 -it --rm busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:0a:00:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 10.0.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # hostname 
4a5449c67f3a
# 此時另開一窗口,在啟動另外一個容器,可以看到ip和主機名啥的都是一樣的
[root@docker2 ~]# docker run --name busy02 -it --network container:busy01 --rm busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:0a:00:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 10.0.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # hostname 
4a5449c67f3a
# 做個測試,證明兩個容器時共用lo接口的,在busy01上面啟動一個httpd
/ # echo 'I am very happy' >/tmp/test/index.html
/ # httpd -f -h /tmp/test/
# 在busy02上訪問本地接口lo,可以看到是成功的
/ # wget -O - -q 127.0.0.1
I am very happy
# 但是文件系統還是隔離的,在busy01容器中創建一個目錄
/ # mkdir /tmp/test
# 在busy02中查看,是木得的
/ # ls /tmp/
/ # 
  • 開放式容器
      開放式容器時聯盟是容器的一個延伸,這種類型的容器直接共享宿主機的網絡名稱空間。
[root@docker2 ~]# docker run --name busy01 -it --network host --rm busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:0c:29:90:c4:6e brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.12/24 brd 10.10.10.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe90:c46e/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
    link/ether 02:42:6a:2a:e2:bb brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 10.0.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:6aff:fe2a:e2bb/64 scope link 
       valid_lft forever preferred_lft forever
7: veth340cf79@if6: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 
    link/ether 0a:29:9a:4d:3b:da brd ff:ff:ff:ff:ff:ff
    inet6 fe80::829:9aff:fe4d:3bda/64 scope link 
       valid_lft forever preferred_lft forever
# 可以看到直接使用物理機的網絡設備,此時我們啟動一個httpd。
/ # echo 'good good study' >/tmp/index.html
/ # httpd -h /tmp/
/ # netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 :::80                   :::*                    LISTEN      8/httpd
tcp        0      0 :::22                   :::*                    LISTEN      -
# 這其實是直接監聽在物理機網卡地址的80端口,我們可以在瀏覽器做訪問測試

四、docker網絡實踐

  • 修改docker0橋的地址,添加bip設置
[root@docker2 ~]# ip a | grep docker0
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    inet 172.17.0.1/16 brd 10.0.255.255 scope global docker0
# docker0橋默認地址是172.17.網段的,現在我修改為172.16網絡的。
[root@docker2 ~]# vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://p4y8tfz4.mirror.aliyuncs.com"],
  "bip": "172.16.0.1/16"
}
[root@docker2 ~]# systemctl restart docker.service 
[root@docker2 ~]# ip a |grep docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    inet 172.16.0.1/16 brd 10.0.255.255 scope global docker0
# 當然也可以指定dns和default-gateway,格式與bip一樣的。
  • 遠程管理docker容器,官網有兩種方法,我只實現了一種。。。。
# 現在我的docker1和docker2主機都是有安裝docker的,我現在修改配置,使docker1能夠控制docker2的容器
[root@docker2 ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
2157de82161a        hamerle/httpd:v1    "/bin/httpd -f -h /d…"   6 days ago          Exited (137) 2 hours ago                       web007
[root@docker2 ~]# systemctl edit docker.service
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375
[root@docker2 ~]# systemctl daemon-reload 
[root@docker2 ~]# systemctl restart docker.service 
[root@docker2 ~]# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      765/sshd            
tcp        0      0 127.0.0.1:2375          0.0.0.0:*               LISTEN      5180/dockerd        
tcp6       0      0 :::22                   :::*                    LISTEN      765/sshd 
# docke daemon已經監聽到2375的端口,我們現在可以通過docker1遠程啟動docker2上的web007容器
[root@docker1 ~]# docker -H 10.0.0.12:2375 ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
2157de82161a        hamerle/httpd:v1    "/bin/httpd -f -h /d…"   6 days ago          Exited (137) 2 hours ago                       web007
[root@docker1 ~]# docker -H 10.0.0.12:2375 start web007 
web007
[root@docker2 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
2157de82161a        hamerle/httpd:v1    "/bin/httpd -f -h /d…"   6 days ago          Up 58 seconds                           web007
  • 手動創建一個網絡類型,並指定對應網橋設備的名稱為docker1,完整的參數可以參考官網,最終實現基於兩個不同網絡啟動的容器間互相通信。
[root@docker2 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
56e76e104239        bridge              bridge              local
af5460d6727a        host                host                local
2305ac12c2f1        none                null                local
[root@docker2 ~]# docker network create --help
[root@docker2 ~]# docker network create -o com.docker.network.bridge.name=docker1 -d bridge --subnet '172.18.0.0/16' bridge-test
32cc657f5b673d989a00555f9f9e5c37d470a5ba4e9b5f24918d163ae364e82e
    # -o:在使用bridge的driver類型時,可以使用-o的附加參數。上面實例中的參數意思是指定創建bridge類型網絡時對應虛擬網橋設備的名字。(就是ip a命令看到的名字)
    # -d:指定driver,默認類型就是bridge。
    # --subnet:指定新建的docker網絡的網段
    # 最后的bridg-test是即將要將創建出的網絡的名字.
[root@docker2 ~]# docker network ls 
NETWORK ID          NAME                DRIVER              SCOPE
56e76e104239        bridge              bridge              local
32cc657f5b67        bridge-test         bridge              local
af5460d6727a        host                host                local
2305ac12c2f1        none                null                local
[root@docker2 ~]# ip a | grep docker1
19: docker1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    inet 172.18.0.1/16 brd 172.16.255.255 scope global docker1
# 我們以bridge-test網絡啟動一個容器
[root@docker2 ~]# docker run --name busy01 -it --network bridge-test --rm busybox
/ # ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:10:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.16.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # 
# 另開一個窗口,使用bridge網絡再起一個容器
[root@docker2 ~]# docker run --name busy02 -it --network bridge --rm busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:0a:00:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.16.0.2/16 brd 10.0.255.255 scope global eth0
       valid_lft forever preferred_lft forever
# 可以看到兩個容器,一個是172.18網段,一個是172.16網段,此時做連通性測試。
/ # ping 172.18.0.2
# 不通,此時確定宿主機的ip_forward是否開啟,如果開啟還不通,則需要另開一個窗口排查防火牆規則。
[root@docker2 ~]# cat /proc/sys/net/ipv4/ip_forward
1
[root@docker2 ~]# iptables -nvL
# 排查防火牆規則,其實很簡單,把target類型為DROP的刪掉就好了。我這只列出有DROP的鏈,並刪除
[root@docker2 ~]# iptables -nvL DOCKER-ISOLATION-STAGE-2 --line-number 
Chain DOCKER-ISOLATION-STAGE-2 (2 references)
num   pkts bytes target     prot opt in     out     source               destination         
1       22  1848 DROP       all  --  *      docker1  0.0.0.0/0            0.0.0.0/0           
2        0     0 DROP       all  --  *      docker0  0.0.0.0/0            0.0.0.0/0           
3        0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0 
[root@docker2 ~]# iptables -D DOCKER-ISOLATION-STAGE-2 2
[root@docker2 ~]# iptables -D DOCKER-ISOLATION-STAGE-2 1
# 刪除完后再ping
/ # ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=63 time=0.262 ms
64 bytes from 172.18.0.2: seq=1 ttl=63 time=0.082 ms


寫作不易,轉載請注明出處,謝謝~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM