Docker Swarm 作為容器協調工具,簡化了容器叢集的管理和應用佈署流程。理解 Swarm 的核心概念對於建構和維護可擴充套件的容器化應用至關重要。本文將逐步解析 Swarm 的節點管理,區分管理節點和工作節點的角色與功能,並示範如何使用指令操作節點。接著,文章將引導讀者建立和佈署 Tomcat 服務,包含映像確認、服務建立指令、副本數量設定,以及透過指令驗證服務狀態。此外,文章也詳細說明如何擴充套件和縮減服務副本數量,並以流程圖輔助說明擴充套件和縮減的運作機制。在服務發現的部分,文章解釋了服務發現的重要性,並比較了客戶端和伺服器端服務發現模式的差異,同時也用圖表說明 Docker Swarm 如何支援這兩種模式。最後,文章探討服務註冊的概念,比較自我註冊和外部註冊的優缺點,並以 Registrator 為例說明外部註冊的運作方式,最後也簡述了服務發現工具的比較和未來發展趨勢。

Docker Swarm 叢集與服務管理

在現代的雲端運算與容器化技術中,Docker Swarm 是一個非常強大的工具,用於管理和協調容器叢集。它提供了簡單且有效的方式來佈署、擴充套件和管理應用程式。以下,玄貓將帶領大家深入瞭解 Docker Swarm 的節點管理、服務建立、擴充套件以及服務發現的相關技術。

Docker Swarm 叢集節點管理

首先,讓我們來看看參與叢集的節點。在 Docker Swarm 中,節點可以分為管理節點(manager)和工作節點(worker)。管理節點負責叢集的控制和排程,而工作節點則負責執行實際的容器任務。

docker node ls

執行上述命令後,你應該會看到類別似以下的輸出:

ID                            HOSTNAME            STATUS    AVAILABILITY   MANAGER STATUS
ckmtounajpf06pglhv8jer1ou     swarm-master        Ready     Active        Leader
p8c41ftcu9g0ugicxf7g5cnff     linux-dev.localdomain Ready    Active

這表示我們的叢集中有一個管理節點(swarm-master)和一個工作節點(linux-dev.localdomain)。

服務建立與佈署

接下來,玄貓將介紹如何在 Docker Swarm 中建立一個 Tomcat 服務並進行佈署。這裡我們需要指定要使用的 Docker 映像以及需要執行的例項數量(副本數)。

首先,確認目前沒有執行中的容器:

docker ps -a

接著,檢查本地是否已經有 Tomcat 映像:

docker images

假設我們已經有 tomcat:7.0 的映像,接下來就可以建立一個名為 TomcatService 的服務,並指定只執行一個副本:

docker service create --name TomcatService --replicas 1 tomcat:7.0

執行上述命令後,你應該會看到類別似以下的輸出:

s7g73pnm2iko7njdmn1fnwp8o

這表示服務已經成功建立。接下來,我們可以透過 docker ps -a 命令來檢視執行中的容器:

docker ps -a

你應該會看到類別似以下的輸出:

CONTAINER ID   IMAGE          COMMAND       CREATED        STATUS       PORTS      NAMES
1525a4bd2b17   tomcat:7.0     "catalina.sh run"  5 seconds ago Up 3 seconds 8080/tcp   TomcatService.1.t1wrpk878feb53r7wsh2lkbvw9362kfvb4wd94jfnx2o...

最後,使用 docker service ls 命令來列出剛剛啟動的服務:

docker service ls

你應該會看到類別似以下的輸出:

ID             NAME           MODE         REPLICAS   IMAGE        PORTS
s7g73pnm2iko   TomcatService  replicated   1/1        tomcat:7.0

這表示 TomcatService 已經成功啟動並且達到了預期的副本數。

擴充套件與縮小服務

在 Docker Swarm 中,擴充套件和縮小服務非常簡單。例如,我們可以透過以下命令來擴充套件 TomcatService 的副本數量到 2 個:

docker service scale TomcatService=2

執行上述命令後,你應該會看到類別似以下的輸出:

TomcatService scaled to 2

接下來,使用 docker service ls 命令來檢視服務狀態:

docker service ls

你應該會看到類別似以下的輸出:

ID             NAME           MODE         REPLICAS   IMAGE        PORTS
s7g73pnm2iko   TomcatService  replicated   1/2        tomcat:7.0

# 再次檢視狀態,應該會看到副本數量已經達到 2 個

ID             NAME           MODE         REPLICAS   IMAGE        PORTS
s7g73pnm2iko   TomcatService  replicated   2/2        tomcat:7.0

同樣地,縮小服務也非常簡單。例如,我們可以透過以下命令來將 TomcatService 的副本數量縮小到 1 個:

docker service scale TomcatService=1

副本擴充套件與縮減流程圖示

此圖示說明瞭如何透過 Docker Swarm 處理擴充套件與縮減容器副本。每當需要增加或減少副本時,Swarm Manager 都會根據設定的目標副本數自動調整容器例項。

  graph TD;
    A[起始狀態 - 副本數為1] --> B[擴充套件命令 - scale TomcatService=2];
    B --> C[Docker Service 則增加一個新容器];
    C --> D[檢查狀態 - 副本數為2];
    D --> E[縮減命令 - scale TomcatService=1];
    E --> F[Docker Service 則停止一個容器];
    F --> G[檢查狀態 - 副本數為1];

內容解密:

  • A:起始狀態為只有一個 TomcatService 的副本。
  • B:發出擴充套件命令時,要求將 TomcatService 的副本數量增加到兩個。
  • C:Docker Service 接收到指令後開始啟動新的容器。
  • D:檢查叢集狀態時確認已成功增加到兩個 TomcatService 副本。
  • E:發出縮減命令時要求將 TomcatService 副本數量減少至一個。
  • F:Docker Service 接收到指令後開始停止不需要的容器例項。
  • G:最終狀態確認剩餘一個 TomcatService 副本。

服務發現

在雲端運算與容器化時代,服務發現(service discovery)是非常重要的一環。它解決了在高度動態環境中如何找到特定服務例項位置的問題。

傳統上,當我們佈署應用程式時會使用固定主機名或 IP 地址來連線不同服務。然而隨著虛擬機器(VM)和容器化技術的普及,動態加入和移除節點變得常見。這使得傳統的靜態組態方式顯得不再可行。

現在我們可以使用負載平衡器(如 NGINX 或 HAProxy)來動態更新組態並分配流量。然而在容器化環境中情況更加複雜:容器能夠快速啟動和停止且位置不固定。

解決這些問題最佳方式之一就是採用服務發現工具。常見模式有兩種:

  • 客戶端服務發現:客戶端會向註冊中心查詢特定服務位置及健康狀況。
  • 伺服器端服務發現:由伺服器端負載平衡器來處理流量分配並掩蓋底層變化。

Docker Swarm 的客戶端與伺服器端發現模式

在 Docker Swarm 中客戶端和伺服器端發現模式都能夠被支援:

  • 客戶端發現:當一個新服務啟動時註冊到中心目錄中;當它停止時從目錄中移除。
  • 伺服器端發現:Swarm Manager 處理所有流量並根據健康狀況動態分配給工作節點中的合適例項。

流程圖示

此圖示展示瞭如何透過 Docker Swarm 的客戶端和伺服器端模式進行服務發現。

  graph LR;
    A[Client Application] --> B{Load Balancer};
    B --> C[Swarm Manager];
    C --> D[Worker Node];
    D --> E[Tomcat Container];

    subgraph Server-Side Discovery;
        B -- Updates dynamically --> C;
        C -- Distributes Traffic --> D;
    end;

    subgraph Client-Side Discovery;
        A -- Query Registry --> F[(Registry)];
        F -- Provides Location Info --> A;
    end;

內容解密:

  • A:客戶應用程式嘗試連線到某個特定功能或資源。
  • B:負載平衡器收到請求並轉發給適當位置。
  • C:Swarm Manager 作為流量分配控制中心處理請求。
  • D:真正執行應用程式的工作節點負責處理請求。
  • E:實際處理請求的是 Tomact Container 本身。

在圖中的Server-Side Discovery部分說明瞭如何由伺服器端負責自動更新分佈流量;而在Client-Side Discovery部分則說明瞭客戶端如何直接向註冊中心查詢資訊以獲得所需資源位置。

容器協調中的服務註冊

在微服務架構中,服務註冊是一個至關重要的概念。它類別似於黃頁,提供了微服務執行位置的詳細資訊,例如主機和埠。由於微服務可以隨時啟動或停止,它們的位置並不固定。因此,服務註冊必須能夠動態更新這些變化。

客戶端服務發現

在客戶端服務發現的模式中,客戶端負責查詢服務註冊以取得所需服務的位置。這種方法的主要缺點是,客戶端必須知道服務註冊的存在,並且在與服務通訊之前需要發現服務。例如,假設有兩個 Service A 的例項和三個 Service B 的例項,如下圖所示:

  graph TD
    A1[Service A (Instance 1)] -->|2.3.4.6: 8080| B[Service Registry]
    A2[Service A (Instance 2)] -->|2.3.4.5: 8080| B
    B1[Service B (Instance 1)] -->|1.2.3.4: 80| B
    B2[Service B (Instance 2)] -->|1.2.3.5: 80| B
    B3[Service B (Instance 3)] -->|1.2.3.6: 80| B
    C[Service A (client)] --> |Query registry for service location| B

此圖示展示了 Service A 的客戶端如何查詢 Service Registry 以取得服務位置。這種方法的缺點是將責任推給了客戶端應用程式,因為它們必須在與服務通訊之前先發現服務。

伺服器端服務發現

在伺服器端服務發現的模式中,客戶端可以直接向 API 閘道器或負載平衡器傳送請求,而不必擔心連線到正確的服務。負載平衡器會處理管理服務註冊、查詢註冊以取得服務位置來處理傳入請求以及在多個例項之間進行負載平衡操作。

  graph TD
    C[Service A (client)] --> |Send request to connect to Service B| LB[Load Balancer / API Gateway]
    LB --> |Query registry for a service location| SR[Service Registry]
    LB --> |Forwards the request to Service B| SB1[Service B (Instance 1)]
    LB --> |Forwards the request to Service B| SB2[Service B (Instance 2)]
    LB --> |Forwards the request to Service B| SB3[Service B (Instance 3)]

此圖示展示了伺服器端服務發現的過程。客戶端向負載平衡器傳送請求,負載平衡器查詢 Service Registry 取得 Service B 的位置,並將請求轉發到適當的例項。

這種模式的典型例子是 Amazon ELB(彈性負載平衡器)。假設我們在 AWS 上設定了一個包含四個 EC2 機器的 Tomcat 叢集來處理應用程式層。為了將流量分配到這四個 Tomcat 例項之間,我們需要將這些例項新增/註冊到 ELB 中,並提供詳細資訊如例項名稱、服務執行的埠、保持健康檢查的機制以及健康檢查頻率。一旦組態完成,ELB 將負責處理傳入請求並將請求路由到合適的 Tomcat 例項。

自我註冊 vs 外部註冊

自我註冊

自我註冊是指微服務本身將其位置資訊傳送到服務註冊。例如,Consul 提供了一個 API 用於與之互動。每個微服務都需要與 Consul API 聯絡以傳遞其位置資訊。然而,根據微服務模式和最佳實踐,每個微服務應該專注於單一功能。強制微服務向服務註冊傳遞其位置資訊違反了單一責任原則,因此自我註冊並不是廣泛使用的選項。

  graph TD
    M1[Micro service] --> |Send up/down events| SR[Service Registry]
    M2[Micro service] --> |Send up/down events| SR
    M3[Micro service] --> |Send up/down events| SR
    M4[Micro service] --> |Send up/down events| SR

此圖示展示了自我註冊過程中的微服務如何直接向 Service Registry 報告其狀態變化。

外部註冊

外部註冊是指利用外部工具來管理微服務與 Service Registry 的互動。這樣可以讓微服務專注於其核心功能而不必擔心向 Service Registry 報告自己的位置。例如,Registrator 是一個開源元件,作為 Docker 與 Service Registry 之間的橋樑。它自動註冊和反註冊容器中的服務。當 Docker 輸出事件時(例如容器啟動或停止),Registrator 則檢視這些容器以取得有關其提供哪些資訊並將這些資訊傳遞給任何 Service Registry 工具(例如 Consul、etcd、SkyDNS)。

  graph TD
    N1[Node 1] -.-> R1[Registrator]
    N2[Node 2] -.-> R2[Registrator]
    R1 -.-> SR[Consul, etcd, SkyDNS]
    R2 -.-> SR
    N1 -.- C11[Container]
    N1 -.- C12[Container]
    N2 -.- C21[Container]
    N2 -.- C22[Container]

此圖示展示了 Registrator 安裝在所有執行容器節點上並與 Service Registry 配合工作以保持即時更新狀態。

各種工具比較

有許多開源工具可以用於進行微服務發現,包括 Consul(HashiCorp)、Zookeeper(Apache)、etcd、SmartStack(AirBnB)、Eureka(Netflix)和 SkyDNS。這些工具在許多能力上是相似的。它們主要區別在於輕重程度以及支援查詢協定(例如 DNS、HTTP/TCP)。

最佳化和未來趨勢

未來趨勢顯示自動化和智慧化將成為主流。例如:

  • 智慧負載平衡:未來負載平衡可能會更加智慧化,考慮到各種因素如網路延遲、資源利用率等。
  • 自動故障檢測:更加智慧的健康檢查機制將幫助系統自動檢測並處理故障。
  • 混合雲支援:隨著混合雲架構的流行,未來微服務發現可能需要同時支援多個不同雲環境中的資源。