Docker Swarm之RoutingMesh


一、集群之間的網絡

  之前有搭建過wordpress應用,其中wordpress運行在manager節點上,mysql服務運行在worker節點上,它們之間的運行時都制定了對應的網絡overlay,但是當時只是在manager節點上創建了這個overlay網絡,worker節點上並沒有創建,但是當Swarm集群的manager節點啟動了mysql服務並且運行在worker節點上后,worker節點上竟然也有了這個overlay網絡,這是為什么呢?

  這就涉及到了Swarm的網絡RoutingMesh,它有兩種體現的方式分別是:Internal和Ingress,其中Internal的通信通過overlay網絡;Ingress是如果服務有綁定接口,則此服務可以通過任意Swarm節點的相應接口進行訪問。

二、 Internal

1、創建overlay網絡

首先先在Swarm的集群中創建一個overlay的network:

[root@centos-7 ~]# docker network create -d overlay demo

然后查看:

[root@centos-7 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
...
xcjljjqcw26b        demo                overlay             swarm
...

2、啟動服務

在這個manager節點上利用demo這個網絡啟動一個服務

[root@centos-7 ~]# docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami
g0vvgklakfoqsjvy0fd1zefjo
[root@centos-7 ~]# docker service ls
ID                  NAME                MODE                REPLICAS       IMAGE                   PORTS
g0vvgklakfoq        whoami              replicated          0/1           jwilder/whoami:latest   *:8000->8000/tcp
[root@centos-7 ~]# docker service ps whoami
ID                  NAME                IMAGE                   NODE      DESIRED STATE       CURRENT STATE     ERROR     PORTS
pk15budjscr7        whoami.1            jwilder/whoami:latest   centos-7  Running             Preparing about a minute ago                       

當我們啟動這個服務后,可以嘗試去訪問它:

[root@centos-7 ~]# curl 127.0.0.1:8000
I'm 9842878ab31b

另外,我們再開啟一個服務:

[root@centos-7 ~]# docker service create --name test -d --network demo busybox /bin/sh -c "while true;do slepp 3600;done"

注意,此時我們這個服務是在worker節點節點上運行的。

[root@centos-7 ~]# docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                   PORTS
rqdbc7dtdh77        test                replicated          1/1                 busybox:latest          
g0vvgklakfoq        whoami              replicated          1/1                 jwilder/whoami:latest   *:8000->8000/tcp
[root@centos-7 ~]# docker service ps test
ID                  NAME                IMAGE               NODE                    DESIRED STATE       CURRENT STATE     ERROR  PORTS
0wqwt54vbiue        test.1              busybox:latest      localhost.localdomain   Running             Running 3 minutes ago    

3、不同節點上服務之間的通信

 如果此時進入到worker節點的test服務容器中,去和manager節點上whoami服務的容器通信們是否可行呢?

  • 進入test服務的容器中
[root@localhost _data]# docker exec -it d161e7c46a8c /bin/sh
/ # ping whoami
PING whoami (10.0.1.33): 56 data bytes
64 bytes from 10.0.1.33: seq=0 ttl=64 time=33.921 ms
64 bytes from 10.0.1.33: seq=1 ttl=64 time=0.088 ms

可以看到,這是可行的,並且返回的地址是10.0.1.33,這是不是就說明了manager節點服務容器的ip是這個呢?我們查看一下。

  • 進入whoami服務容器中
[root@centos-7 ~]# docker exec -it 9842878ab31b  /bin/sh
/app # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
266: eth1@if267: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:00:15 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.21/24 brd 10.0.0.255 scope global eth1
       valid_lft forever preferred_lft forever
268: eth2@if269: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    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 eth2
       valid_lft forever preferred_lft forever
270: eth0@if271: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:01:22 brd ff:ff:ff:ff:ff:ff
    inet 10.0.1.34/24 brd 10.0.1.255 scope global eth0
       valid_lft forever preferred_lft forever

  顯然這里面並沒有10.0.1.33,這是怎么回事呢?我們知道scale參數可以將容器水平擴展,不同的容器都有一個ip,為了保證這些服務的ip不變,這里使用了虛擬的ip,這個ip地址是不會改變的,比如現在利用scale多創建幾個whoami服務的容器,然后再進行通信。

  • 創建多個whoami服務的容器
[root@centos-7 ~]# docker service scale whoami=3
whoami scaled to 3
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged 
  • 再次測試

再在worker節點的test服務容器中進行測試:

[root@localhost ~]# docker exec -it 638b  /bin/sh
/ # ping whoami
PING whoami (10.0.1.33): 56 data bytes
64 bytes from 10.0.1.33: seq=0 ttl=64 time=49.712 ms
64 bytes from 10.0.1.33: seq=1 ttl=64 time=0.072 ms
64 bytes from 10.0.1.33: seq=2 ttl=64 time=0.072 ms

可以看到雖然whoami服務已經啟動了3個容器,但是這個虛擬的ip還是沒有變化,那么怎么查看這個虛擬ip對應的真實ip呢?可以通過以下命令查看:

[root@localhost ~]# docker exec -it 638b  /bin/sh
/ # nslookup whoami
Server:        127.0.0.11
Address:    127.0.0.11:53
/ # nslookup tasks.whoami

我們也可以這樣去驗證,只需要在本地上去訪問這個服務,看它返回的主機信息:

[root@localhost ~]# curl 127.0.0.1:8000
I'm 6f5862805bcf
[root@localhost ~]# curl 127.0.0.1:8000
I'm d274e2b20fd8
[root@localhost ~]# curl 127.0.0.1:8000
I'm 9842878ab31b
[root@localhost ~]# curl 127.0.0.1:8000
I'm 6f5862805bcf

這就是借助overlay網絡實現的Swarm集群容器之間通信的模式。

4、總結

   兩個服務whoami和test之間是建立了虛擬的ip進行聯系,但是一個虛擬的ip可能就對應一個服務中多個容器的ip,它們之間是通過lvs(Linux Virtual Server)技術來實現的,從而達到負載均衡的效果。  

三、Ingress 

1、什么是Ingress?

在Swarm集群中可能同一個service部署在不同的節點上,那么如果Swarm中有的節點沒有 這個service,是否這個節點就不能訪問這個服務呢?

現在先啟動兩個服務:

[root@centos-7 ~]# docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami
n9i8qe8obf5ke73ptbuejl49o
[root@centos-7 ~]# docker service scale whoami=2
whoami scaled to 2
overall progress: 2 out of 2 tasks 
1/2: running   [==================================================>] 
2/2: running   [==================================================>] 
verify: Service converged 

再看看這兩個啟動在節點上:

[root@centos-7 ~]# docker service ls
ID                  NAME                MODE                REPLICAS     IMAGE                   PORTS
n9i8qe8obf5k        whoami              replicated          2/2         jwilder/whoami:latest   *:8000->8000/tcp
[root@centos-7 ~]# docker service ps whoami
ID                  NAME                IMAGE                   NODE     DESIRED STATE  CURRENT STATE   ERROR    PORTS
jb4sodzzwoke        whoami.1            jwilder/whoami:latest   centos-7    Running      Running 49 seconds ago                       
ajnie812nqsg     whoami.2      jwilder/whoami:latest   localhost.localdomain   Running      Running 20 seconds ago                       

可以看到兩個服務啟動在不同的節點上,一個在manager節點(centos-7),一個在worker節點(localhost.localdomain),我們現在manager節點上訪問:

[root@centos-7 ~]# curl 127.0.0.1:8000
I'm ae433c63efaf
[root@centos-7 ~]# curl 127.0.0.1:8000
I'm d20d6ad9f7ae

可以看到manager節點上竟然兩個都能訪問,不是另一個部署在worker節點上了嗎?那么再去worker節點上測試:

[root@localhost ~]# curl 127.0.0.1:8000
I'm ae433c63efaf
[root@localhost ~]# curl 127.0.0.1:8000
I'm d20d6ad9f7ae

竟然也是一樣的,這就是Swarm中的Ingress網絡,它可以將服務端口暴露在Swarm中的各個節點上。

2、Ingress的實現

  • 轉發規則

我們可以看看worker節點上沒有存在的服務它是怎么訪問的,如果訪問它內部是怎么轉發的。

[root@localhost ~]# iptables -nL -t nat
...
Chain DOCKER-INGRESS (2 references)
target     prot opt source               destination         
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8000 to:172.20.0.2:8000
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
...

我們可以看到如果不存在的就會轉發到172.20.0.2::8000這個這個地址上去,那么我們看看它自己的ip:

[root@localhost ~]# ip a
...
12: docker_gwbridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ab:b2:f4:f0 brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.1/16 brd 172.20.255.255 scope global docker_gwbridge
       valid_lft forever preferred_lft forever
    inet6 fe80::42:abff:feb2:f4f0/64 scope link 
       valid_lft forever preferred_lft forever
...

我們沒有找到那個地址,但是找到了docker_gwbridge,可以看到兩個ip處於同一段,那么172.20.0.2應該也連接上docker_gwbridge:

[root@localhost ~]# brctl show
bridge name    bridge id        STP enabled    interfaces
br-2d6d1e198a6c        8000.0242deeae757    no        
br-8abcc5cd875c        8000.02424eb653eb    no        
docker0        8000.02424a3fbec6    no        
docker_gwbridge 8000.0242abb2f4f0 no 
                          veth1b22ec2                       veth6839368
virbr0
8000.525400dec34c yes virbr0-nic

可以看到它有兩個interface,但是哪一個才是 172.20.0.0使用的呢?那么我們現在可以從這個網絡連接的容器着手。

[root@localhost ~]# docker network inspect docker_gwbridge
[
...
 "Containers": {
            "ae433c63efafd9376ff82699d127563e780ae73caebcb604c3b0966000236e79": {
                "Name": "gateway_fe0a7f060fb9",
                "EndpointID": "6eddc5ac0721d319e11eb475c3f937ccf78713ed56f89fef563c13333d2526b4",
                "MacAddress": "02:42:ac:14:00:03",
                "IPv4Address": "172.20.0.3/16",
                "IPv6Address": ""
            },
            "ingress-sbox": {
                "Name": "gateway_ingress-sbox",
                "EndpointID": "08639c027efb5c9e51aaf742587c9ae944d1d82275f92ef4f2d1f77965194656",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            }
        }
...
]

可以看到它有兩個容器,其中ingress-sbox容器的ip就是我們需要尋找的。它是什么呢?它是一個Network Namespace,那么也就是請求本轉發到這里面來了。

  • 進入ingress-sbox

我們可以先查看docker中所有的Network Namespace:

[root@localhost ~]# ls /var/run/docker/netns
1-lg0vf65qxp  1-xcjljjqcw2  fe0a7f060fb9  ingress_sbox  lb_xcjljjqcw

然后通過下面的命令進入:

[root@localhost ~]# nsenter --net=/var/run/docker/netns/ingress_sbox

查看ip:

[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP 
    link/ether 02:42:0a:00:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.0.3/24 brd 10.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.0.0.26/32 brd 10.0.0.26 scope global eth0
       valid_lft forever preferred_lft forever
13: eth1@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 172.20.0.2/16 brd 172.20.255.255 scope global eth1
       valid_lft forever preferred_lft forever

這個名稱空間中的ip就是我們要找的。

當被轉發到這個名稱空間后它又是怎么做的呢?我們先看看它的轉發規則:

root@localhost ~]# iptables -nL -t mangle
Chain PREROUTING (policy ACCEPT)
target prot opt source destination MARK tcp --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8000 MARK set 0x10b

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
MARK       all  --  0.0.0.0/0            10.0.0.26            MARK set 0x10b

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination   

可以看到紅色的部分,當轉發8000端口時MARK set 0x10b,接下來執行如下的命令:

[root@localhost ~]# ipvsadm -l

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
FWM  271 rr
  -> 10.0.0.27:0                  Masq    1      0          0         

  -> 10.0.0.28:0                  Masq    1      0          0   

  實際上在這個名稱空間中也是講這個端口進行了轉發,轉發到了上面紅色字體的地址和8000端口,那這兩個地址是什么呢?其實就是Swarm中的所有節點的8000端口,這也就是Ingress的作用了。

3、總結

   當我們訪問訪問本地8000端口時,只要我們這個節點處於Swarm集群中,不管服務部署到那個節點都能訪問,只要端口相同即可。我們本地的請求會被轉發到Ingress_sbox這個Network Namespace中,在這個名稱空間中再通過lvs轉發到具體服務容器的ip和8000端口中去。

 


免責聲明!

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



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