玩轉Docker-------第四部------------(原生網絡&自定義網絡、容器通信)

玩轉Docker-------第四部------------(原生網絡&自定義網絡、容器通信)

1.Docker原生網絡

安裝Docker時,它會自動創建三個網絡,bridge(創建容器默認連接到此網絡)、 none 和host。

docker network ls

在這裏插入圖片描述

docker網絡模式 功能
Host 容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口。
Container(Joined) 創建的容器不會創建自己的網卡,配置自己的IP,而是和一個指定的容器共享IP、端口範圍。
None 該模式關閉了容器的網絡功能。
Bridge 此模式會爲每一個容器分配、設置IP等,並將容器連接到一個docker0虛擬網橋,通過docker0網橋以及Iptables nat表配置與宿主機通信。
運行容器的時候指定網絡模式:

模式					參數
host模式				使用 --net=host(–network host) 指定。
none模式				使用 --net=none 指定。
bridge模式				使用 --net=bridge 指定,默認設置。
container模式			使用 --net=container:NAME_or_ID 指定。

bridge網橋模式

bridge模式是Docker默認的網絡設置,當Docker server啓動時,會在主機上創建一個名爲docker0的虛擬網橋。
在這裏插入圖片描述
docker安裝時會創建一個名爲docker0的linux bridge,新建的容器會自動橋接到這個接口

[root@server1 ~]# docker run -d --name nginx nginx
998e60bd9dcd844c256d2889dfbc31e5cb7b7a34cfbd9298340b57d65142ac9c
[root@server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02422aa432f0	no		veth3c75f87

在這裏插入圖片描述
可以發現,當掛起一個容器時,就會出現相對應的網橋接口:

docker inspect nginx

在這裏插入圖片描述
這時,我們的容器就通過docker0網橋與宿主機建立通信了:

ping 172.17.0.3
curl 172.17.0.3

在這裏插入圖片描述

橋接模式下容器沒有公共 ip,只有宿主機可以訪問,外部主機不可見,容器要訪問外網必須通過宿主機的 NAT 規則,所以我們如果要想通過訪問本機的80端口去訪問容器,就需要做端口映射,將容器的80映射到server1主機上的80端口才行。而且橋接模式下容器是沒有對外的ip的,在企業中我們的server1主機ip應該是能進入到公網的IP,所以我們打開ip_forward的功能,讓容器可以通過server1訪問到外網。

不僅如此,只要宿主機做了NAT,我們同時在容器中做好dns解析,就能與外網通信

在這裏插入圖片描述
這樣在容器開啓的時候,就會生成網絡對,相當於一根網線,連接容器與docker0,docker0在通過內核路由功能轉發到我們的真實網卡上面,然後在出去,訪問到公網。

host模式

host模式下容器會和宿主機共享網絡。

相當於使用了Vmware中的橋接模式,與宿主機在同一個網絡中,但沒有獨立IP地址。

一個Network Namespace提供了一份獨立的網絡環境,包括網卡、路由、Iptable規則等都與其他的Network Namespace隔離。一個Docker容器一般會分配一個獨立的Network Namespace。但如果啓動容器的時候使用host模式,那麼這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機共用一個Network Namespace。容器將不會虛擬出自己的網卡,配置自己的IP等,而是使用宿主機的IP和端口。

host模式可以讓容器共享宿主機網絡棧,這樣的好處是外部主機與容器直接通信,但是容器的網絡缺少隔離性。

做此過程之前刪除上一步驟中運行的所有容器

netstat -antlp	#先查看宿主機的端口情況
docker run -d --name nginx  --network host nginx
netstat -antlp	#再次查看宿主機的端口情況(80端口打開了)
brctl show

在這裏插入圖片描述
在這裏插入圖片描述
我們可以看到它並不像bridge模式那樣,沒有在docker0下橋接接口,而是與宿主機共用一個網絡

用外部主機訪問,可以看到nginx默認發佈頁面

curl 192.168.43.71

在這裏插入圖片描述

docker run -it --rm --network host busybox
ip addr

在這裏插入圖片描述
可以看到與宿主機的網絡一模一樣

這時候,如果此時我們再開一個nginx:

docker run -d --name nginx2  --network host nginx
docker ps	#開啓成功
docker ps	#其中一個nginx消失
docker ps -a	#可以看到被停掉的nginx

在這裏插入圖片描述
在這裏插入圖片描述
這是因爲兩個nginx的端口和ip衝突了

none模式

none模式是指禁用網絡功能,只有lo接口,在容器創建時使用–network none

none模式關閉了容器的網絡功能,但是在以下兩種情況下是有用的:

  1. 容器並不需要網絡(例如只需要寫磁盤卷的批處理任務)。
  2. overlay:在docker1.7代碼進行了重構,單獨把網絡部分獨立出來編寫,所以在docker1.8新加入的一個overlay網絡模式。
docker run -it --rm --network none busybox
ip addr

在這裏插入圖片描述

可以看到只有lo接口

在這裏插入圖片描述
查看到網絡是不可以使用的

2.Docker自定義網絡

原生網絡是docker安裝後自動創建的,真正需要配置的是自定義網絡。

Docker 提供三種 user-defined 網絡驅動:bridge, overlay 和 macvlan。

bridge驅動類似默認的bridge網絡模式,但增加了一些新的功能
overlay 和 macvlan 用於創建跨主機的網絡

bridge網絡驅動

[root@server1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f905d0cfd038        bridge              bridge              local
5dc66fa4665c        host                host                local
304f37a81f85        none                null                local
[root@server1 ~]# docker network create -d bridge my_net1     # 創建自定義橋接
c73546940ab666d4c641eed79df76d8963f133a578b570209f1a6e922ce90efe
[root@server1 ~]# docker network ls       #可以看出我們的自定義網絡加進去了
NETWORK ID          NAME                DRIVER              SCOPE
f905d0cfd038        bridge              bridge              local
5dc66fa4665c        host                host                local
c73546940ab6        my_net1             bridge              local
304f37a81f85        none                null                local

[root@server1 ~]# docker run -it --name vm1 --network my_net1 ubuntu  # 用自定義網絡運行
root@9616cfb055e9:/# ip a
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
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
## 發現網段變成了172.18網段了,說明自定義網絡的時候網段是遞增的,和開啓容器時ip遞增一樣

## 我們還可以自定義網關和網段:
[root@server1 ~]# docker network create -d bridge --subnet 172.22.0.0/24 --gateway 172.22.0.1 my_net2
f5f5655d83dbd39958379c8c90d75025748a18787eb5de120f64224e83eee3d3
[root@server1 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f905d0cfd038        bridge              bridge              local
5dc66fa4665c        host                host                local
c73546940ab6        my_net1             bridge              local
f5f5655d83db        my_net2             bridge              local
304f37a81f85        none                null                local
[root@server1 ~]# docker run -it --name vm2 --network my_net2 ubuntu
root@2da970629875:/# ip a
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
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:16:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.2/24 brd 172.22.0.255 scope global eth0  #確實變成了172.22網段
       valid_lft forever preferred_lft forever


##自定義IP
[root@server1 ~]# docker run -it --name vm3 --network my_net2  --ip 172.22.0.100 ubuntu
root@71d882cabbc7:/# ip a
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
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:16:00:64 brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.100/24 brd 172.22.0.255 scope global eth0
       valid_lft forever preferred_lft forever
root@71d882cabbc7:/# ping 172.22.0.2     #可以ping同剛纔那個VM2容器,因爲橋接在同一網絡上
PING 172.22.0.2 (172.22.0.2) 56(84) bytes of data.
64 bytes from 172.22.0.2: icmp_seq=1 ttl=64 time=0.207 ms
64 bytes from 172.22.0.2: icmp_seq=2 ttl=64 time=0.086 ms
64 bytes from 172.22.0.2: icmp_seq=3 ttl=64 time=0.158 ms
^C
--- 172.22.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.086/0.150/0.207/0.050 ms


[root@server1 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
br-c73546940ab6		8000.02421577f327	no		veth734b2f2  #my_net1只橋接了一個網卡
br-f5f5655d83db		8000.024214c10f10	no		vethee1d0ed
							vethfdca8a6                      # my_net2橋接了兩個
docker0		8000.02422aa432f0	no		
# 橋接在不同網橋上的容器,彼此之間不能通信#

[root@server1 ~]# iptables -S
-A DOCKER-ISOLATION-STAGE-2 -o br-f5f5655d83db -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o br-c73546940ab6 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
可以看到三個網橋對互相之間的數據都是DROP
都是互相丟棄的所以不同網橋之間是無法通信的。

那我們如何讓不同網橋之間進行通信呢?

[root@server1 ~]# docker network connect my_net2 vm1
[root@server1 ~]# docker attach vm1
root@9616cfb055e9:/# ip a
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
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
16: eth1@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:16:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.22.0.3/24 brd 172.22.0.255 scope global eth1      # 多了172.22的網卡
       valid_lft forever preferred_lft forever
root@9616cfb055e9:/# ping vm1
PING vm1 (172.18.0.2) 56(84) bytes of data.
64 bytes from 9616cfb055e9 (172.18.0.2): icmp_seq=1 ttl=64 time=0.028 ms
64 bytes from 9616cfb055e9 (172.18.0.2): icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 9616cfb055e9 (172.18.0.2): icmp_seq=3 ttl=64 time=0.032 ms
^C
--- vm1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.028/0.031/0.033/0.002 ms
root@9616cfb055e9:/# ping vm2
PING vm2 (172.22.0.2) 56(84) bytes of data.
64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=2 ttl=64 time=0.050 ms
64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=3 ttl=64 time=0.048 ms
^C64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=4 ttl=64 time=0.048 ms
64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=5 ttl=64 time=0.050 ms
64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=6 ttl=64 time=0.140 ms
64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=7 ttl=64 time=0.066 ms
^C64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=8 ttl=64 time=0.051 ms
64 bytes from vm2.my_net2 (172.22.0.2): icmp_seq=9 ttl=64 time=0.049 ms
^C
--- vm2 ping statistics ---
9 packets transmitted, 9 received, 0% packet loss, time 8001ms
rtt min/avg/max/mdev = 0.048/0.063/0.140/0.028 ms
root@9616cfb055e9:/# ping vm3
PING vm3 (172.22.0.100) 56(84) bytes of data.
64 bytes from vm3.my_net2 (172.22.0.100): icmp_seq=1 ttl=64 time=0.057 ms
^C
--- vm3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.057/0.057/0.057/0.000 ms
#我們發現可以ping通#

root@9616cfb055e9:/# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.18.0.2	9616cfb055e9
172.22.0.3	9616cfb055e9   #這就是dns的自動解析,它自帶dns解析

這裏我們先介紹bridge,overlay 和macvlan在我們學習了容器之間的通信之後在進行學習

3.Docker容器間通信

通過上面的實驗我們可以知道,使用同一自定義網絡(即同一網段)運行的容器是可以相互通信的,那麼如果兩個容器不在同一網段,但我們也想讓它通信,怎麼辦?

方法1:使用內嵌的 DNS server 通過容器名去自動解析容器的IP地址

[root@server1 ~]# docker run -it --name vm1 --network my_net1 ubuntu
root@21692ff10442:/# [root@server1 ~]# docker run -it --name vm2 --network my_net1 ubuntu
root@c9c781f485c2:/# ping vm1
PING vm1 (172.18.0.2) 56(84) bytes of data.
64 bytes from vm1.my_net1 (172.18.0.2): icmp_seq=1 ttl=64 time=0.061 ms
64 bytes from vm1.my_net1 (172.18.0.2): icmp_seq=2 ttl=64 time=0.051 ms
^C
--- vm1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.051/0.056/0.061/0.005 ms
root@c9c781f485c2:/# ip a
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
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
  我們可以看到這裏多出了一個網卡eth0@if21,ip爲172.18.0.3

方法2:joined(類似於默認的 host 模式,容器之間共享網絡)

container模式指定新創建的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新創建的容器不會創建自己的網卡,配置自己的IP,而是和一個指定的容器共享IP、端口範圍等。同樣,兩個容器除了網絡方面,其他的如文件系統、進程列表等還是隔離的。兩個容器的進程可以通過lo網卡設備通信。

[root@server1 ~]# docker run -it --name vm1  ubuntu
root@9ff4ffcba7c0:/# ip a
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
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
root@9ff4ffcba7c0:/# [root@server1 ~]# docker run -it --name vm2  --network container:vm1 ubuntu
root@9ff4ffcba7c0:/# ip a
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
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

可以發現,和vm1網絡完全一致,使用相同的網絡name space:

這樣做的用處在於,兩個容器之間可以使用 localhost(迴環接口)進行快速通信,適用於 web 服務器和應用服務器。

方法3:使用–link連接容器

[root@server1 ~]# docker run -d nginx     #不加--name時系統會自動分配一個容器名
105b5c0c65f16c22681f6f193411ba459b12af7a225021cb8f23282cba5d818d
[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
105b5c0c65f1        nginx               "nginx -g 'daemon of…"   15 seconds ago      Up 14 seconds       80/tcp              lucid_aryabhata
[root@server1 ~]# docker run -it --name vm1 --link lucid_aryabhata:web ubuntu
###使用--link連接這個容器,併爲它起個別名web,因爲系統給的太難記了###
root@6c5b91bc7b5b:/# ping web
PING web (172.17.0.2) 56(84) bytes of data.
64 bytes from web (172.17.0.2): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from web (172.17.0.2): icmp_seq=2 ttl=64 time=0.106 ms
^C     #發現是可以通信的,這是因爲我們的容器做了兩件事
--- web ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.070/0.088/0.106/0.018 ms
root@6c5b91bc7b5b:/# cat /etc/hosts    # 第一,寫了解析
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2	web 105b5c0c65f1 lucid_aryabhata
172.17.0.3	6c5b91bc7b5b
root@6c5b91bc7b5b:/# env   # 第二設置了環境變量
...    
WEB_NAME=/vm1/web
WEB_PORT_80_TCP_PROTO=tcp
WEB_PORT_80_TCP_ADDR=172.17.0.2
...



[root@server1 ~]# docker stop lucid_aryabhata    #關閉剛開始的nginx容器
lucid_aryabhata
[root@server1 ~]# docker run -d nginx            #重新開一個
db52f4e7087049f0c0fba22cc2d9b909eb52a70cb266fb6940308f72a668fdf2
[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
db52f4e70870        nginx               "nginx -g 'daemon of…"   2 minutes ago       Up 2 minutes        80/tcp              happy_ptolemy
[root@server1 ~]# docker inspect happy_ptolemy
 "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",  #它的ip地址也是172.17.0.2
                    "IPPrefixLen": 16,

[root@server1 ~]# docker start lucid_aryabhata    #再打開剛纔第一個nginx容器
lucid_aryabhata
[root@server1 ~]# docker inspect lucid_aryabhata 
 "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",      # 它的ip地址變成了0.3了
          #####說明容器關閉後其獲得的ip地址會被釋放#####


[root@server1 ~]# docker start lucid_aryabhata 
lucid_aryabhata
[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
db52f4e70870        nginx               "nginx -g 'daemon of…"   13 minutes ago      Up 13 minutes       80/tcp              happy_ptolemy
105b5c0c65f1        nginx               "nginx -g 'daemon of…"   29 minutes ago      Up 8 seconds        80/tcp              lucid_aryabhata
[root@server1 ~]# docker start vm1 
vm1
[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
db52f4e70870        nginx               "nginx -g 'daemon of…"   13 minutes ago      Up 13 minutes       80/tcp              happy_ptolemy
6c5b91bc7b5b        ubuntu              "/bin/bash"              29 minutes ago      Up 5 seconds                            vm1
105b5c0c65f1        nginx               "nginx -g 'daemon of…"   30 minutes ago      Up 25 seconds       80/tcp              lucid_aryabhata
[root@server1 ~]# docker attach vm1 
root@6c5b91bc7b5b:/# 
root@6c5b91bc7b5b:/# 
root@6c5b91bc7b5b:/# 
root@6c5b91bc7b5b:/# cat /etc/hosts 
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	web 105b5c0c65f1 lucid_aryabhata     #VM1上的本地解析也變了
172.17.0.4	6c5b91bc7b5b

4.容器是如何訪問外網的?

容器與外網通信是通過iptables的SNAT實現的:

容器訪問外網是通過 iptables 的 SNAT 實現的,容器和 docker0 是橋接的方式,docker0 是
容器的網關,到達 docker0 後,通過 linux 內核的路由功能(ip_forward),然後防火牆會做
僞裝,也就是 SNAT,然後通過物理網卡接口到外網。

[root@server1 ~]# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.22.0.0/24 ! -o br-f5f5655d83db -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-c73546940ab6 -j MASQUERADE   #爲容器的ip做了地址僞裝
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i br-f5f5655d83db -j RETURN
-A DOCKER -i br-c73546940ab6 -j RETURN
-A DOCKER -i docker0 -j RETURN

在物理機開啓ip_forward讓server1可以上網

[root@server0 ~]# sysctl -a |grep ip_forward
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_use_pmtu = 0

# 測試:
[root@server1 ~]# ping baidu.com
PING baidu.com (220.181.38.148) 56(84) bytes of data.
64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=1 ttl=51 time=61.6 ms
64 bytes from 220.181.38.148 (220.181.38.148): icmp_seq=2 ttl=51 time=47.0 ms
^C
--- baidu.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 47.045/54.362/61.679/7.317 ms

#然後我們在進入ubuntu容器測試:
[root@server1 ~]# docker start vm1
vm1
[root@server1 ~]# docker attach vm1 
root@6c5b91bc7b5b:/# 
root@6c5b91bc7b5b:/# ping baidu.com
PING baidu.com (39.156.69.79) 56(84) bytes of data.
64 bytes from 39.156.69.79: icmp_seq=1 ttl=47 time=58.3 ms
64 bytes from 39.156.69.79: icmp_seq=2 ttl=47 time=48.7 ms
^C
--- baidu.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 48.767/53.583/58.399/4.816 ms
root@6c5b91bc7b5b:/# 
# 這樣容器就也可以上網了。

5.外網是如何訪問容器的?

[root@server1 ~]# docker run -d --name vm1 -p 80:80 nginx  做端口映射(冒號後的是容器內部的端口)
d995bd5ba8fe0008c288081d958fcb0bab05c9532232dc6c1986c7be2e3eee85
[root@server1 ~]# docker port vm1     ##查看容器端口映射情況
80/tcp -> 0.0.0.0:80
[root@server1 ~]# iptables -t nat -S     ##查看防火牆策略
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80

訪問流程:
外部主機訪問時--> 訪問到宿主機的 eth0(192.168.43.71:80)--> 然後火牆做了DNAT轉換 --> 訪問172.17.0.2(容器地
址)

測試:訪問192.168.43.71
在這裏插入圖片描述

在這裏插入圖片描述
docker-proxy 打開了80端口,我們每打開一個容器,都會開啓一個docker-proxy 進程

在這裏插入圖片描述

注意:

宿主機訪問本機容器使用 iptables 的 DNAT,外部主機訪問容器或者容器之間訪問是
docker-proxy 實現的。

流程:

外部主機 --> 宿主機 eth0 --> docker-proxy(外部訪問容器時通過 docker-proxy 處理數據
包,不是防火牆) --> docker0(172.17.0.1) --> 容器

6.Docker跨主機的容器網絡

docker跨主機的網絡方式:

docker原生的overlay和macvlan
第三方的flannel、weave、calico

CNM(container network model)模型

三類組件 作用
Sandbox 容器網絡棧(namespace
Endpoint 將sandbox接入network(veth)
Network 包含一組endpoint,同一network的endpoint可以通信

使用macvlan實現Docker容器跨主機網絡

macvlan特點:

  1. 使用linux內核提供的一種網卡虛擬化技術
  2. 性能好:因爲無需使用橋接,直接使用宿主機物理網口。

清理掉之前的容器,刪除自定義網絡:

[root@server1 ~]# docker network prune
WARNING! This will remove all networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
my_net1
my_net2

[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
baa31764f59f        nginx               "nginx -g 'daemon of…"   8 minutes ago       Up 8 minutes        0.0.0.0:8080->80/tcp   vm2
d995bd5ba8fe        nginx               "nginx -g 'daemon of…"   19 minutes ago      Up 19 minutes       0.0.0.0:80->80/tcp     vm1
[root@server1 ~]# docker rm -f vm1
vm1
[root@server1 ~]# docker rm -f vm2
vm2
[root@server1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

給兩臺主機都添加上一塊新的虛擬網卡。
在這裏插入圖片描述

[root@server1 ~]# ip a
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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:a5:b1:7f brd ff:ff:ff:ff:ff:ff
    inet 192.168.43.71/24 brd 192.168.43.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 240e:bf:d429:dd57:20c:29ff:fea5:b17f/64 scope global mngtmpaddr dynamic 
       valid_lft 2237sec preferred_lft 2237sec
    inet6 2409:8a70:f8a1:ae10:20c:29ff:fea5:b17f/64 scope global mngtmpaddr dynamic 
       valid_lft 259144sec preferred_lft 172744sec
    inet6 fe80::20c:29ff:fea5:b17f/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:2a:a4:32:f0 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:2aff:fea4:32f0/64 scope link 
       valid_lft forever preferred_lft forever
44: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 00:0c:29:a5:b1:89 brd ff:ff:ff:ff:ff:ff

添加之後,我們可以看到現在有ens0和eth1這兩塊網卡

激活這兩塊網卡,並開啓混雜模式:

server1:
[root@server1 ~]# ip link set up eth1
[root@server1 ~]# ip link set eth1 promisc on

server2:
[root@server2 ~]# ip link set up eth1
[root@server2 ~]# ip link set eth1 promisc on
[root@server2 ~]# ip a
能看到PROMISC 就會說明開啓了
4: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> 

在這裏插入圖片描述

server1和server2上創建macvlan 網絡模型:

[root@server1 ~]# docker network create -d macvlan --subnet 172.20.0.0/24 --gateway 172.20.0.1 -o parent=eth0 macvlan1
90bee86d976bb3293faf2531d7c71e82666f540cafed47ec6d3f756480cbb1fc

[root@server2 ~]# docker network create -d macvlan --subnet 172.20.0.0/24 --gateway 172.20.0.1 -o parent=eth0 macvlan1
499d58aa9c967b3559302a57a664d1abde6c0afef74d12c7cc70a8f9eba3b0ee

在這裏插入圖片描述
在這裏插入圖片描述

[root@server1 ~]# docker run -it --name vm1 --network macvlan1 --ip 172.20.0.11 ubuntu
[root@server2 ~]# docker run -it --name vm2 --network macvlan1 --ip 172.20.0.12 ubuntu
#運行容器,macvlan 模型這裏必須手動指定 ip 地址,如果不指定會自動分配,單調遞增,兩臺主機可能會衝突。

在server1上:
root@1046c09fdcab:/# ping 172.20.0.12
PING 172.20.0.12 (172.20.0.12) 56(84) bytes of data.
64 bytes from 172.20.0.12: icmp_seq=1 ttl=64 time=0.956 ms
64 bytes from 172.20.0.12: icmp_seq=2 ttl=64 time=0.548 ms

在server2上:
root@e22da2aae025:/# ping 172.20.0.11
PING 172.20.0.11 (172.20.0.11) 56(84) bytes of data.
64 bytes from 172.20.0.11: icmp_seq=1 ttl=64 time=0.458 ms
64 bytes from 172.20.0.11: icmp_seq=2 ttl=64 time=0.558 ms


#########兩臺主機就可以互相通信了##########


[root@server1 rpms]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.02422aa432f0	no	

[root@server2 ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242c65fa427	no	

並且兩臺主機的網絡都沒有橋接到docker0上。而是直接佔用了物理網卡。無需 NAT 或端口映射

但是,我們發現這樣就出現了一個問題,我們每次創建一個網絡就需要一塊新的網卡,這樣顯然是不現實的。

解決方法:

macvlan會獨佔網卡,但是可以使用vlan的子接口實現多macvlan網絡,最多可以將物理二層網絡劃分成4094各邏輯網絡,且彼此隔離。

所以:macvlan網絡在物理網絡二層是隔離的,無法直接通信,但是可以在三層上(即容器內部)通過網關將macvlan網絡連通起來。

使用 vlan 子接口實現多 macvlan 網絡

vlan 可以將物理二層網絡劃分爲 4094 個邏輯網絡,彼此隔離,取值爲 1~4094,這樣就極大的提升了網卡的複用性

[root@server1 rpms]# docker network create -d macvlan --subnet 172.21.0.0/24 --gateway 172.21.0.1 -o parent=eth0.1 macvlan2
b908e524d6ae3471366ef0351b7fcfb6d8213fcbd1258d065e6bb7324329a541
[root@server1 rpms]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f905d0cfd038        bridge              bridge              local
5dc66fa4665c        host                host                local
90bee86d976b        macvlan1            macvlan             local
b908e524d6ae        macvlan2            macvlan             local
304f37a81f85        none                null                local


[root@server2 ~]# docker network create -d macvlan --subnet 172.21.0.0/24 --gateway 172.21.0.1 -o parent=eth0.1 macvlan2
6731f6bfad762ebe68028166a566a59102d6a4a34017c00408fa4aa5a0a7da70
[root@server2 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
353e8449c00f        bridge              bridge              local
0c145a0ac5db        host                host                local
499d58aa9c96        macvlan1            macvlan             local
6731f6bfad76        macvlan2            macvlan             local
7369a58f2403        none                null                local

server1和server2:
6: eth0.1@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 00:0c:29:05:08:07 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::20c:29ff:fe05:807/64 scope link 
       valid_lft forever preferred_lft forever

[root@server1 ~]# docker run -it --name vm3 --network macvlan2 --ip 172.21.0.11 ubuntu
[root@server2 ~]# docker run -it --name vm4 --network macvlan2 --ip 172.21.0.12 ubuntu

在這裏插入圖片描述
在這裏插入圖片描述
同一個macvlan的容器纔可以互相通信

注意:macvlan 網絡在二層是隔離的,所以不同 macvlan 容器不能通信,可以在三層通過網關連接(加路由),docker 本身不做任何限制,像傳統 vlan 那樣管理即可。網絡選型時如果對網絡比較熟悉,選 macvlan較好,因爲只需要把網絡設備調整好,docker 方面基本不用做什麼調整。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章