企業級微服務實戰(六)

Docker 網絡剖析與實戰

1. Docker 網絡驅動模型

在咱們使用的 v18.09 版本中 官方文檔,官方文檔給出了一下如下五種網絡驅動模型,以下:docker

  • bridge:網橋類型網絡;其實就是咱們以前介紹五大虛擬化網絡模型中的 NAT網絡,只不過這裏叫作 bridge 網橋類型
  • host:主機類型網絡,其原理是容器使用宿主機的網絡名稱空間,所以會直接看到並使用宿主機的全部網絡功能,對應我們以前在虛擬化網絡模型中的 「橋接網絡」,這裏叫作 host 網絡驅動
  • none:禁用容器網絡,即在容器中不啓動網絡,僅有 lo 網卡用於本地迴環地址通訊;
  • overlay:疊加網絡,藉助 docker swarm 服務實現的高級疊加網絡模型;
  • macvlan:在 macvlan 網絡模型下,咱們能夠將 MAC 地址分配給某個容器,這樣當容器須要經過物理網絡傳輸數據時,能夠直接經過 MAC 地址進行路由傳輸,而再也不依靠 docker host 也就是宿主機的網絡棧進行轉發,提升報文處理效率;

可是有過 docker 使用經驗的朋友,可能都知道還有另一種驅動模型,即 container 容器網絡驅動模型,這種模型跟 host 類型有些相似,只不過 host 類型是容器和宿主機共享網絡名稱空間,而 container 類型是多個容器之間共享網絡名稱空間。json

注意:這裏咱們提到共享網絡名稱空間(host & container 網絡驅動模型),可是實際上除了網絡名稱空間外,還有 IPC、UTS 兩個名稱空間被共享,也就是說容器僅 MOUNT、PID、USER 這三個名稱空間是本身獨有的!

對於 container 網絡模型,在生產上主要用於兩個容器間的高效通訊,官方文檔上雖然已經隱藏了該類型,可是我在測試後發現依然能夠正常使用。不過你們要注意,若是沒有特別需求,仍是不要使用這種模型了。網絡


2. Docker 網絡模型架構圖

咱們來看下常見的網絡驅動模型架構圖:
image.png
其中圖中 Closed container 對應咱們上面提到的 none 網絡模型;Bridged container 對應 bridge 模型;Joined container 對應 container 網絡模型;Open container 則對應 host 網絡模型。
下面咱們對常見的網絡驅動模型進行講解與演示。架構


3. Docker 網絡模型演示

3.1 bridge 網絡模型

bridgedocker 上默認的容器網絡模型,該模型默認會建立一個 docker0 的網橋,網橋地址爲 172.16.0.1,鏈接到該網橋上的容器會從地址段 172.17.0.0/16 中獲取一個隨機地址。若是咱們想要修改容器的默認網橋信息,能夠經過修改 daemon.json 配置文件,官網中給出了示例,以下:socket

{
  "bip": "192.168.1.5/24",
  "fixed-cidr": "192.168.1.5/25",
  "fixed-cidr-v6": "2001:db8::/64",
  "mtu": 1500,
  "default-gateway": "10.20.1.1",
  "default-gateway-v6": "2001:db8:abcd::89",
  "dns": ["10.20.1.2","10.20.1.3"]
}

你們若是須要修改的,能夠參考該配置文件進行修改。
爲了更好的演示該網絡模型,咱們先中止全部容器。tcp

# 中止並刪除全部容器
[root@docker-server ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

查看當前宿主機網絡信息微服務

[root@docker-server ~]# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:88:01:70 brd ff:ff:ff:ff:ff:ff
    inet 172.24.236.96/22 brd 172.24.239.255 scope global dynamic eth0
       valid_lft 74261sec preferred_lft 74261sec
    inet6 fe80::a00:27ff:fe88:170/64 scope link
       valid_lft forever preferred_lft forever
5: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:83:32:b3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.3.15/24 brd 10.0.3.255 scope global dynamic eth1
       valid_lft 74263sec preferred_lft 74263sec
    inet6 fe80::a00:27ff:fe83:32b3/64 scope link
       valid_lft forever preferred_lft forever
6: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:39:1f:ab:bd brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:39ff:fe1f:abbd/64 scope link
       valid_lft forever preferred_lft forever
由於我實驗環境比較特殊,因此啓動了兩個網卡 eth0、eth1
咱們能夠看到除了在 docker daemon 啓動後建立的 docker0 網卡外,沒有其餘虛擬網卡,等咱們建立完容器以後,再來對比看下宿主機上的網卡信息。

查看此時的網橋信息工具

注: brctl 工具默認沒有,須要咱們手動安裝 bridge-utils 安裝包。
[root@docker-server ~]# brctl show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.0242391fabbd    no

【建立兩個容器】oop

[root@docker-server ~]# docker run --name demo1 --rm -it busybox:latest
[root@docker-server ~]# docker run --name demo2 --rm -it busybox:latest
[root@docker-server ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
880ca55196da        busybox:latest      "sh"                26 seconds ago      Up 11 seconds                           demo1
f46be5a89f6d        busybox:latest      "sh"                18 seconds ago      Up 17 seconds                           demo2

【再查看網卡和網橋信息】學習

[root@docker-server ~]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:88:01:70 brd ff:ff:ff:ff:ff:ff
5: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:83:32:b3 brd ff:ff:ff:ff:ff:ff
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
    link/ether 02:42:39:1f:ab:bd brd ff:ff:ff:ff:ff:ff
106: veth0813d85@if105: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    link/ether ca:5e:7e:19:06:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0
108: veth789d62b@if107: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
    link/ether 3e:6b:52:7d:27:a3 brd ff:ff:ff:ff:ff:ff link-netnsid 1
[root@docker-server ~]# brctl show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.0242391fabbd    no        veth0813d85
                                  veth789d62b

能夠看到此時多了兩個虛擬網卡,並且該網卡是成對出現的,一半鏈接在宿主機上的 docker 網橋上,一半在容器中。
那麼咱們怎麼去判斷網卡的另外一半是在哪一個容器中,請仔細看視頻教程。
那此時咱們如何看容器的 IP 地址,固然能夠經過登陸到容器以後再查看,可是比較麻煩,使用 docker [container] inspect 就能夠查看,以下:

[root@docker-server ~]# docker inspect demo1 -f {{.NetworkSettings.Networks.bridge.IPAddress}}
172.17.0.2
[root@docker-server ~]# docker inspect demo2 -f {{.NetworkSettings.Networks.bridge.IPAddress}}
172.17.0.3

【容器網絡測試】

[root@docker-server ~]# docker exec -it demo1  ping -c 2 baidu.com
PING baidu.com (39.156.69.79): 56 data bytes
64 bytes from 39.156.69.79: seq=0 ttl=61 time=6.608 ms
64 bytes from 39.156.69.79: seq=1 ttl=61 time=39.276 ms

--- baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 6.608/22.942/39.276 ms

爲何網絡能通呢

[root@docker-server ~]# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  0.0.0.0/0            0.0.0.0/0

其中

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

該規則的意義是,讓全部從 172.17.0.0/16 網段的源地址,發往 !docker0 網卡的數據(即 非本地容器地址)所有作源地址轉換,也就是我們以前虛擬化網絡模型中的 NAT 模型。如今來看下下面這幅 bridge 模型圖,應該能清晰的描繪出數據流了吧。
image.png

3.2 host 網絡模型

咱們演示一下該網絡模型的建立,以及該網絡模型下的網卡特性。
【建立 host 網絡模型容器】

[root@docker-server ~]# docker run --name demo3 -it --rm --network host busybox:latest

查看網絡信息

/ # ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    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
4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 08:00:27:88:01:70 brd ff:ff:ff:ff:ff:ff
    inet 172.24.236.96/22 brd 172.24.239.255 scope global dynamic eth0
       valid_lft 70857sec preferred_lft 70857sec
    inet6 fe80::a00:27ff:fe88:170/64 scope link
       valid_lft forever preferred_lft forever
5: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 08:00:27:83:32:b3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.3.15/24 brd 10.0.3.255 scope global dynamic eth1
       valid_lft 70859sec preferred_lft 70859sec
    inet6 fe80::a00:27ff:fe83:32b3/64 scope link
       valid_lft forever preferred_lft forever
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
    link/ether 02:42:39:1f:ab:bd brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:39ff:fe1f:abbd/64 scope link
       valid_lft forever preferred_lft forever
106: veth0813d85@if105: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0
    link/ether ca:5e:7e:19:06:dd brd ff:ff:ff:ff:ff:ff
    inet6 fe80::c85e:7eff:fe19:6dd/64 scope link
       valid_lft forever preferred_lft forever
108: veth789d62b@if107: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0
    link/ether 3e:6b:52:7d:27:a3 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::3c6b:52ff:fe7d:27a3/64 scope link
       valid_lft forever preferred_lft forever
能夠看到在 host 網絡模型下, docker container 能看到的網絡信息和宿主機是同樣的,也就是與宿主機共享NET網絡名稱空間與 IPC 名稱空間,那麼咱們繼續看下其餘的名稱空間 PID、MOUNT、USER、UTS

名稱空間的共享與獨享

# PID 名稱空間獨享
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 sh
   16 root      0:00 ps
   
# MOUNT 名稱空間獨享
/ # ls /root/
/ #
[root@docker-server ~]# ls /root/
a  anaconda-ks.cfg

# USER 名稱空間獨享
/ # cat /etc/passwd
root:x:0:0:root:/root:/bin/sh
daemon:x:1:1:daemon:/usr/sbin:/bin/false
bin:x:2:2:bin:/bin:/bin/false
sys:x:3:3:sys:/dev:/bin/false
sync:x:4:100:sync:/bin:/bin/sync
mail:x:8:8:mail:/var/spool/mail:/bin/false
www-data:x:33:33:www-data:/var/www:/bin/false
operator:x:37:37:Operator:/var:/bin/false
nobody:x:65534:65534:nobody:/home:/bin/false
/ #

# UTS 名稱空間獨享
/ # hostname
docker-server
通常容器只具備宿主機網絡的使用權限,而不具備修改權限。
這種網絡模型,容器能夠直接使用宿主機網絡,由於不須要額外的地址轉換,因此效率很高。可是容器與宿主機使用相同網絡,就致使了網絡資源的佔用,好比容器佔用了 tcp 80 端口,那麼宿主機就不能在使用這個端口。
3.3 none 網絡模型

一塊兒來看下這種網絡模型怎麼建立:

[root@docker-server ~]# docker run --name demo4 -it --rm --network none busybox
/ # ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

/ #

爲何存在這種模型呢?由於企業中有時候還真須要這種容器,好比咱們以前作數據清洗的一個程序,它其實不須要網絡,只須要把數據處理完保存到本地便可(固然這藉助到容器的「卷存儲」知識,咱們後面再說)。

3.4 container 網絡模型

若是同一個宿主機上的不一樣容器想要通訊,最容易想到的方法是什麼?兩個容器都使用 bridge 模型,即至關於容器鏈接到同一個虛擬網橋上,只要配置好 IP 地址就能夠直接基於 tcp/ip 通訊,這種方式固然能夠,只不過還有另一種方式,即讓兩個容器使用相同的網絡名稱空間,他們之間基於 IPC 通訊,效率更好。下面咱們跟你們演示一下如何建立這種模型:
建立一個新的容器

[root@docker-server ~]# docker run --name demo5 --rm -it busybox:latest
/ #

建立 container 網絡類型容器

[root@docker-server ~]# docker run --name demo6 --rm -it --network container:demo5 busybox:latest
/ #
注意:須要指定使用哪一個容器的網絡。

名稱空間的共享與獨享

# IPC 共享,兩個容器能夠直接經過 Unix socket 通訊
# UTS 共享(兩個容器中主機名相同)
/ # hostname
7104b99d8de4

# NET 共享(兩個容器中網絡信息相同)
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:04
          inet addr:172.17.0.4  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:108 errors:0 dropped:0 overruns:0 frame:0
          TX packets:104 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:9969 (9.7 KiB)  TX bytes:9597 (9.3 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

# PID 獨享
(demo5)/ # ping -c 100 baidu.com &
/ # ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 sh
   15 root      0:00 ping -c 100 baidu.com
   16 root      0:00 ps -ef
(demo6)/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 sh
   13 root      0:00 ps
   
# MOUNT 獨享
(demo6)/ # touch test
/ # ls
bin   dev   etc   home  proc  root  sys   test  tmp   usr   var
(demo5)/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var

# USER 獨享(busybox 沒法測試,你們可使用其餘鏡像進行測試)
注意:這種網絡模型通常用於兩個容器之間網絡依賴性特別強,相比較 bridge 模型能夠提升網絡效率,可是一樣帶來了容器之間的服務依賴。以我們實例爲例,demo6 依賴與 demo5 的網絡,一旦 demo5 容器終止,則 demo6 也沒法使用網絡。微服務初衷是想讓服務之間解耦,可是這種網絡模型反而使二者的依賴程度增高,因此這也多是 docker 官方文檔中再也不體現這種網絡模型的緣由。

注:更多技術博客請關注 字節教育官網,若是在學習或者本身實驗的過程當中遇到問題,及時與做者溝通。【QQ羣 374106486

相關文章
相關標籤/搜索