Docker容器跨主機通信之:直接路由方式


一、Docker網絡基本原理

直觀上看,要實現網絡通信,機器需要至少一個網絡接口(物理接口或虛擬接口)與外界相通,並可以收發數據包;此外,如果不同子網之間要進行通信,需要額外的路由機制。

 

Docker中的網絡接口默認都是虛擬的接口。虛擬接口的最大優勢就是轉發效率極高。這是因為Linux通過在內核中進行數據復制來實現虛擬接口之間的數據轉發,即發送接口的發送緩存中的數據包將被直接復制到接收接口的接收緩存中,而無需通過外部物理網絡設備進行交換。對於本地系統和容器內系統來看,虛擬接口跟一個正常的以太網卡相比並無區別,只是它速度要快得多。

 

Docker容器網絡就很好地利用了Linux虛擬網絡技術,在本地主機和容器內分別創建一個虛擬接口,並讓它們彼此連通(這樣的一對接口叫做veth pair)

一般情況下,Docker創建一個容器的時候,會具體執行如下操作:

1.創建一對虛擬接口,分別放到本地主機和新容器的命名空間中;

2.本地主機一端的虛擬接口連接到默認的docker0網橋或指定網橋上,並具有一個以veth開頭的唯一名字,如veth1234;

3.容器一端的虛擬接口將放到新創建的容器中,並修改名字作為eth0。這個接口只在容器的命名空間可見;

4.從網橋可用地址段中獲取一個空閑地址分配給容器的eth0(例如172.17.0.2/16),並配置默認路由網關為docker0網卡的內部接口docker0的IP地址(例如172.17.42.1/16)。

完成這些之后,容器就可以使用它所能看到的eth0虛擬網卡來連接其他容器和訪問外部網絡。用戶也可以通過docker network命令來手動管理網絡。

 

二、Docker網絡默認模式

按docker官方的說法,docker容器的網絡有五種模式:

1)bridge模式,--net=bridge(默認)
這是dokcer網絡的默認設置,為容器創建獨立的網絡命名空間,容器具有獨立的網卡等所有單獨的網絡棧,是最常用的使用方式。
在docker run啟動容器的時候,如果不加--net參數,就默認采用這種網絡模式。安裝完docker,系統會自動添加一個供docker使用的網橋docker0,我們創建一個新的容器時,
容器通過DHCP獲取一個與docker0同網段的IP地址,並默認連接到docker0網橋,以此實現容器與宿主機的網絡互通。
 
2)host模式,--net=host
這個模式下創建出來的容器,直接使用容器宿主機的網絡命名空間。
將不擁有自己獨立的Network Namespace,即沒有獨立的網絡環境。它使用宿主機的ip和端口。
 
3)none模式,--net=none
為容器創建獨立網絡命名空間,但不為它做任何網絡配置,容器中只有lo,用戶可以在此基礎上,對容器網絡做任意定制。
這個模式下,dokcer不為容器進行任何網絡配置。需要我們自己為容器添加網卡,配置IP。
因此,若想使用pipework配置docker容器的ip地址,必須要在none模式下才可以。
 
4)其他容器模式(即container模式),--net=container:NAME_or_ID
與host模式類似,只是容器將與指定的容器共享網絡命名空間。
這個模式就是指定一個已有的容器,共享該容器的IP和端口。除了網絡方面兩個容器共享,其他的如文件系統,進程等還是隔離開的。
 
5)用戶自定義:docker 1.9版本以后新增的特性,允許容器使用第三方的網絡實現或者創建單獨的bridge網絡,提供網絡隔離能力。
View Code

 

bridge模式

bridge模式是docker默認的,也是開發者最常使用的網絡模式。在這種模式下,docker為容器創建獨立的網絡棧,保證容器內的進程使用獨立的網絡環境,
實現容器之間、容器與宿主機之間的網絡棧隔離。同時,通過宿主機上的docker0網橋,容器可以與宿主機乃至外界進行網絡通信。
其網絡模型可以參考下圖:

 

 

從上面的網絡模型可以看出,容器從原理上是可以與宿主機乃至外界的其他機器通信的。同一宿主機上,容器之間都是連接掉docker0這個網橋上的,它可以作為虛擬交換機使容器可以相互通信。
然而,由於宿主機的IP地址與容器veth pair的 IP地址均不在同一個網段,故僅僅依靠veth pair和namespace的技術,還不足以使宿主機以外的網絡主動發現容器的存在。為了使外界可以方位容器中的進程,docker采用了端口綁定的方式,也就是通過iptables的NAT,將宿主機上的端口
端口流量轉發到容器內的端口上。

舉一個簡單的例子,使用下面的命令創建容器,並將宿主機的3306端口綁定到容器的3306端口:
docker run -tid --name db -p 3306:3306 MySQL
 
在宿主機上,可以通過iptables -t nat -L -n,查到一條DNAT規則:
 
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.5:3306
 
上面的172.17.0.5即為bridge模式下,創建的容器IP。
 
很明顯,bridge模式的容器與外界通信時,必定會占用宿主機上的端口,從而與宿主機競爭端口資源,對宿主機端口的管理會是一個比較大的問題。同時,由於容器與外界通信是基於三層上iptables NAT,性能和效率上的損耗是可以預見的。
View Code

 

三、方案介紹

概述

就目前Docker自身默認的網絡來說,單台主機上的不同Docker容器可以借助docker0網橋直接通信,這沒毛病,而不同主機上的Docker容器之間只能通過在主機上用映射端口的方法來進行通信,有時這種方式會很不方便,甚至達不到我們的要求,因此位於不同物理機上的Docker容器之間直接使用本身的IP地址進行通信很有必要。再者說,如果將Docker容器起在不同的物理主機上,我們不可避免的會遭遇到Docker容器的跨主機通信問題。本文就來嘗試一下。

情景構造

如下圖所示,我們有兩個物理主機1和主機2,我們在各自宿主機上啟動一個centos容器,啟動成功之后,兩個容器分別運行在兩個宿主機之上,默認的IP地址分配如圖所示,這也是Docker自身默認的網絡。

 

 

此時兩台主機上的Docker容器如何直接通過IP地址進行通信?

一種直接想到的方案便是通過分別在各自主機中 添加路由 來實現兩個centos容器之間的直接通信。我們來試試吧

 

方案原理分析

由於使用容器的IP進行路由,就需要避免不同主機上的容器使用了相同的IP,為此我們應該為不同的主機分配不同的子網來保證。於是我們構造一下兩個容器之間通信的路由方案,如下圖所示。

 

 

 

各項配置如下:

  • 主機1的IP地址為:192.168.91.128
  • 主機2的IP地址為:192.168.91.129
  • 為主機1上的Docker容器分配的子網:10.0.128.0/24
  • 為主機2上的Docker容器分配的子網:10.0.129.0/24

這樣配置之后,兩個主機上的Docker容器就肯定不會使用相同的IP地址從而避免了IP沖突。

我們接下來 定義兩條路由規則 即可:

  • 所有目的地址為10.0.128.0/24的包都被轉發到主機1上
  • 所有目的地址為10.0.129.0/24的包都被轉發到主機2上

綜上所述,數據包在兩個容器間的傳遞過程如下:

  • 從container1 發往 container2 的數據包,首先發往container1的“網關”docker0,然后通過查找主機1的路由得知需要將數據包發給主機2,數據包到達主機2后再轉發給主機2的docker0,最后由其將數據包轉到container2中;反向原理相同,不再贅述。

我們心里方案想的是這樣,接下來實踐一下看看是否可行。

 

四、實際試驗

環境介紹

操作系統 服務器地址 Dockerd地址
ubuntu-16.04.5-server-amd64 192.168.91.128 10.0.128.2
ubuntu-16.04.5-server-amd64 192.168.91.129 10.0.129.2

 

 

 

 

請確保已經安裝好了docker,這里是使用以下命令安裝的

apt-get install -y docker.io

 

docker的版本為  17.03.2-ce

 

比如主機1,我需要運行一個docker鏡像,要求它的網段必須是 10.0.128.0/24 ,怎么設置呢?

有3個辦法:

1. 修改docker0的網段

2. 創建一個docker網橋

 

這里為了快速實現,選用第一種方案。直接修改 /etc/default/docker 文件,添加 DOCKER_OPTS 參數即可

修改docker0

分別對主機1和主機2上的docker0進行配置

主機1

編輯主機1上的 /etc/default/docker 文件,最后一行添加

DOCKER_OPTS="--bip 10.0.128.1/24"

 

特別注意,DOCKER_OPTS參數后面必須有引號。--bip后面的ip就是docker0的ip地址,一般從第一個ip開始!

不要修改 /etc/docker/daemon.json 文件添加bip,我測試了一些,重啟docker會報錯!

 

主機2

編輯主機1上的 /etc/default/docker 文件,最后一行添加

DOCKER_OPTS="--bip 10.0.129.1/24"

 

重啟docker服務

主機1和主機2上均執行如下命令重啟docker服務以使修改后的docker0網段生效

systemctl restart docker

 

查看主機1上docker0的ip地址

root@ubuntu:~# ifconfig docker0
docker0   Link encap:Ethernet  HWaddr 02:42:8a:46:e2:eb
          inet addr:10.0.128.1  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  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:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

 

查看主機2上docker0的ip地址

root@ubuntu:~# ifconfig docker0
docker0   Link encap:Ethernet  HWaddr 02:42:22:b1:25:66
          inet addr:10.0.129.1  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  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:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

 

發現默認的網段已經改變了!

 

添加路由規則

主機1

查看路由表

root@ubuntu:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.91.2    0.0.0.0         UG    0      0        0 ens32
10.0.128.0      0.0.0.0         255.255.255.0   U     0      0        0 docker0192.168.91.0    0.0.0.0         255.255.255.0   U     0      0        0 ens32

 

默認只有自己本身的路由,如果需要訪問 10.0.129.0/24 網段,需要添加路由

 

主機1上添加路由規則如下:

route add -net 10.0.129.0/24 gw 192.168.91.129

 

gw 表示下一跳地址,這里的地址就是主機2的ip地址

 

再次查看路由,發現已經添加上了

root@ubuntu:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.91.2    0.0.0.0         UG    0      0        0 ens32
10.0.128.0      0.0.0.0         255.255.255.0   U     0      0        0 docker0
10.0.129.0      192.168.91.129  255.255.255.0   UG    0      0        0 ens32
192.168.91.0    0.0.0.0         255.255.255.0   U     0      0        0 ens32

 

主機2

主機2上添加路由規則如下:

route add -net 10.0.128.0/24 gw 192.168.91.128

 

在主機1上,ping主機2的docker0地址

root@ubuntu:~# ping 10.0.129.1 -c 1
PING 10.0.129.1 (10.0.129.1) 56(84) bytes of data.
64 bytes from 10.0.129.1: icmp_seq=1 ttl=64 time=1.35 ms

--- 10.0.129.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.355/1.355/1.355/0.000 ms

 

在主機2上,ping主機1的docker0地址

root@ubuntu:~# ping 10.0.128.1 -c 1
PING 10.0.128.1 (10.0.128.1) 56(84) bytes of data.
64 bytes from 10.0.128.1: icmp_seq=1 ttl=64 time=1.73 ms

--- 10.0.128.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.732/1.732/1.732/0.000 ms

 

ok,既然docker0都通了,那么起一個docker容器,會不會也是通的的呢?測試一下吧

在主機1上面啟動一個容器,這里選用apline鏡像,它只有4.5M,並且自帶ping命令!

先查看ip地址

root@ubuntu:~# docker run -it alpine
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:80:02
          inet addr:10.0.128.2  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::42:aff:fe00:8002/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1156 (1.1 KiB)  TX bytes:578 (578.0 B)

 

它的ip地址為 10.0.128.2 ,由於docker0占用了第一個ip地址。所以容器啟動時,ip地址從第二個開始分配!

 

在主機2上面啟動一個容器

root@ubuntu:~# docker run -it alpine
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:81:02
          inet addr:10.0.129.2  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::42:aff:fe00:8102/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1016 (1016.0 B)  TX bytes:508 (508.0 B)

 

在主機1上的容器中 ping 主機2中的容器

先來ping 主機2的docker0,再ping 主機2中的容器

/ # ping 10.0.129.1 -c 1
PING 10.0.129.1 (10.0.129.1): 56 data bytes
64 bytes from 10.0.129.1: seq=0 ttl=63 time=0.419 ms

--- 10.0.129.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.419/0.419/0.419 ms
/ # ping 10.0.129.2 -c 1
PING 10.0.129.2 (10.0.129.2): 56 data bytes

--- 10.0.129.2 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss

 

從結果中,可以發現。docker0是通的,但是主機2中的容器是不通的,為什么呢?

Docker Bridge創建創建過程

1)首先宿主機上創建一對虛擬網卡veth pair設備,veth設備總是成對出現的,形成一個通信通道,數據傳輸就是基於這個鏈路的,veth設備常用來連接兩個網絡設備

2)Docker將veth pair設備的一端放在容器中,並命名為eth0,然后將另一端加入docker0網橋中,可以通過brctl show命令查看

3)從docker0字網卡中分配一個IP到給容器使用,並設置docker0的IP地址為容器默認網關

4)此時容器IP與宿主機是可以通信的,宿主機也可以訪問容器中的ip地址,在bridge模式下,連接同一網橋的容器之間可以相互通信,同時容器可以訪問外網,但是其他物理機不能訪問docker容器IP,需要通過NAT將容器的IP的port映射為宿主機的IP和port;

 

在主機1上面,再開一個窗口,使用ifconfig查看

root@ubuntu:~# ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:8a:46:e2:eb
          inet addr:10.0.128.1  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::42:8aff:fe46:e2eb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:11 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:760 (760.0 B)  TX bytes:830 (830.0 B)

ens32     Link encap:Ethernet  HWaddr 00:0c:29:12:ff:d3
          inet addr:192.168.91.128  Bcast:192.168.91.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fe12:ffd3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:689 errors:0 dropped:0 overruns:0 frame:0
          TX packets:552 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:60936 (60.9 KB)  TX bytes:71802 (71.8 KB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:176 errors:0 dropped:0 overruns:0 frame:0
          TX packets:176 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:13296 (13.2 KB)  TX bytes:13296 (13.2 KB)

veth077daec Link encap:Ethernet  HWaddr 7e:ef:1b:5e:b3:11
          inet6 addr: fe80::7cef:1bff:fe5e:b311/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:19 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:928 (928.0 B)  TX bytes:1478 (1.4 KB)
View Code

 

會發現有一個 veth077daec 的網卡設備。咦,這是個啥?

當運行docker容器后,再次執行ifconfig命令可以看到會多出個網卡驅動veth開頭的名字,所以補充下veth。

veth

Linux container 中用到一個叫做veth的東西,這是一種新的設備,專門為 container 所建。veth 從名字上來看是 Virtual ETHernet 的縮寫,它的作用很簡單,就是要把從一個 network namespace 發出的數據包轉發到另一個 namespace。veth 設備是成對的,一個是 container 之中,另一個在 container 之外,即在真實機器上能看到的。
VETH設備總是成對出現,一端請求發送的數據總是從另一端以請求接受的形式出現。創建並配置正確后,向其一端輸入數據,VETH會改變數據的方向並將其送入內核網絡子系統,完成數據的注入,而在另一端則能讀到此數據。(Namespace,其中往veth設備上任意一端上RX到的數據,都會在另一端上以TX的方式發送出去)veth工作在L2數據鏈路層,veth-pair設備在轉發數據包過程中並不串改數據包內容。

成數據的注入,而在另一端則能讀到此數據。(Namespace,其中往veth設備上任意一端上RX到的數據,都會在另一端上以TX的方式發送出去)veth工作在L2數據鏈路層,veth-pair設備在轉發數據包過程中並不串改數據包內容。
顯然,僅有veth-pair設備,容器是無法訪問網絡的。因為容器發出的數據包,實質上直接進入了veth1設備的協議棧里。如果容器需要訪問網絡,需要使用bridge等技術,將veth1接收到的數據包通過某種方式轉發出去 。
veth參考鏈接:http://blog.csdn.net/sld880311/article/details/77650937

因此,如果要多台主機之間的docker通信,需要使用NAT轉換。那么接下來,就是設置iptables規則了!

配置iptables規則

主機1

在主機1上查看默認的nat 規則

root@ubuntu:~# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  anywhere             anywhere             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  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  10.0.128.0/24        anywhere

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

 

這些nat規則,都是docker幫你做的。

增加一條規則

iptables -t nat -I PREROUTING -s 10.0.128.0/24 -d 10.0.129.0/24 -j DNAT --to 10.0.128.1

 

PREROUTING:可以在這里定義進行目的NAT的規則,因為路由器進行路由時只檢查數據包的目的ip地址,所以為了使數據包得以正確路由,我們必須在路由之前就進行目的NAT;

 

上面那一條路由規則是啥意思呢?就是當源地址為10.0.128.0/24網段 訪問 10.0.129.0/24 時,在路由之前,將ip轉換為10.0.128.1。

注意:一定要加-d參數。如果不加,雖然docker之間可以互通,但是不能訪問網站,比如百度,qq之類的!

為什么呢?訪問10.0.129.0/24 時,通過docker0網卡出去的。但是訪問百度,還是通過docker0,就出不去了!

真正連接外網的是ens32網卡,必須通過它才行!因此必須要指定-d參數!

 

這個時候,直接ping 主機2上的docker地址

/ # ping 10.0.129.2 -c 3
PING 10.0.129.2 (10.0.129.2): 56 data bytes
64 bytes from 10.0.129.2: seq=0 ttl=64 time=0.073 ms
64 bytes from 10.0.129.2: seq=1 ttl=64 time=0.143 ms
64 bytes from 10.0.129.2: seq=2 ttl=64 time=0.149 ms

--- 10.0.129.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.073/0.121/0.149 ms

 

是可以通訊的!

注意:iptables必須在 PREROUTING 上面做,而不是常規的 POSTROUTING。我測試在POSTROUTING做規則,始終無法通訊!

 

主機2

主機2上添加如下規則:

iptables -t nat -I PREROUTING -s 10.0.129.0/24 -d 10.0.128.0/24 -j DNAT --to 10.0.129.1

 

測試ping 主機1上的容器地址

/ # ping 10.0.128.2 -c 3
PING 10.0.128.2 (10.0.128.2): 56 data bytes
64 bytes from 10.0.128.2: seq=0 ttl=64 time=0.092 ms
64 bytes from 10.0.128.2: seq=1 ttl=64 time=0.140 ms
64 bytes from 10.0.128.2: seq=2 ttl=64 time=0.141 ms

--- 10.0.128.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.092/0.124/0.141 ms

 

也是可以通訊的!

注意:如果發現還是不通,重啟一下docker服務,應該就可以了!

 

五、3台主機測試

環境介紹

操作系統 服務器地址 Dockerd地址
ubuntu-16.04.5-server-amd64 192.168.91.128 10.0.128.2
ubuntu-16.04.5-server-amd64 192.168.91.129 10.0.129.2
ubuntu-16.04.5-server-amd64 192.168.91.131 10.0.131.2

 

 

 

 

 

拓撲圖

一鍵腳本

上面已經實現了2台docker之間的通信,如果是3台呢?怎么搞?還是一樣的。

只不過每台主機都要增加2條路由規則以及2條iptables規則。

做路由規則時,容器搞混淆,為了避免這種問題,做一個一鍵腳本就可以了!

 

環境要求

1. 每台主機已經安裝好了docker,並且已經啟動

2. 請確保每台主機的 /etc/default/docker 沒有被更改過。還是默認的172.17.0.2/16網段

如果是虛擬機,直接還原快照即可!

 

docker_dr.sh

#!/bin/bash

# 主機ip后綴清單
hosts="128 129 131"

# 循環主機
for i in `echo $hosts`;do
    # 寫入臨時文件
    cat >/tmp/dockerc<<EOF
    DOCKER_OPTS=\"--bip 10.0.$i.1/24\"
EOF
    # 遠程執行命令,更改docker0網段
    ssh 192.168.91.$i "echo $(cat /tmp/dockerc)>> /etc/default/docker"
    # 重啟docker服務
    ssh 192.168.91.$i "systemctl restart docker"
    # 清空nat規則
    # ssh 192.168.91.$i "sudo iptables -t nat -F"

    # 再次循環
    for j in `echo $hosts`;do
        # 排除自身
        if [ "$j" != "$i" ];then
            # 添加路由
            ssh 192.168.91.$i "route add -net 10.0.$j.0/24 gw 192.168.91.$j"
            # 添加nat規則
            ssh 192.168.91.$i "iptables -t nat -I PREROUTING -s 10.0.$i.0/24 -d 10.0.$j.0/24 -j DNAT --to 10.0.$i.1"
        fi
    done
    # 重啟docker服務,寫入默認的nat規則
    ssh 192.168.91.$i "systemctl restart docker"
done

 

ssh免密登錄

在主機1執行以下命令

生成秘鑰,並寫入到authorized_keys

ssh-keygen -t rsa -P "" -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

 

復制公鑰,執行以下3個命令

ssh-copy-id 192.168.91.128
ssh-copy-id 192.168.91.129
ssh-copy-id 192.168.91.131

 

正式執行 docker_dr.sh

bash docker_dr.sh

 執行之后,是沒有啥輸出的

 

3台主機都啟動alpine鏡像

docker run -it alpine

 

在主機1上面,測試訪問另外2個docker地址,並測試上網,效果如下:

/ # ping 10.0.129.2 -c 2
PING 10.0.129.2 (10.0.129.2): 56 data bytes
64 bytes from 10.0.129.2: seq=0 ttl=64 time=0.078 ms
64 bytes from 10.0.129.2: seq=1 ttl=64 time=0.107 ms

--- 10.0.129.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.078/0.092/0.107 ms
/ # ping 10.0.131.2 -c 2
PING 10.0.131.2 (10.0.131.2): 56 data bytes
64 bytes from 10.0.131.2: seq=0 ttl=64 time=0.073 ms
64 bytes from 10.0.131.2: seq=1 ttl=64 time=0.093 ms

--- 10.0.131.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.073/0.083/0.093 ms
/ # ping www.baidu.com -c 2
PING www.baidu.com (61.135.169.121): 56 data bytes
64 bytes from 61.135.169.121: seq=0 ttl=127 time=25.826 ms
64 bytes from 61.135.169.121: seq=1 ttl=127 time=26.172 ms

--- www.baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 25.826/25.999/26.172 ms
/ #

 

 測試成功,大功告成!!!

 

 

本文參考鏈接:

https://www.cnblogs.com/whych/p/9595671.html

http://blog.51cto.com/dengaosky/2067727

https://yq.aliyun.com/articles/602107

https://blog.csdn.net/m0_38080062/article/details/79292058?tdsourcetag=s_pcqq_aiomsg

 


免責聲明!

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



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