前言
單機(jī)模式下,我們可以使用 Docker Compose 來(lái)編排多個(gè)服務(wù)郭变,而在 上一篇文章 中介紹的 Docker Swarm 只能實(shí)現(xiàn)對(duì)單個(gè)服務(wù)的簡(jiǎn)單部署。于是就引出了本文的主角 Docker Stack 蓖救,通過(guò) Docker Stack 我們只需對(duì)已有的 docker-compose.yml 配置文件稍加改造就可以完成 Docker 集群環(huán)境下的多服務(wù)編排瑞躺。
正文
-
首先創(chuàng)建一個(gè) docker-compose.yml 文件,使用 Docker Compose v3 語(yǔ)法
內(nèi)容比較簡(jiǎn)單莺禁,一個(gè)有四個(gè)實(shí)例的 nginx 服務(wù)留量,兩個(gè)只部署在 manager 節(jié)點(diǎn)上的單實(shí)例監(jiān)控工具服務(wù):portainer 和 visualizer
version: "3"
services:
nginx:
image: nginx:alpine
ports:
- 80:80
deploy:
mode: replicated
replicas: 4
visualizer:
image: dockersamples/visualizer
ports:
- "9001:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
replicas: 1
placement:
constraints: [node.role == manager]
portainer:
image: portainer/portainer
ports:
- "9000:9000"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
replicas: 1
placement:
constraints: [node.role == manager]
- 部署服務(wù)
$ docker stack deploy -c docker-compose.yml stack-demo
- 部署成功之后查看詳情
$ docker stack services stack-demo
ID NAME MODE REPLICAS IMAGE PORTS
4yb35ywqvo49 stack-demo_portainer replicated 1/1 portainer/portainer:latest *:9000->9000/tcp
mzd2volqug28 stack-demo_nginx replicated 4/4 nginx:alpine *:80->80/tcp
r0zlzpp3wujg stack-demo_visualizer replicated 1/1 dockersamples/visualizer:latest *:9001->8080/tcp
- 在瀏覽器中訪(fǎng)問(wèn)監(jiān)控工具,對(duì)應(yīng)端口如下:
portainer ——→ ip:9000
visualizer ——→ ip:9001
注意:如果有多個(gè) manager 節(jié)點(diǎn)哟冬,portainer 和 visualizer 可能分別部署在兩臺(tái)機(jī)器上楼熄,所以ip可能會(huì)不一樣。
- 修改 docker-compose.yml 文件后重新部署即可完成對(duì)修改內(nèi)容的更新
$ docker stack deploy -c docker-compose.yml stack-demo
關(guān)于負(fù)載均衡
評(píng)論區(qū)有小伙伴提到浩峡,容器間通過(guò)服務(wù)名 ( 比如文中的 nginx ) 通訊時(shí)可岂,對(duì)應(yīng)的 IP 卻和容器的實(shí)際 IP 對(duì)不上。出現(xiàn)這個(gè)情況是因?yàn)樨?fù)載均衡( 對(duì)外表現(xiàn)為一個(gè)服務(wù)翰灾,內(nèi)部為多個(gè)服務(wù) )缕粹。下面是我做的試驗(yàn),希望能幫助大家理解纸淮。
按上面的配置啟動(dòng)集群 ( 由兩臺(tái)服務(wù)器構(gòu)成 )
-
在 manager 節(jié)點(diǎn)服務(wù)器中看下運(yùn)行的服務(wù)
$ docker ps CONTAINER ID IMAGE NAMES 9b96f07bbb91 dockersamples/visualizer:latest stack-demo_visualizer.1.p5hy7gsc50vbm0wkxm1c17rl6 942dd34d024e nginx:alpine stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz 706ae42e0089 nginx:alpine stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk 6dba55dd7d63 portainer/portainer:latest stack-demo_portainer.1.yv76gf0i7gou2awen44kshm1j
-
在這臺(tái)服務(wù)器上啟動(dòng)了兩個(gè) nginx 容器實(shí)例平斩,隨便進(jìn)一個(gè)實(shí)例看下 IP
$ docker exec -it stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk ifconfig eth0 Link encap:Ethernet HWaddr 02:42:0A:FF:00:3E inet addr:10.255.0.62 Bcast:10.255.255.255 Mask:255.255.0.0 eth1 Link encap:Ethernet HWaddr 02:42:0A:00:06:07 inet addr:10.0.6.7 Bcast:10.0.6.255 Mask:255.255.255.0 eth2 Link encap:Ethernet HWaddr 02:42:AC:13:00:04 inet addr:172.19.0.4 Bcast:172.19.255.255 Mask:255.255.0.0 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0
發(fā)現(xiàn)容器中綁了3個(gè)網(wǎng)卡 eth0 、eth1 咽块、eth2 绘面,我猜想分別對(duì)應(yīng) 整個(gè) Swarm 集群的局域網(wǎng)、當(dāng)前 Stack 集群的局域網(wǎng) 侈沪、當(dāng)前主機(jī)下 Compose 服務(wù)的局域網(wǎng) 三個(gè)網(wǎng)絡(luò)揭璃。
-
查看當(dāng)前主機(jī)下的 docker 網(wǎng)絡(luò)
$ docker network ls NETWORK ID NAME DRIVER SCOPE bd4fa8219483 bridge bridge local e51735fef0d6 docker_gwbridge bridge local 26360437865a host host local yvupj4ex3odl ingress overlay swarm f0a0190c3b1f none null local oft930l7jpdn stack-demo_default overlay swarm
-
上一步看到有兩個(gè) swarm 的網(wǎng)絡(luò),進(jìn)去看下具體信息
$ docker network inspect ingress "IPAM": { "Config": [ { "Subnet": "10.255.0.0/16", "Gateway": "10.255.0.1" } ] }, "Containers": { "6dba55dd7d63f7166e2e0ee3afed8e427089b7140d62f39a835d3145a058b868": { "Name": "stack-demo_portainer.1.yv76gf0i7gou2awen44kshm1j", "IPv4Address": "10.255.0.59/16", }, "706ae42e00890444087aa6d51ccb966b76b5ad4c985b48fdf5215c192bcf0836": { "Name": "stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk", "IPv4Address": "10.255.0.62/16", }, "942dd34d024e218aad4e5034e1194a2cfa1d9be81a839ec86403cf237d41368b": { "Name": "stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz", "IPv4Address": "10.255.0.64/16", }, "9b96f07bbb91a570bb8d26945996d77151c5633c0a6057361ab4474b393da364": { "Name": "stack-demo_visualizer.1.p5hy7gsc50vbm0wkxm1c17rl6", "IPv4Address": "10.255.0.66/16", }, "ingress-sbox": { "Name": "ingress-endpoint", "IPv4Address": "10.255.0.2/16", } }
內(nèi)容太多就省略其他無(wú)關(guān)內(nèi)容了亭罪,從上面的信息已經(jīng)可以證明第三步的猜想了 ( ingress 對(duì)應(yīng) Swarm 集群 , stack-demo_default 對(duì)應(yīng) Stack 集群 ) 瘦馍,要進(jìn)一步確認(rèn)可以再看下另一臺(tái)服務(wù)器上的網(wǎng)絡(luò)。
-
通過(guò)容器 nginx.4 使用服務(wù)名的方式 ping 一下 nginx
$ docker exec -it stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz ping nginx PING nginx (10.0.6.5): 56 data bytes 64 bytes from 10.0.6.5: seq=0 ttl=64 time=0.121 ms
發(fā)現(xiàn) IP 是 10.0.6.5 皆撩,屬于 stack-demo_default 網(wǎng)絡(luò)扣墩,但是在兩臺(tái)服務(wù)器的 docker 網(wǎng)絡(luò)詳情里面都找不到這個(gè)實(shí)例哲银。
-
在容器 nginx.4 中安裝 curl 然后再訪(fǎng)問(wèn) nginx 看下效果
$ docker exec -it stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz sh -c 'echo -e "https://mirrors.ustc.edu.cn/alpine/latest-stable/main\nhttps://mirrors.ustc.edu.cn/alpine/latest-stable/community" > /etc/apk/repositories && apk --update add curl' $ docker exec -it stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz curl nginx
可以看到訪(fǎng)問(wèn)成功扛吞,再多調(diào)用幾次。
-
打印 nginx 容器的日志 ( 可以多開(kāi)幾個(gè)終端打印日志荆责,再訪(fǎng)問(wèn) nginx 看下實(shí)時(shí)日志的效果滥比,這樣更直觀 )
$ docker logs stack-demo_nginx.2.vnlmlky5m5qy7l8qxq6k5nllk && echo "---分界線(xiàn)---" && docker logs stack-demo_nginx.4.tp6u05jmg9iuookqc9i9e11kz 10.0.6.4 - - [06/Dec/2018:10:15:18 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0" "-" ---分界線(xiàn)--- 10.0.6.4 - - [06/Dec/2018:10:13:16 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0" "-" 10.0.6.4 - - [06/Dec/2018:10:15:19 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.60.0" "-"
可以看到明顯的負(fù)載均衡的效果,請(qǐng)求都來(lái)自 10.0.6.4做院,它就是 stack-demo_default 網(wǎng)絡(luò)中一個(gè)名為
lb-
開(kāi)頭的實(shí)例盲泛,它就是這個(gè)負(fù)載均衡的入口濒持。"lb-stack-demo_default": { "Name": "stack-demo_default-endpoint", "IPv4Address": "10.0.6.4/24", }
-
再去另一臺(tái)服務(wù)器看下 nginx 的日志
發(fā)現(xiàn)并沒(méi)有訪(fǎng)問(wèn)記錄,說(shuō)明這個(gè)負(fù)載均衡僅限于 當(dāng)前服務(wù)器 寺滚、相同服務(wù) 的 多個(gè)實(shí)例柑营,不會(huì)跨服務(wù)器負(fù)載均衡。
-
在另一臺(tái)服務(wù)器上再重復(fù) 7 & 8 兩個(gè)步驟
發(fā)現(xiàn)另一臺(tái)服務(wù)器上不存在名為
lb-
開(kāi)頭的實(shí)例村视,而負(fù)載均衡的入口是其中一個(gè)普通的 nginx 實(shí)例官套。
總結(jié)下:
整個(gè)請(qǐng)求的調(diào)用流程應(yīng)該就是:通過(guò)服務(wù)名 nginx 訪(fǎng)問(wèn) -- 指向 --> stack 集群網(wǎng)關(guān) ( 10.0.6.5 ) -- 轉(zhuǎn)發(fā) --> stack 集群中,位于當(dāng)前服務(wù)器的負(fù)載均衡實(shí)例 ( 10.0.6.4 ) -- 分發(fā) --> 最終的應(yīng)用 蚁孔。
相關(guān)命令
命令 | 描述 |
---|---|
docker stack deploy | 部署新的堆椖膛猓或更新現(xiàn)有堆棧 |
docker stack ls | 列出現(xiàn)有堆棧 |
docker stack ps | 列出堆棧中的任務(wù) |
docker stack rm | 刪除一個(gè)或多個(gè)堆棧 |
docker stack services | 列出堆棧中的服務(wù) |