Docker Swarm系列——7.Swarm服務呼叫
在這篇文章中,大家將會了解在Swarm中,服務與服務之間如何互相呼叫。通過前面幾篇文章的學習,我們已經能夠熟練地部署服務,並在瀏覽器中成功訪問。但是,我們一直以來部署的都是單個服務,還沒接觸到例如,在
web
中呼叫api
,在api
中呼叫mysql
,接下來,我們就從網路開始,一探究竟。
1. 網路名稱
還記得我們最開始通過docker network create -d overlay --attachable httpnet
建立的httpnet
網路嗎?這一步究竟做了什麼?如果不清楚,docker教給我們一個方法inspect
:
$ docker network inspect httpnet [ ... { "Name": "httpnet", "IPAM": { "Config": [ { "Subnet": "10.0.1.0/24", "Gateway": "10.0.1.1" } ] }, ... } ]
我們只截取了對網路httpnet
分析最重要的一部分,仔細看一下,我們會發現如下新的資訊:
Subnet
子網,凡是註冊到此網路上的服務或容器,docker都會從10.0.1.0/24
中自動分配一個或多個內部IP給它。Gateway
閘道器,httpnet
網路的閘道器是10.0.1.1
預設在同一個子網(內網),任何IP
都可以ping
通,任何PORT
都對外開放,這就是本質上容器間或服務間互相訪問呼叫的方式。
2. 服務名稱
我們已經知道,本質上容器間或服務間都是通過ip:port
的形式進行訪問或呼叫,但是我們同時也清楚,容器的生命週期始於建立終於銷燬,且容器的啟停很頻繁,那就意味著一個服務中容器的真實IP隨時都可能改變。
因此,docker提供給我們的方式,通過命令的編寫就能看出來,那就是名稱,包括網路名稱、stack名稱、服務名稱、容器名稱等。那讓我們看看,服務名稱背後又是什麼玄機?
$ docker service inspect http-v1 [ ... "Spec": { "Name": "http-v1", "Networks": [ { "Target": "httpnet" } ], "Replicated": { "Replicas": 2 } } "Endpoint": { "Spec": { "Mode": "vip", "Ports": [ { "Protocol": "tcp", "TargetPort": 80, "PublishedPort": 80, "PublishMode": "ingress" } ] }, "VirtualIPs": [ { "NetworkID": "m8hsd6mdesxey1m0sm6ipjxrt", "Addr": "10.0.1.7/24" } ] ... } ]
我們只截取了對服務http-v1
分析最重要的一部分,仔細看一下,我們會發現如下新的資訊:
Mode
機制,vip
代表對服務中所有容器的代理,不是直接訪問,而是通過vip
地址。Addr
地址,vip
的地址為10.0.1.7
,它代表服務的地址,但不是真實的容器地址。
我們可以任意進入一個容器裡面看看:
$ docker exec -it http-v1.2.7xp9liu4tn21hzogtqhyswk5n /bin/sh
# traceroute http-v1
traceroute to http-v1 (10.0.1.7), 30 hops max, 46 byte packets
1 10.0.1.7 (10.0.1.7) 0.029 ms 0.672 ms 0.024 ms
# curl http-v1
{"version":"v1","hostname":"6e54dd2e8007","address":"10.0.1.9"}/app
# curl http-v1
{"version":"v1","hostname":"4d51a5226238","address":"10.0.1.8"}/app
# curl 10.0.1.7
{"version":"v1","hostname":"6e54dd2e8007","address":"10.0.1.9"}/app
# curl 10.0.1.7
{"version":"v1","hostname":"4d51a5226238","address":"10.0.1.8"}/app
graph LR
A(curl http-v1)-->|dns, vip|B(10.0.1.7)
B(10.0.1.7)-->|輪詢|C(10.0.1.8, 10.0.1.9)
不難看出,一個服務永遠只對應一個VIP
,而VIP
通過輪詢每次返回一個真實的容器IP
,且VIP
負責維護真實容器的所有IP
(建立、銷燬)。
graph LR
A(curl 172.16.0.15)-->|iptables, ipvs|B(10.0.1.7)
B(10.0.1.7)-->|輪詢|C(10.0.1.8, 10.0.1.9)
此外,如果一個服務對外暴露了埠,也可以通過外部ip:port
的方式進行呼叫。但是這種方式不僅捨近求遠,還增加了IP地址轉換的效能損耗,而且因為叢集中每個節點的ip:port
都可以訪問,那該選擇一個固定的還是每次從所有的節點中隨機?如果一個節點不可用又怎麼辦?
至此,我們終於弄明白了在【2.Swarm服務發現】文章中未深入介紹的服務發現和負載均衡原理,同時,如果在一個服務中想要呼叫另外一個服務,只需要在連線字串中加入另外一個服務的名稱和埠即可。