Docker的集群實戰之Swarm模式
- 2019 年 12 月 12 日
- 筆記
點擊上方「編程三分鐘」,馬上關注,技術原來如此簡單。
隨著業務規模的擴大,一台機器的Docker已經無法滿足我們的要求,為了保證性能和高可用,Docker提供了一種叫Swarm的解決方案。
他可以跨多個Docker主機來部署容器,具有完備的安全機制、內置負載均衡器;支援擴縮容、升級和回滾。
這次讓我們用Swarm來部署一個2節點集群,並使用其負載均衡特性部署一個2副本Web應用。
何謂Swarm?
一個Swarm集群由一個或多個Docker節點組成。這些節點可以是物理機、虛擬機等。只要保證節點之間的網路通暢即可。Docker Swarm的結構如下:

上圖是六個節點的集群,我們來引入三個概念:
節點:分為管理節點(Manager)或工作節點(Worker)兩種類型,Manager負責監控集群狀態、分發任務到Worker等操作;Woker負責接收Manager發來的任務並執行,每個節點就是一台Docker主機,Manager同時也是Worker節點,因為老闆某種程式上來說也是員工,只不過老闆是在為自己打工。
服務:服務是Worker節點執行任務相關的概念,把每個在Swarm上跑的應用都是以服務的方式運行。
副本:每個服務為了達到高可用,會複製部署多個,部署了三個我們就稱這個服務部署了三個副本。
負載均衡:Swarm自帶負載均衡器,用來處理的請求。
值得一提的是Swarm的配置和狀態資訊保存在位於所有Manager上的分散式etcd資料庫中;同時在集群內部,有一個安全系統,用於節點間通訊加密、認證和授權等操作,這整個過程都是自動的,和etcd一樣不需要任何配置,幾乎察覺不到他們的存在。
- Docker Swarm自docker 1.12版本以後已經和Docker直接集成在一起了,一條命令就可以啟用。
第0步 – 準備

我們要搭建一個兩節點集群,整個集群只有一個服務,兩個副本,每個副本就是一個容器,均勻分布在每個節點上。
準備:
- 兩個互通的Docker主機 主機名為host01 host02
- 一個能獲取到主機名的html網站鏡像
第1步 – 初始化Swarm模式
(創建第一個manager)


使用以下命令把docker轉成Swarm模式。
$ docker swarm init
執行完這條命令,當前節點就成為了Manager節點,並打出一個token,以後在拓展的時候就要用的到token驗證了。
host01執行 $ docker swarm init Swarm initialized: current node (hzdjc2iv3m7onlz54k8hkhfpe) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-1hkuj0ya0ppj2qbmnq3tiqtyfbudo3wp6xcfmy446tadde1gpl-2ldsknja98b6s94k4pc3huno4 172.17.0.15:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
172.17.0.15是host01的ip,2377是Swarm默認的集群管理埠,加入集群就是向此埠通訊。這個埠要控制好訪問許可權來防止不信任的用戶或者節點訪問到。
第2步 – 加入集群

集群的好處就是崩潰一個節點的時候,節點上運行的容器就會自動遷移到其他正常節點上。
要向集群加入新的節點,首先要做的就是獲得token
#輸出添加worker所需要的token $ docker swarm join-token -q worker #輸出添加manager所需要的token $ docker swarm join-token -q manager
我們現在host01已經創建為manager節點了,現在把host02節點以worker的身份加入集群。
在host02上執行以下命令(命令較長,和
>
代表換行)
$ token=$(ssh -o StrictHostKeyChecking=no 172.17.0.15 > "docker swarm join-token -q worker") && echo $token Warning: Permanently added '172.17.0.15' (ECDSA) to the list of known hosts. SWMTKN-1-1hkuj0ya0ppj2qbmnq3tiqtyfbudo3wp6xcfmy446tadde1gpl-2ldsknja98b6s94k4pc3huno4
在host02上執行以下命令,可以遠程登陸host01並把worker所需的token賦值到token變數中(172.17.0.15是host01的ip)
$ docker swarm join 172.17.0.15:2377 --token $token This node joined a swarm as a worker.
向manager節點發加入集群的請求,token為附帶參數(根據token來判斷新加入的節點角色)
默認情況下,manager將自動接受添加到集群的新節點。
可以使用docker node ls
來查看節點狀態
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION hzdjc2iv3m7onlz54k8hkhfpe * host01 Ready Active Leader 18.09.5 c5fsn2z7p1tw5iqwa2d54698m host02 Ready Active 18.09.5
第3步 – 創建覆蓋網路
(overlay網路)

在創建服務之前,需要創建一個覆蓋網路,它是一個二層網路(沒有匯聚層)。
以下命令將創建一個名為skynet的新overlay網路。註冊到此網路的所有容器都可以互相通訊,不管部署在哪個節點上。 第一台
$ docker network create -d overlay skynet 8t0ntbrcbo
第4步 – 部署服務

默認情況下,Docker會均勻的把副本部署在集群中,如果刪掉一個節點,上面所有的服務都會重新分配在其他機器上。
現在就要把我們準備好的鏡像拿出來了,一個名為hostname-web:v1
的鏡像,他部署在哪台機器上就到獲取到哪個主機的hostname,設置到容器內部的index.html里。
manager執行
docker service create --name http --network skynet --replicas 2 -p 80:80 hostname-web:v1
--name
服務名
--network
指定網路 --replicas
副本數
-p
映射埠
上面的命令創建了一個名為http的服務,指定的網路為上一步創建的skynet覆蓋網路,2個副本,映射80到容器中的80埠,使用hostname-web:v1鏡像。
請求80埠就是在訪問服務,swarm會在所有副本之間進行負載均衡,
可以在manager上運行docker service ls
查看狀態
$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS tvidvge94pzt http replicated 2/2 hostname-web:v1
可以使用docker ps
分別在兩個主機上查看創建的鏡像,這裡我們就不廢話了。
在host01上請求,查看結果
$ curl host01 <h1>host01</h1> $ curl host01 <h1>host02</h1>
第5步 – 檢查狀態
查看服務下所有的容器列表詳細資訊,包括容器跑在哪台機器上,用的什麼鏡像,跑了多長時間等。
$ docker service ps http ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS zydwyr2tpzd4 http.1 hostname-web:v1 host02 Running Running 3 minutes ago 38ih400au70t http.2 hostname-web:v1 host01 Running Running 3 minutes ago
查看服務的詳細資訊和配置
$ docker service inspect --pretty http
可以使用docker node ls
來查看節點狀態
$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION hzdjc2iv3m7onlz54k8hkhfpe * host01 Ready Active Leader 18.09.5 c5fsn2z7p1tw5iqwa2d54698m host02 Ready Active 18.09.5
可以把上面輸出結果的第一列ID當做docker node ps
的參數,查詢此節點上的服務列表,如果用self參數則代表本機。
擴容與縮容自動均衡
我們可以在服務運行的時候,修改副本數量實現自動擴容
執行以下命令把http服務擴容成五個副本運行。
$ docker service scale http=5 http scaled to 5 overall progress: 5 out of 5 tasks 1/5: running 2/5: running 3/5: running 4/5: running 5/5: running verify: Service converged
在host01上查看擴容結果,可以看到有兩個容器,另一台機器上有三個容器。Swarm會盡量保證各個副本均勻的分布在每個節點上(就算負載大的機器還是會被均勻分配,有興趣可以研究真正的負載均衡方案,也歡迎在留言器和我交流)
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fe374853b402 hostname-web:v1 "/app" 48 seconds ago Up 47seconds 80/tcp http.3.8xx1eo4qop3ctefim9k685xz7 01241f07c109 hostname-web:v1 "/app" 7 minutes ago Up 7 minutes 80/tcp http.2.38ih400au70tvbs76xa10xmpa
小結
docker swarm init
初始化新的Swarm,並把當前節點設置為第一個Manager。
docker swarm join-token --tags <token>
節點加入集群
docker swarm join-token -q manager|worker
列印加入集群時節點對應角色所需要的token
docker node ls
列出所有節點資訊
docker node ps <id>
查看某個節點下的所有服務
docker service create
創建服務
docker service inspect <service>
服務詳細資訊
docker service ps <service>
服務的副本(容器)資訊
docker service scale <service>=<number>
擴縮容
docker service update
更新服務屬性
docker service logs
查看服務日誌
docker service rm
刪除服務(在不做確認的情況下刪掉服務的所有副本)
Docker 還有滾動升級、自動鎖機制等優秀的特性,感興趣可以一起學習一下~