Swarm 是 Docker 引擎內建(原生)的叢集管理和編排工具
學習 swarm 一定要理解的幾個重要概念
節點
服務
任務
節點
一臺物理或雲主機加入 docker 叢集,那麼這臺主機就是一個節點。
節點分為管理 (manager) 節點和工作 (worker) 節點。
管理節點用於叢集的管理,一個 Swarm 叢集可以有多個管理節點,但只有一個管理節點可以成為 leader。
工作節點是任務執行節點,管理節點將服務 (service) 下發至工作節點執行。
管理節點預設也作為工作節點。你也可以通過配置讓工作節點只進行任務排程。
Docker 官網的這張圖片形象的展示了叢集中管理節點與工作節點的關係。
任務和服務
任務 (Task)是 Swarm 中的最小的排程單位,目前來說就是一個單一的容器。任務包含一個 Docker 容器和在容器中執行的命令。
服務 (Services) 是指一組任務的集合,服務定義了任務的屬性。服務有兩種模式:
replicated services(副本模式) 按照一定規則在各個工作節點上執行指定個數的任務。
global services(全域性模式) 每個工作節點上執行一個任務
兩種模式通過 docker service create 的 –mode 引數指定。
swarm 叢集基本操作
三臺安裝了 Docker 的主機,各主機間可以通訊。
Docker 版本必須大於 1.12
需要開啟 tcp 2377 埠、tcp/udp 7946 埠、udp 4789 埠
選一臺主機作為管理節點,獲取其 ip 地址
docker-machine
Docker Machine 是 Docker 官方提供的一個工具,它可以幫助我們在遠端的機器上安裝 Docker,或者在虛擬機器 host 上直接安裝虛擬機器並在虛擬機器中安裝 Docker。我們還可以通過 docker-machine 命令來管理這些虛擬機器和 Docker。
安裝 docker-machine
首先下載可執行檔案 github.com/docker/machine/releases
將下載好的檔案移動到
/usr/local/bin/docker-machine
目錄下並改名為 docker-machine執行
sudo chmod +x /usr/local/bin/docker-machine
命令為其新增可執行許可權執行如下命令,驗證是否安裝成功
$ docker-machine -v
docker-machine version 0.16.1, build cce350d7
初始化叢集
第一步:如下命令建立 一個 Docker 主機作為管理節點。
$ docker-machine create -d virtualbox manager
由於眾所周知的原因下載 boot2docker 特別慢,我們通過 boot2docker 專案頁面直接下載該檔案,然後將該檔案移動到該 /Users/使用者名稱/.docker/machine/cache
目錄下。最後重新執行建立的命令就可以了
第二步:在管理節點上初始化一個 swarm 叢集
// ssh 到虛擬機器中
$ docker-machine ssh manager
// 初始化 swarm 叢集,並指定管理節點 ip 地址
docker@manager:~$ docker swarm init --advertise-addr 192.168.99.100
Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c
192.168.99.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
執行 docker swarm init 命令的節點自動成為管理節點。
第三步:建立工作節點,並加入 swarm 叢集
worker 1
$ docker-machine create -d virtualbox worker1
$ docker-machine ssh worker1
// 工作節點初始化叢集的時候會自動給出該命令。
docker@worker1:~$ docker swarm join
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c
192.168.99.100:2377
This node joined a swarm as a worker.
通過該 docker swarm join-token worker
命令獲取加入叢集的命令
worker2
$ docker-machine create -d virtualbox worker2
$ docker-machine ssh worker2
docker@worker1:~$ docker swarm join
--token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c
192.168.99.100:2377
This node joined a swarm as a worker.
第四步:檢視節點狀態
// 該命令只能在管理節點使用
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
jnn6cji3hy22ninkymqxer49q * manager Ready Active Leader 19.03.12
r5sce06gn9351jvotf6xp1r53 worker1 Ready Active 19.03.12
ssdfsdfs2df32dfk34dc3498 worker1 Ready Active 19.03.12
Docker 引擎通過主機名自動為節點命名
MANAGER 列標識群中的管理器節點。Leader 表示管理節點,空表示工作節點
部署一個服務
$ docker service create --replicas 1 --name helloworld busybox ping baidu.com
wo27l49vowb7reote7apzqn8d
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
–preplicas 1 指定副本個數為 1 個(即在叢集中啟動一個容器執行)
–name 指定服務名稱為 helloworld
busybox 指定映象為 busybox
ping baidu.com 指定執行的命令
檢視當前執行的服務
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
wo27l49vowb7 helloworld replicated 1/1 busybox:latesttcp
檢視服務詳情
$ docker service inspect --pretty helloworld
ID: wo27l49vowb7reote7apzqn8d
Name: helloworld
Service Mode: Replicated
Replicas: 1
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
RollbackConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Rollback order: stop-first
ContainerSpec:
Image: busybox:latest@sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
Args: ping baidu.com
Init: false
Resources:
Endpoint Mode: vip
- –pretty 以更好看的格式顯示(不指定的話將以 json 格式顯示)
檢視服務執行在哪個接點上
docker@manager:~$ docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
re3rdqvnsoa3 helloworld.1 busybox:latest worker1 Running Running 11 minutes ago
我們可以看到該服務執行在 worker1 節點上。讓我們 ssh 到 worker1 節點執行 docker ps 命令,發現確實有容器在執行。而我們 ssh 到其他節點上執行 docker ps 會發現並沒有容器在執行。
擴充套件叢集中的服務
必須在管理節點操作
$ docker service scale helloworld=5
helloworld 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
$ docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
re3rdqvnsoa3 helloworld.1 busybox:latest worker1 Running Running about an hour ago
4tjmgtulmkx0 helloworld.2 busybox:latest worker2 Running Running 38 minutes ago
zl3u08rsrm72 helloworld.3 busybox:latest manager Running Running 38 minutes ago
am36krqw6o97 helloworld.4 busybox:latest manager Running Running 39 minutes ago
tsbhagfz6fx6 helloworld.5 busybox:latest worker1 Running Running 39 minutes ago
我們可以看到新增加了 4 個任務分佈在manager、worker1、worker2 上。
ssh 到各個主機執行
docker ps
檢視主機執行容器的狀態
刪除叢集中的服務
必須在管理節點操作
$ docker service rm helloworld
helloworld
docker@manager:~$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
其他主機需要等一會再檢視執行的容器是否刪除
動態升級服務
建立一個低版本的 redis 服務
$ docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
vep8ciixn4otmt9g0khd98z5d
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
–update-delay 設定更新任務之間的延遲時間(20h10m5s 表示延遲為 20 小時 10 分鐘 5 表)
–update-parallelism 設定同時更新任務的最大數(預設值為 1)
–update-failure-action 設定更新任務失敗後執行的動作(預設設定為如果在更新過程中的任何時候任務返回失敗,則排程程式將暫停更新)
更新 redis
$ docker service update --image redis:3.0.7 redis
上面的命令實際執行流程為:
暫停第一個任務
為停止的任務安排更新計劃
啟動一個新版本的容器
如果任務的返回“RUNNING”,則等待指定的延遲時間後開始下一個任務
如果任務返回“FAILED”,則暫停更新。
檢視當前服務狀態
可以看出服務的更新是暫停老版本,增加新版本
docker@manager:~$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
jbojkid2itrn redis.1 redis:3.0.7 worker2 Running Running 3 minutes ago
r4nyfe94e5ms \_ redis.1 redis:3.0.6 worker2 Shutdown Shutdown 3 minutes ago
t8umvvy4bf80 redis.2 redis:3.0.7 manager Running Running 2 minutes ago
rhunef6vi2dk \_ redis.2 redis:3.0.6 manager Shutdown Shutdown 3 minutes ago
w2jcya0tc9cv redis.3 redis:3.0.7 worker1 Running Running 2 minutes ago
sz1ptkhmak6q \_ redis.3 redis:3.0.6 worker1 Shutdown Shutdown 2 minutes ago
設定節點為 Drain 狀態
目前我們的所有節點都為 Active 狀態,也就是所有節點都可以接受任務。但有時候我們想指定某個節點正在維護,不進行任務處理,那麼我們就要對節點的狀態進行更改。
// 為了後面檢視方便,刪除上面進行建立的 redis 服務
$ docker service rm redis
//重新建立一個 redis 服務
$ docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
// 檢視當前服務執行狀態(每個節點執行一個任務)
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ffhwf4i243yc redis.1 redis:3.0.6 worker2 Running Running 35 seconds ago
sflv38rtetvh redis.2 redis:3.0.6 manager Running Running 35 seconds ago
kzn7cn15rrye redis.3 redis:3.0.6 worker1 Running Running 35 seconds ago
// 將 worker1 節點設為 Drain 狀態
$ docker node update --availability drain worker1
worker1
// 檢視當前服務執行狀態(注意 worker1 節點服務的狀態已經為關閉,worker2 節點上又多了一個任務)
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ffhwf4i243yc redis.1 redis:3.0.6 worker2 Running Running about a minute ago
sflv38rtetvh redis.2 redis:3.0.6 manager Running Running about a minute ago
ir0nvesyhrea redis.3 redis:3.0.6 worker2 Running Running less than a second ago
kzn7cn15rrye \_ redis.3 redis:3.0.6 worker1 Shutdown Shutdown less than a second ago
Routing Mesh (路由網格)
Routing Mesh 是 docker swarm 提供的確保服務在多節點網路上可用的叢集網路機制。
當我們建立一個服務的時候,如果將埠釋出出來,那麼所有節點都會加入到這個路由網格中,當我們在外部通過任意主機 ip 和釋出的埠訪問服務的時候,無論該主機上時候啟動服務,我們都能訪問的到。(負載均衡)
在使用之前需要先開啟如下埠:
TCP/UDP 的 7946 埠
UDP 的 4789 埠
格式:
docker service create
--name <SERVICE-NAME>
--publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT>
<IMAGE>
SERVICE-NAME 自定義服務的名稱
PUBLISHED-PORT 對外發布的埠號
CONTAINER-PORT 容器的埠號
IMAGE 服務所使用的映象
啟動 nginx 服務併發布埠
$ docker service create --name web --publish published=8080,target=80 --replicas 2 nginx
// 檢視服務當前執行在哪個節點上
$ docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
kuocqhmt4rl7 web.1 nginx:latest worker1 Running Running 40 seconds ago
s3ybcckxdrnb web.2 nginx:latest manager Running Running 40 seconds ago
// 檢視當前所有節點
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
3px1nw94x2wmnr0k7846hpksh * manager Ready Active Leader 19.03.12
ibhxsuf055peywhawgp7hslav worker1 Ready Active 19.03.12
ny1e3wd4l7enyh0pp547azefe worker2 Ready Active 19.03.12
各節點 ip 地址
manager 192.168.99.100
worker1 192.168.99.101
worker2 192.168.99.102
訪問各個節點
我們發現即使 worker2 節點沒有執行 nginx 容器,但我們依然可以通過 worker2 節點訪問釋出的服務。
對已存在的服務釋出埠
docker service update
--publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT>
<SERVICE>
繞過 Routing Mesh
不具體講解了,沒有想到實際的應用場景。
$ docker service create --name dns-cache
--publish published=53,target=53,protocol=udp,mode=host
--mode global
dns-cache
服務全域性模式(global service)
上面的各種示例都是基於副本模式,下面開始全域性模式。
$ docker service create
--mode global
--publish mode=host,target=80,published=8080
--name=nginx
nginx:latest
使用上面的命令可以在當前的每個工作節點啟動一個 nginx 容器,這時如果有一個節點掛掉了,那麼並不會在其他節點重啟啟動一個新的容器。而如果我們這時在新增一個新的節點,那麼當這個新的節點加入 swarm 叢集的時候,該節點也會自動啟動一個 nginx 容器。
overlay 網路
該網路可以連線 swarm 叢集中的一個或多個服務
建立 overlay 網路
$ docker network create --driver overlay my-network
建立服務的時候加入 overlay 網路
$ docker service create --replicas 3 --network my-network --name my-web nginx
將現有的服務加入 overlay 網路
$ docker service update --network-add my-network my-web
將現有服務從 overlay 網路中斷開
$ docker service update --network-rm my-network my-web
在 Swarm 叢集中管理敏感資料
建立 secret
格式:docker secret create <secret-name> <file-name>
$ printf "This is a secret" | docker secret create my_secret_data -
因為我們通過讀取標準輸入的方式,所以最後使用 - 標記
建立一個 redis 服務並授權方位 secret
$ docker service create --name redis --secret my_secret_data redis:alpine
預設情況下,容器可以通過 /run/secrets/<secret_name>
路徑訪問金鑰。或者可以使用 target 選項自定義容器上的檔名。
檢視當前服務執行狀態
$ docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
bp0ylcmxw6ll redis.1 redis:alpine worker1 Running Running about a minute ago
驗證 secret
// 根據上面檢視的資料,進入 worker1 容器
$ docker-machine ssh worker1
// 獲取 worker1 容器執行的 redis 服務
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aa049d4173e1 redis:alpine "docker-entrypoint.s…" 8 minutes ago Up 8 minutes 6379/tcp redis.1.bp0ylcmxw6llv9icvhgrk189f
// 進入 redis 容器
$ docker exec -it redis.1.bp0ylcmxw6llv9icvhgrk189f sh
//在容器中檢視 secret
# cat /run/secrets/my_secret_data
This is a secret
使用中的 secret 無法刪除
// 進入 manager 節點
$ docker-machine ssh manager
$ docker secret rm my_secret_data
Error response from daemon: rpc error: code = InvalidArgument desc = secret 'my_secret_data' is in use by the following service: redis
docker@manager:~$
通過更新的方式刪除 secret
$ docker service update --secret-rm my_secret_data redis
redis
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
刪除服務和 secret
$ docker service rm redis
$ docker secret rm my_secret_data
在 Swarm 叢集中管理非敏感資料(配置)
使用方式與 secret 相似
docker 17.06引入了swarm service configs。允許你在服務映像或執行容器之外儲存非敏感資訊
注意:config 僅能在 Swarm 叢集中使用。
建立 config
// 建立一個名為 redis.conf 的檔案,內容為 port:6380
$ cat redis.conf
port 6380
// 建立 config
$ docker config create redis.conf redis.conf
$ docker config ls
ID NAME CREATED UPDATED
fkamdbup3egw8752bm4ixrsm2 redis.conf 23 minutes ago 23 minutes ago
跟 secret 使用類似
建立 redis 服務並授權其方位 config
$ docker service create
--name redis
--config redis.conf
--publish published=6379,target=6380
redis:latest
redis-server /redis.conf
或顯式的指定路徑
$ docker service create
--name redis
--config source=redis.conf,target=/etc/redis.conf
--publish published=6379,target=6380
redis:latest
redis-server /etc/redis.conf
以上兩種建立服務的方法都可以
驗證 config
使用 redis 管理工具連線 redis,連結地址填寫 192.168.99.100
使用中的 config 無法刪除
$ docker config rm redis.conf
Error response from daemon: rpc error: code = InvalidArgument desc = config 'redis.conf' is in use by the following service: redis
通過更新的方式刪除 config
docker service update --config-rm redis.conf redis
docker config rm redis.conf
redis.conf
移除 redis 服務
$ docker service rm redis
本作品採用《CC 協議》,轉載必須註明作者和本文連結