在現代軟體開發中,容器化技術已成為不可或缺的一部分。Docker Swarm 作為 Docker 原生的容器協調工具,提供了一套簡潔而強大的機制來管理和擴充套件容器化應用程式。本文將探討 Docker Swarm 中的服務擴充套件策略,包括複製服務和全域服務的運作方式,以及如何利用 Docker 命令列工具進行操作。此外,文章也會詳細介紹如何在 Docker Swarm 中使用掛載(Mounts),包含命名卷和繫結掛載的應用,以及如何在服務佈署過程中動態建立和管理卷,確保資料的永續性和分享性,特別是在資料函式庫等狀態型應用程式中的最佳實踐。
Docker Swarm 服務擴充套件與管理
Docker Swarm 提供了一種強大的容器協調工具,能夠有效地管理和擴充套件服務。本章節將重點介紹 Docker Swarm 中的服務擴充套件機制,包括複製服務(Replicated Services)和全域服務(Global Services),以及如何使用 Docker 命令列工具進行服務擴充套件和管理。
全域服務(Global Services)
全域服務是一種特殊的服務模式,它會在 Swarm 叢集中的每個節點上執行一個任務例項。這種模式非常適合需要執行在每個節點上的服務,例如日誌收集或監控代理。
建立全域服務
建立全域服務時,使用 docker service create 命令並加上 --mode global 引數。例如,建立一個名為 mysql-global 的全域服務,執行 mysql:latest 映象:
docker service create --name mysql-global --mode global mysql:latest
驗證全域服務
使用 docker service ls 命令可以檢視服務列表,並確認 mysql-global 服務的模式為 global:
docker service ls
輸出結果應該顯示 mysql-global 服務的模式為 global,並且在 REPLICAS 列顯示 3/3(假設有 3 個節點在 Swarm 中)。
檢視全域服務任務
使用 docker service ps mysql-global 命令可以檢視 mysql-global 服務的任務詳情,包括每個節點上的任務狀態:
docker service ps mysql-global
輸出結果將列出每個節點上執行的任務,包括任務 ID、節點名稱和當前狀態。
全域服務的限制
全域服務不能使用 docker service scale 命令進行擴充套件,因為它會在每個節點上自動執行一個任務例項。嘗試對全域服務進行擴充套件將會傳回錯誤訊息:
docker service scale mysql-global=5
輸出結果:mysql-global: scale can only be used with replicated mode
移除全域服務
可以使用 docker service rm 命令移除全域服務,就像移除複製服務一樣:
docker service rm mysql-global
複製服務(Replicated Services)
複製服務允許您指定服務的副本數量,並且 Docker Swarm 會確保在叢集中執行指定數量的任務例項。
建立複製服務
建立複製服務時,使用 docker service create 命令並加上 --replicas 引數。例如,建立一個名為 nginx 的複製服務,初始副本數量為 1:
docker service create --replicas 1 --name nginx nginx
擴充套件複製服務
可以使用 docker service scale 命令對複製服務進行擴充套件。例如,將 nginx 和 mysql 兩個服務分別擴充套件到 10 和 5 個副本:
docker service scale nginx=10 mysql=5
檢視複製服務狀態
使用 docker service ls 命令可以檢視服務列表,並確認 nginx 和 mysql 服務的副本數量:
docker service ls
輸出結果應該顯示 nginx 服務的副本數量為 10/10,而 mysql 服務的副本數量為 5/5。
檢視複製服務任務
使用 docker service ps 命令可以檢視指定服務的任務詳情。例如,檢視 nginx 和 mysql 兩個服務的任務狀態:
docker service ps nginx mysql
輸出結果將列出兩個服務的所有任務,包括任務 ID、節點名稱和當前狀態。
節點離開 Swarm 時的任務替換
當一個節點離開 Swarm 時,Docker Swarm 的排程器會自動在其他可用節點上重新排程該節點上的任務,以保持期望的副本數量。
節點離開 Swarm 的影響
當一個工作節點離開 Swarm 時,該節點上的任務將被標記為 Shutdown 狀態,並在其他可用節點上重新排程新的任務。例如,假設有一個名為 mysql 的複製服務,在三個節點上各執行一個副本。當其中一個工作節點離開 Swarm 時,該節點上的 mysql 副本將被關閉,並在其他可用節點上重新排程新的副本。
docker service ps mysql
輸出結果將顯示原始任務的狀態為 Shutdown,以及新排程的任務的狀態為 Running。
使用掛載(Mounts)於 Docker Swarm
在 Docker Swarm 模式下,服務任務容器(Service Task Container)可存取由其 Docker 映像繼承而來的檔案系統。資料透過 Docker 映像被整合到容器中。然而,在某些情況下,容器可能需要儲存或存取持久化檔案系統上的資料。由於容器的檔案系統會在容器離開時被刪除,因此需要將資料持久化儲存在容器外部。
問題描述
僅在容器記憶體儲資料可能導致以下問題:
- 資料不具永續性。當 Docker 容器停止時,資料將被刪除。
- 資料無法與其他 Docker 容器或主機檔案系統分享。
解決方案
根據單一職責原則(Single Responsibility Principle, SRP)的模組化設計建議將資料與 Docker 容器解耦。Docker Swarm 模式提供了掛載(Mounts)機制,用於分享資料並使資料在容器啟動和關閉過程中持久化。Docker Swarm 模式支援兩種型別的掛載:
- 卷掛載(Volume Mounts)
- 繫結掛載(Bind Mounts)
預設情況下,使用的是卷掛載。透過 docker service create 命令的 --mount 選項可為服務建立掛載。
卷掛載
卷掛載是將主機上的命名卷(Named Volumes)掛載到服務任務容器的指定目錄。即使容器停止或被刪除,主機上的命名卷仍然存在。命名卷可以在建立服務之前建立,也可以在服務佈署時建立。如果在服務佈署時建立命名卷,若未指定卷名,則會自動生成一個名稱。
卷掛載範例
假設有一個名為 mysql-scripts 的命名卷,在建立服務之前已存在,並將其掛載到服務任務容器的 /etc/mysql/scripts 目錄下。
docker service create --name mysql-service --mount type=volume,src=mysql-scripts,dst=/etc/mysql/scripts mysql:latest
繫結掛載
繫結掛載是將主機上的檔案系統路徑掛載到服務任務容器的指定目錄。該主機檔案系統路徑必須在 Swarm 中所有可能排程任務的主機上存在。若使用節點約束排除了某些節點,則這些節點上不必存在該路徑。
繫結掛載範例
將主機上的 /db/mysql/data 路徑掛載到服務容器的 /etc/mysql/data 目錄下。
docker service create --name mysql-service --mount type=bind,src=/db/mysql/data,dst=/etc/mysql/data mysql:latest
環境設定
為了示範不同型別的掛載,首先需要在 AWS 上建立一個由一個管理節點和兩個工作節點組成的 Docker Swarm,用於演示卷掛載。對於繫結掛載,則需要在 CoreOS 例項上建立一個由一個管理節點和兩個工作節點組成的 Swarm。
使用掛載(Using Mounts)
建立命名卷(Creating a Named Volume)
在使用Docker Swarm時,掛載卷(mounts)是持久化資料或在容器之間分享資料的重要方式。首先,我們需要建立一個命名卷(named volume)。命名卷可以事先建立,也可以在佈署服務時自動建立。使用以下命令建立命名卷:
docker volume create [OPTIONS] [VOLUME]
建立並檢查命名卷
~ $ docker volume create --name hello
hello
建立命名卷後,可以使用docker volume ls命令列出所有卷:
~ $ docker volume ls
DRIVER VOLUME NAME
local hello
進一步,可以使用docker volume inspect命令檢查命名卷的詳細資訊:
~ $ docker volume inspect hello
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/hello/_data",
"Name": "hello",
"Options": {},
"Scope": "local"
}
]
命名卷選項
建立命名卷時,可以使用多個選項,如下表所示:
| 選項 | 描述 | 型別 | 預設值 |
|---|---|---|---|
| –driver, -d | 指定卷驅動程式名稱 | string | local |
| –label | 為卷設定後設資料 | value | [] |
| –name | 指定卷名稱 | string | |
| –opt, -o | 為驅動程式設定特定選項 | value | map[] |
使用卷掛載(Using a Volume Mount)
在建立服務時,可以使用--mount選項指定命名卷。例如,使用剛建立的hello卷和tutum/hello-world映象建立服務:
docker service create --name hello-service --mount src=hello,dst=/path/in/container tutum/hello-world
卷掛載選項
以下是一些常用的掛載選項:
| 選項 | 是否必填 | 描述 | 預設值 |
|---|---|---|---|
| type | 否 | 指定掛載型別(volume、bind、tmpfs) | volume |
| src 或 source | type=bind時必填,type=volume時可選 | 指定來源目錄或卷名稱 | |
| dst 或 destination 或 target | 是 | 指定容器內的掛載路徑 | |
| readonly 或 ro | 否 | 指定是否以唯讀方式掛載 |
對於卷掛載,還有額外的選項可用,如下表所示:
| 選項 | 是否必填 | 描述 | 預設值 |
|---|---|---|---|
| volume-driver | 否 | 指定用於建立命名卷的驅動程式名稱 | local |
| volume-label | 否 | 為卷設定後設資料標籤 | |
| volume-nocopy | 否 | 指定是否將容器內的檔案複製到卷中 | true 或 1 |
| volume-opt | 否 | 為建立命名卷提供額外的選項 |
使用命名卷建立服務
使用以下命令建立一個服務,並將hello命名卷掛載到容器內:
docker service create --name hello-service --mount type=volume,src=hello,dst=/container/path,volume-label="label-1=hello-world" tutum/hello-world
詳細解說
docker service create: 這個命令用於建立一個新的服務。--name hello-service: 指定服務的名稱為hello-service。--mount: 指定掛載選項。type=volume: 指定掛載型別為卷。src=hello: 指定來源卷名稱為hello。如果該卷不存在,將自動建立。dst=/container/path: 指定容器內的掛載路徑為/container/path。volume-label="label-1=hello-world": 為卷新增標籤"label-1=hello-world"。
tutum/hello-world: 指定用於建立服務的Docker映象。
使用掛載(Mounts)於 Docker Swarm 服務
Docker Swarm 提供了靈活的掛載選項,讓你可以將資料持久化並在服務之間分享。本章將探討如何在 Docker Swarm 服務中使用掛載功能,包括命名卷(Named Volumes)和匿名卷(Anonymous Volumes)。
建立帶有命名卷的服務
首先,我們來建立一個使用命名卷的服務。以下範例建立了一個名為 hello-world 的服務,並將命名卷 hello 掛載到容器內的 /hello 目錄。
docker service create \
--name hello-world \
--mount src=hello,dst=/hello,volume-label="msg=hello",volume-label="msg2=world" \
--publish 8080:80 \
--replicas 2 \
tutum/hello-world
內容解密:
docker service create: 建立一個新的 Docker Swarm 服務。--name hello-world: 指定服務名稱為hello-world。--mount src=hello,dst=/hello,...: 將命名卷hello掛載到容器內的/hello目錄,並為該卷新增標籤msg=hello和msg2=world。--publish 8080:80: 將主機的 8080 埠對映到容器的 80 埠。--replicas 2: 指定服務執行 2 個副本。
執行上述命令後,Docker 將建立服務並輸出服務 ID。
在佈署時建立命名卷
在另一個範例中,我們在建立服務時動態建立命名卷 nginx-root,並將其掛載到 Nginx 容器的 /var/lib/nginx 目錄。
docker service create \
--name nginx-service \
--replicas 3 \
--mount type=volume,source="nginx-root",destination="/var/lib/nginx",volume-label="type=nginx root dir" \
nginx:alpine
內容解密:
--mount type=volume,source="nginx-root",destination="/var/lib/nginx": 指定掛載型別為volume,來源為nginx-root,目標為/var/lib/nginx。volume-label="type=nginx root dir": 為nginx-root卷新增標籤。
如果 nginx-root 卷不存在,Docker 將在建立服務時自動建立它,並且只會在執行任務的節點上建立該卷。
省略命名卷名稱
在某些情況下,你可以省略命名卷的名稱,讓 Docker 自動生成一個名稱。
docker service create \
--name nginx-service-2 \
--replicas 3 \
--mount type=volume,destination=/var/lib/nginx \
nginx:alpine
內容解密:
--mount type=volume,destination=/var/lib/nginx: 省略了source引數,Docker 將自動生成一個命名卷。
每個執行任務的節點都會建立一個自動生成的命名卷。
為 MySQL 資料函式庫服務建立命名卷
最後,我們來為 MySQL 資料函式庫服務建立一個命名卷 mysql-scripts。
docker volume create --name mysql-scripts
建立後,可以透過以下命令檢視已建立的命名卷:
docker volume ls
內容解密:
docker volume create --name mysql-scripts: 手動建立一個名為mysql-scripts的命名卷。docker volume ls: 列出所有可用的命名卷。