[Docker] 使用 Docker Swarm 管理多台 Server 的服務

架設容器調度工具 - Docker Swarm & 託管多個 Container 的教學。

 

 

 

前言

之前我有寫一篇  [Docker] 使用 Docker Compose 統一管理 Container | K. C. - 點部落 (dotblogs.com.tw)  文章說明在單台 Server 如何管理多個 Container,但是大多數公司不會只有一台 Server,如果想要在多台 Server 部屬 & 管理 Container,使用 Docker Compose 就有點吃力了,並且單台部屬的 Docker Compose 是無法因應某台 Server 故障的異常處理,一旦有任何一台 Server 出事,該台 Server 上的服務就會全都跟著一起死掉了,所以接下來就要使用到容器調度工具了。

使用容器調度工具來管理的話,他可以幫你輕鬆快速的創建 Container,並且可以同時管理多台 Server,做監控 & 調度的工作,那些由他管理的服務並不會固定放在某台 Server,如果某個服務目前部屬的 Server 突然死掉了,調度工具會偵測到那台 Server 出事,將那台 Server 上的服務改部屬至其他台 Server,這就是調度最重要的目的。


當然,調度工具也不是只能做到調度而已,每種調度工具都各自會提供一些不同的附加功能。目前市面上主流的容器調度工具分別是 Kubernetes(K8s)與 Docker Swarm,K8s 雖然功能更多更完善,不過學習曲線比較高,而 Docker Swarm 入門 & 設置都比較容易,並且 Server 只要有安裝 Docker 就能使用,docker-compose.yml 也能沿用 Docker Compose 版的來做小小調整即可,所以對兩者都沒碰過的我來說我選擇先以 Docker Swarm 入門,如果之後需要更多完善的功能,在有容器調度相關的常識後再跳槽 K8s 應該也會比較容易。網路上很多 K8s 與 Docker Swarm 的比較文章,有興趣的小夥伴可以再多爬些比較文根據自身條件選擇,這裡我就不贅述了~

 

 

建置環境

Linux OS Version:Ubuntu 20.04.3 LTS

Docker version:20.10.12

容器調度工具:Docker Swarm

 

 

Docker Swarm 配置規劃

這裡我準備 2 台 Server,1 台當 manager,1 台當 worker

(請確保使用的這幾台 Server 網路都可以通都能互相訪問)

這裡是因為做 Demo 所以才只展示 2 台,正式環境的話建議最少要有 7 台 Server 喔~
關於 Swarm 用的 Server 數量建議可再參考  How nodes work | Docker Documentation


這裡補充一下 manager 與 worker 的功能差異:

manager:管理/查看/監控 worker 的狀況、分配服務給 worker 的 Server,所以服務的定義檔(docker-compose.yml)必須交給 manager 來讓它執行,不過當 manager 的 Server 也能做 worker 的工作(運行 Swarm 服務)

worker:運行 Swarm 服務的 Server,但 worker 只能是 worker,不能做任何 manager 權限的事

 

 

install Docker

請先在想加入 Docker Swarm 叢集的 Server 內安裝好 Docker。

使用 Docker Swarm 只需要安裝 Docker 即可,不用像 Docker Compose 還需要再安裝 docker-compose。還沒安裝 Docker 的話先移至 [Docker] Server 從 0 開始建置 Docker 環境 | K. C. - 點部落 (dotblogs.com.tw) 查看安裝方式,安裝完再回來繼續。

 

 

將 Server 加入 Docker Swarm 叢集

Server 安裝完 Docker 後,Docker CLI 預設就有支援 Docker Swarm 的命令,立即就能開始實作。

要將 Server 加入 Docker Swarm 叢集,有幾個步驟要設置:

  • 將 Docker 切換到 Swarm 模式
  • 設置 Swarm 用 IP
  • 加入 worker
  • 加入 manager

 

 

將 Docker 切換到 Swarm 模式

首先在你要當作 manager 的 Server 輸入 swarm init 命令,他會將此 Server 切換到 Swarm 模式,並把這台設置為 manager

docker swarm init

swarm init 命令只須執行一次,後續其他台的 manager、worker 都只需要透過 join 命令來加入,不用每台都做一次 init

Swarm 化後,這些加入 Docker Swarm 叢集內的 Server 們,我們會稱呼他們為 Node(節點)

 

 

設置 Swarm 用 IP

如果此 Server 有多個網卡,就會有多個 IP,在 init 時會跳出這種錯誤訊息,告訴你需要特別指定用哪個 IP 供其他 Node 訪問用

Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (10.1.10.14 on ens166 and 10.1.20.14 on ens191) - specify one with --advertise-addr

 

那你的 init 命令就再加上 --advertise-addr,選擇好自己想要的 IP,改輸入以下命令 👇

docker swarm init --advertise-addr 10.1.20.14

 

 

加入 worker

執行完 swarm init 後,他會告訴你他已經將此 Node 設置為 manager,並先生成一個 add worker 用的指令

 

在其他台 Server 輸入此指令,就可以讓那台成為 worker Node

(這是我這一個 Swarm 叢集的 token,你不要複製我的阿,複製你自己的 😅)

docker swarm join --token SWMTKN-1-02ttsd1su3vyanl2uvgwqcbc2vd8lpancqb3mwjt8n5d68vd4g-5hv7xg50i2dbk9iung0rjxztc 10.1.20.14:2377

10.1.20.14:2377 是 leader manager 的 IP,讓 worker 知道要使用哪個 IP 來連線

 

 

若之後還要再添加 worker,也能在任一台 manager 輸入以下指令,再次取得 join worker 的命令

docker swarm join-token worker

 

看到 This node joined a swarm as a worker. 就表示加入成功了

 

 

加入 manager

若還要添加別台 manager,也是在既有的任一台 manager 輸入以下指令,即可取得 join manager 的命令

docker swarm join-token manager

已經執行過 swarm init 命令的 manager 就不用再執行 join 了喔~


他就會產生 join manager 用的 token

 

 

看到 This node joined a swarm as a manager. 就表示加入成功了

 

從上面幾張圖可以看到,join worker 與 manager 的指令長相是一樣的,只差別在於 token 後面有稍微不同,所以要小心不要搞錯了喔~

 

 

join 完後,可以在 manager 輸入此指令,查看 Swarm 中的所有 Node

docker node ls

關於上圖中這些 node 內容的詳情可參考 Manage nodes in a swarm | Docker Documentation

 

這裡要注意一下~

Swarm 模式下的一些查詢指令,只有 manager 可以使用,如果在 worker 執行就會顯示此錯誤 👇

Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.

 

 

Docker Swarm 架構

做完上述的操作後,你的 Server 就已經具有 Docker Swarm 的功能了,接下來該來認識一下 Docker Swarm 的服務部屬方式了。

Docker Swarm 與 Docker Compose 一樣,都是使用 docker-compose.yml 來部屬服務,只是差別在於他可以有多個複本(replicas),並且可以部屬至多台 Server 而已。

 

Docker Swarm主要由 4 個單位組成:

Node:前面章節有稍微提過了,Node 就是指加入 Docker Swarm 叢集的 Server

Stack:是將各種資源(Service、Network、Volume、Task)組合在一起的集合體,一個 docker-compose.yml 會運行一個 Stack

Service:也就是 docker-compose.yml 裡面撰寫的 Service,與 Docker Compose 的 Service 差不多

Task:就是一個 Container,不過他不是個獨立的 Container,他是由 Swarm 的 manager 控管的,它會根據 replicas 的項目來決定總共會 create 幾個 Task,獨立的 Container 可以在任一台有 Docker 的 Server 創建,而 Task 只能由 manager 創建
 

 

相關名詞的官方說明文章 Swarm mode key concepts | Docker Documentation

 

 

建立 Swarm 版 docker-compose.yml

這裡可以在 manager Node 裡面手動新增一個 docker-compose.yml 來測試

touch docker-compose.yml

 

docker-compose.yml 內容

version: "3.9"
services:
  demowebapi:
        image: docker.private.net/demowebapi:POC
        ports:
          - 9920:9920
        deploy:
          replicas: 2
          resources:
            limits:
              cpus: "0.30"
              memory: 500M
            reservations: 
              cpus: '0.20'
              memory: 100M
          placement:
              constraints:
                - node.role == worker
        environment:
          - ASPNETCORE_ENVIRONMENT=SIT
        extra_hosts:
          - "MyDB:10.10.10.11"
          - "MyDB2:10.10.10.12"
          - "MyDB3:10.10.10.13"

 

如果你跟上一篇 Docker Compose 的 yml 比較的話,會發現有以下幾個不同

  1. 拿掉 restart: always
    因為 Container 的控管已經是由 Swarm 處理,Swarm 會自動啟動你的服務,你不用再自己決定要不要重啟什麼
     
  2. 少了 network
    在 Docker Swarm 中的 network 叫 overlay network,如果你沒有在 docker-compose.yml 中配置,Swarm 預設會幫你 create 一個此 Stack 專用的 default overlay network,此 network 就會與此 Stack 共存亡。如果是另外單獨 create 一個 overlay network,多個服務關聯此 network,則可以做到用 DNS Name 互相訪問
    更多詳情可參考 Use overlay networks | Docker Documentation
     
  3. 多了 deploy 區塊
    這個就是 Swarm 模式中最主要的設定,接下來說明一下這些設置內容~

 

replicas:創建的 Task 數量,也就是 Container 的數量

resources: limits:限制此服務「最高」的資源限制(也就是上限的意思),不讓服務可以無限的使用主機的 CPU & Memory

resources: reservations:此服務「預先保留」的資源限制,在此設置的 cpus /memory 的量都只能 for 此服務使用,即使此服務沒有用到那麼多,這些資源也無法給其他人使用。

cpus: "0.30": CPU 限制 30%

memory: 500M:memory 限制 500 MB,如果是 GB 就後面改帶「G」就好(ex:1G)

placement: constraints: 限制服務只能在特定的 node 運行

  node.role == worker:限制只能在 worker node 運行

 

如果 Container 沒有指定 limit,預設可以存取 Server 內所有的 CPU 與 memory,所以正式環境一定要指定 limit,防止惡意攻擊大量消耗系統資源。

 

 

Deploy Stack

新增好 docker-compose.yml 後,接下來就如同前面架構說明所展示的流程圖,到 manager 建立 Stack 吧

溫馨提醒,以下操作都只能在 manager 處理喔~

 

Deploy Stack

docker stack deploy -c docker-compose.yml [StackName]

執行完 Deploy 命令後,會看到他告訴你在此 Stack 底下新增了 default 的 network,命名為 xxxapi_default,還有新增了 Servcice 命名為 xxxapi_xxxapi

這裡他的命名方式會用 stackName_serviceName 這種 format

 

列出所有 Stack

docker stack ls

會顯示 Stack 底下有幾個 Service

 

列出 Stack 內的所有 Service

docker stack services [stackName]

會顯示每個 Service 的詳細內容,使用的 image、他底下有幾個 replicas、服務開出去的 port 等內容

 

也可以查看不同 Stack 的所有 Service

docker service ls

 

如果想更新服務 or 更新 docker-compose.yml 的話,只要用原有的 Stack Name 再執行一次命令即可,他就會把 Stack 底下的 Service、network、Task 全部重建,等於更新現有的 Stack

 

查看 Service 所有的 replicas(也就是 Task)

docker service ps [ServiceName]

※ 這裡的 Node 顯示的是 node ID

上面這些是此 Service 的所有 replicas 的狀態,可以看到在服務更新的時候,他其實是直接 create 一個新的 Service,然後把新的 Service run 起來後,再把舊的 Service 下下來(切換成 Shutdown 狀態)

 

接著到各 worker 內,則可以用普通 docker 命令查看 Container

docker ps

由於我上面的 yml 有設置只能 worker 執行,所以才會只能在 worker 看到這些 Container,如果你沒有特別設置 placement,則會 worker、manager 都有可能運行 Container

 

 

接著就一樣用對應的 port 訪問即可

 

End

 

 

更多 Docker Swarm 說明可參考官方教學文章 Deploy services to a swarm | Docker Documentation