上篇博客 寫了如何使用docker-compose來部署服務。雖然docker-compose解決了docker間通信問題,但是缺點也是很明顯的。就是只能在一台宿主機上通信。我們使用docker-compose在宿主機上部署了20+的應用,宿主機配置 16C 32GB RAM。服務全部啟動后,常態內存占用就高達85%。顯然是無法應對突發情況的,因此如果服務比較多,僅僅使用docker-compose是不夠的。因此我們使用docker-swarm來部署服務。
docker-swarm是docker官方推出的docker集群解決方案,相比與k8s更輕量,因此如果服務不多可以采用docker-swarm來部署服務!
1.初始化集群
[root@zhongjianjian03 ~]# docker swarm init

執行該命令的節點,一般會成為master(leader)節點,之后的一些集群操作命令,也都是在master節點執行。這里一定要注意
注意紅線框住的地方,這里給了一個命令,就是其他節點如果要加入集群可以使用這個命令加入。
我這里又找了一台機器,執行了該命令

可以看到當前節點加入到了swarm集群,且作為worker節點。此時
我們可以在master節點查看節點狀態了
使用命令。
[root@zhongjianjian03 ~]# docker node ls

可以看到目前集群有兩個節點了(在這里我是使用了兩個linux主機,如果只有一台主機,可以試試使用docker-machine來創建虛擬主機,這個工具還有功能就是可以創建管理本地及遠程虛擬主機,試想假如有100台主機,如何在上面配置Docker呢?批量執行腳本是個選擇,同樣的使用docker-machine也是一個選擇)。且一台master 一台work 即MANAGER STATUS 其實這個字段還有其他值
Reachable:該節點是管理節點中的從節點,如果 Leader 節點不可用,該節點有資格被選為新的 Leader
Unavailable:該管理節點已不能與其他管理節點通信。如果管理節點不可用,應該將新的管理節點加入群集,或者將工作節點升級為管理節點。
這里有一個知識點就是如果節點比較多的情況下怎么知道節點對應的宿主機呢?
其實在每個節點 使用 hostname這個命令即可對應到節點的列表中了。(docker node ls 命令會展示節點對應的Hostname)
實際上我們還可以對每個節點進行個性化設置。即添加標簽。
# 只能在manager節點執行該命令 docker node update --label-add <label-name>=<label-value> --label-add <label-name>=<label-value> <hostname>
命令如上。此時我們即可對每個node添加標簽了,比如我們可以添加一個名稱為ip的標簽
使用命令
docker node update --label-add ip=192.168.1.1 www.xxx.com
即可添加到對應的label。
此時我們在manager節點,使用 docker node ls 得到節點列表。
同時使用。
docker node inspect <節點id>
即可找到該節點對應的ip。當然直接使用該命令(不用前面的麻煩步驟)也可以得到當前節點對應的Ip
既然集群已經創建好了,那么我們如何部署自己的應用呢?
其實很簡單,前面學習的docker-compose的知識可以用到了。
這里先說明一下部署的應用。要部署4個應用。使用docker-swarm在兩個節點的情況下,他會給每個節點分配兩個應用。最后達成的效果應該是這個四個服務可以互相訪問的到。
首先先編寫"docker-compose.yml",這里為什么加上了引號,因為嚴格意義上說我們並不是要使用docker-compose了,因為這里有的參數並不適用於docker-compose。
version: '3'
services:
node_a1:
image: xxx/node:v1
networks:
- my-net
ports:
- "8000:8080"
deploy:
replicas: 1
command: java -jar node-a1-1.jar
node_a2:
image: xxx/node:v1
networks:
- my-net
ports:
- "8001:8080"
deploy:
replicas: 1
command: java -jar node-a2-1.jar
node_b1:
image: xxxx/node:v1
networks:
- my-net
ports:
- "8002:8080"
deploy:
replicas: 1
command: java -jar node-b1-1.jar
node_b2:
image: xxx/node:v1
networks:
- my-net
ports:
- "8003:8080"
deploy:
replicas: 1
command: java -jar node-b2-1.jar
networks:
my-net:
driver: overlay
可以看到,我們寫了四個應用,這四個應用里面是什么內容呢? 其實就是每個應用訪問其他三個應用。需要注意的是。這里使用的網絡 是 overlay
接下來就是要發布服務了。使用命令
# 在master節點執行 , stack.yml 就是剛才編輯的"docker-compose.yml"文件 test 是服務名前綴
[root@zhongjianjian03 ~]# docker stack deploy -c stack.yml test

可以看到創建了一個網絡,和四個應用。
此時我們可以查看我們的服務有哪些
#mster節點執行 [root@zhongjianjian03 ~]# docker service ls

可以看到我們的服務有哪些。
但其實我關心的是,我的服務在哪個節點上,畢竟我是swarm集群,有兩台機器。
其實查找服務在哪個節點,有兩種方法,一種是直接在某個節點上執行
docker ps
這樣就可以看到執行命令的節點上跑了哪些容器(也即服務)。
節點A

節點B

這樣我們就找到了服務對應的機器節點。
你可能會想這樣很慢,如果節點很多,那要找一個服務所在的節點不是很慢?
其實還可以使用其他方式,首先查詢所有的服務列表

比如我想知道 test_node_b2所在的節點。此時我們現在有了 service id 。我們可以通過命令查到服務所在節點信息
# 在master節點執行
[root@zhongjianjian03 ~]# docker service ps i5xlp60hd4x5

如圖,可以看到已經查到了節點信息,可以跟上圖做一個比較,發現信息是一致的。
但是當我們的服務比較多的時候,怎么快速找到服務對應的容器是哪個呢?
# 該命令在master/work節點都可以工作,命令返回容器信息(只顯示當前節點的) docker ps --filter name=<service_name> -q(可選)
此時,服務都啟動了。我們怎么知道服務之前是否互通呢?
很簡單,之前我們在編輯“docker-compose.yml”文件時定義了四個服務。
即:node_a1 node_a2 node_b1 node_b2
現在這四個服務分布在了兩個機器上。我們任意選擇一個機器,選擇其中的一個容器進去。
比如我們進入node_a1容器
# 需在容器所在的節點 上執行該命令
[root@zhongjianjian03 ~]# docker exec -it d97765b92136 bash
這樣我們就進入了容器內部。
接着我們只需要使用ping 命令就可以知道是否可以互相訪問了

從圖片可以知道。網絡是通的。接着就可以測試自己應用的通過性了,具體就以實際應用為准了
至此docker-swarm集群搭建完畢。可以看到跟docker-compose相比,只是在命令上有些不同,docker-compose需要單獨安裝,而docker-swarm則需要提前創建集群。
現在我們的應用分布在集群里,就可以方便的進行服務冗余了,當然docker-swarm的命令不止這些,但是缺點也比較明顯就是沒有可視化的界面可供操作,雖然可以通過安裝portainer
來管理swarm集群,但功能上會有局限,並沒有k8s強大!
同樣的,如果增加了某個服務,比如增加了一個node5服務,首先現在 stack.yml中新增服務。然后使用命令
docker stack deploy --compose-file=/opt/docker/yml/stack.yml node5
即可完成新增服務的部署!
如果不想使用集群了。也可以刪除集群。
當前節點狀態:

可以看到 AVAILABILITY字段的兩個值均是在線狀態
刪除節點:
# 讓 node3 離開,排空 該node 的容器(在 master 上操作)
[root@zhongjianjian03 ~]# docker node update --availability drain i0yhyiotqklaj7626jfavnuky
此時可以看到node的狀態

讓被移除的node離開集群
# 在被離開的節點上操作
[root@app01 ~]# docker swarm leave
Node left the swarm.
刪除node節點
# 在master節點操作
[root@zhongjianjian03 ~]# docker node rm i0yhyiotqklaj7626jfavnuky
此時 節點列表為:

之后我們只需要使用類似的命令就能刪掉主節點:
[root@zhongjianjian03 ~]# docker node update --availability drain rsj6jxbm1fwz7dsbn0pxillxj rsj6jxbm1fwz7dsbn0pxillxj [root@zhongjianjian03 ~]# docker swarm leave --force Node left the swarm.
之后再次查看集群狀態

集群已移除!。
如果master節點未被刪除,現在有新節點要加入集群,應該如何獲取Token呢?
# 在master節點上使用命令 docker swarm join-token 可以查看或更換join token。 docker swarm join-token worker:查看加入woker的命令。 docker swarm join-token manager:查看加入manager的命令 docker swarm join-token --rotate worker:重置woker的Token。 docker swarm join-token -q worker:僅打印Token。
需要注意的幾個點,我們上篇文檔介紹了 。docker-compose占位符的使用。
而再docker swarm的stack.yml文件中,除了部分配置有差別外,docker-compose的占位符也是不能直接使用的。
如果你直接使用了,你在啟動的容器中使用inspect查看容器信息。是看不到占位符的信息的。
因此總體解決思路是這樣的,先使用docker-compose -f custom-docker-compose.yml config > stack.yml
先使用docker-compose config命令輸出文件,到stack.yml 然后再使用docker stack deploy -c stack.yml <stack name>來啟動。
可以參考
同時,docker swarm 與docker-compose本身也是有區別的,當然顯著的區別是docker-compose 是單機的,swarm是集群的,同時,對於docker-compose來說,每個服務是container 而docker swarm是每個service,雖然在docker-compose 也可以使用service,這個在 portainer 工具中是可以查看的,有一個能想到的點是,如果我docker swarm發布了很多應用,這個時候我想更改某個服務的端口映射,那么停止服務,更新腳本,重啟啟動,明顯是很麻煩的。其實還是可以通過docker命令來更新的。鏈接
更新運行中容器端口映射。
#添加端口映射,第一個為宿主機端口,servicename需要注意,看使用的是swarm集群還是直接的compose,如果是swarm集群需要加上stack 名 docker service update --publish-add '5050:8080' <service_name>
由上所述服務在單副本的情況下,是沒有問題的,但是多副本時,就會涉及到服務的負載均衡。簡單來講,docker swarm的負載均衡有兩種方式
1.vip
vip這種形式為swarm的默認形式,簡單說,如果swarm集群里,部署了一個nginx應用,並且配置容器與宿主機的端口映射,此時你訪問集群的任意節點,都可以訪問該服務。
2.dnsrr
dnsrr需要單獨進行配置,對應命令行中的 --endpoint-mode dnsrr 。這種模式下不支持端口映射,也就是說如果你是前端應用就不能使用該模式了。該模式的是使用DNS輪詢的方法進行的負載均衡。因此比較適合做后端服務。也就是說在一個swarm的stack中,后端service有多個副本,適合使用該方式,前端發送的請求后均勻發送到后端的容器中。然而並非每次請求都會均勻分布,比如十次請求,前5次走A容器后5次走B容器,如果manager節點也運行了服務,則manager節點不處理請求。
#version: "3" #這里需要注意版本,如果是3則報錯:error endpoint_mode Additional property endpoint_mode is not allowed
version: "3.3"
services:
wordpress:
image: wordpress
ports:
- 8080:80
networks:
- overlay
deploy:
mode: replicated
replicas: 2
endpoint_mode: vip #wordpress是前端應用(准確說是前后端在一起的應用)使用默認的vip方式
mysql:
image: mysql
volumes:
- db-data:/var/lib/mysql/data
networks:
- overlay
deploy:
mode: replicated
replicas: 2
endpoint_mode: dnsrr #mysql是后端服務,不與宿主機映射端口,可以使用dns輪詢的方式
volumes:
db-data:
networks:
overlay:
compose-file API


