在講解使用 Docker Stack 部署應用之前,有幾個前置處理需要完成。
? Swarm 模式:應用將采用 Docker Stack 部署,而 Stack 依賴 Swarm 模式。
? 標簽:某個 Swarm worker 節點需要自定義標簽。
? 密鑰:應用所需的密鑰需要在部署前創建完成。
接下來的講解中會完成基于 Linux 的三節點 Swarm 集群搭建,同時能滿足上面應用的全部前置依賴。完成之后,實驗環境如下圖所示。
接下來內容分為 3 個步驟。
? 創建新的 Swarm。
? 添加節點標簽。
? 創建密鑰。
首先創建新的三節點 Swarm 集群。
⒈ 初始化 Swarm
在任意 Swarm 管理節點的機器上,運行下面的命令。
$ docker swarm init
Swarm initialized: current node (lhma...w4nn) is now a manager.
<Snip>
⒉ 添加工作節點
復制前面輸出中出現的 docker swarm join 命令。將復制內容粘貼到工作節點上并運行。
//Worker 1 (wrk-1)
wrk-1$ docker swarm join --token SWMTKN-1-2hl6...-...3lqg 172.31.40.192:2377
This node joined a swarm as a worker.
//Worker 2 (wrk-2)
wrk-2$ docker swarm join --token SWMTKN-1-2hl6...-...3lqg 172.31.40.192:2377
This node joined a swarm as a worker.
⒊ 確認當前 Swarm 由一個管理節點和兩個工作節點構成
在管理節點中運行下面的命令。
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
lhm...4nn * mgr-1 Ready Active Leader
b74...gz3 wrk-1 Ready Active
o9x...um8 wrk-2 Ready Active
Swarm 集群目前就緒。payment_gateway 服務配置了部署約束,限制該服務只能運行在有 pcidss=yes 標簽的工作節點之上。本步驟中將在 wrk-1 上添加該節點標簽。
在實際操作中,添加該標簽之前必須將某個 Docker 節點按 PCI 規范進行標準化。但是,這只是一個實驗環境,所以就暫且跳過這一過程,直接將標簽添加到 wrk-1 節點。
在 Swarm 管理節點運行下面的命令。
⒈ 添加節點標簽到 wrk-1
$ docker node update --label-add pcidss=yes wrk-1
Node 標簽只在 Swarm 集群之內生效。
⒉ 確認節點標簽
$ docker node inspect wrk-1
[
{
"ID": "b74rzajmrimfv7hood6l4lgz3",
"Version": {
"Index": 27
},
"CreatedAt": "2018-01-25T10:35:18.146831621Z",
"UpdatedAt": "2018-01-25T10:47:57.189021202Z",
"Spec": {
"Labels": {
"pcidss": "yes"
},
<Snip>
wrk-1 工作節點現在已經配置完成,所以該節點可以運行 payment_gateway 服務副本了。
應用定義了 4 個密鑰,這些都需要在應用部署前創建。
postgress_password。
staging_token。
revprox_cert。
revprox_key。
在管理節點運行下面的命令,來創建這些密鑰。
⒈ 創建新的鍵值對
密鑰中有 3 個是需要加密 key 的。在本步驟中會創建加密 key,下一步會將加密 key 放到 Docker 密鑰文件當中。
$ openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout domain.key -x509 -days 365 -out domain.crt
⒉ 創建 revprox_cert、revprox_key 以及 postgress_password 密鑰
$ docker secret create revprox_cert domain.crt
cqblzfpyv5cxb5wbvtrbpvrrj
$ docker secret create revprox_key domain.key
jqd1ramk2x7g0s2e9ynhdyl4p
$ docker secret create postgres_password domain.key
njpdklhjcg8noy64aileyod6l
⒊ 創建 stage_token 密鑰
$ echo staging | docker secret create staging_token -
sqy21qep9w17h04k3600o6qsj
⒋ 列出所有密鑰
$ docker secret ls
ID NAME CREATED UPDATED
njp...d6l postgres_password 47 seconds ago 47 seconds ago
cqb...rrj revprox_cert About a minute ago About a minute ago
jqd...l4p revprox_key About a minute ago About a minute ago
sqy...qsj staging_token 23 seconds ago 23 seconds ago
上面已經完成了全部的前置準備。是時候開始部署應用了!
如果還沒有代碼,請先復制應用的 GitHub 倉庫到 Swarm 管理節點。
$ git clone https://github.com/dockersamples/atsea-sample-shop-app.git
Cloning into 'atsea-sample-shop-app'...
remote: Counting objects: 636, done.
Receiving objects: 100% (636/636), 7.23 MiB | 3.30 MiB/s, done. remote:
Total 636 (delta 0), reused 0 (delta 0), pack-reused 636 Resolving
deltas: 100% (197/197), done.
Checking connectivity... done.
$ cd atsea-sample-shop-app
現在已經擁有了源碼,可以開始部署應用了。
Stack 通過docker stack deploy 命令完成部署。基礎格式下,該命令允許傳入兩個參數。
? Stack 文件的名稱。
? Stack 的名稱。
應用的 GitHub 倉庫中包含一個名為 docker-stack.yml 的 Stack 文件。這里會使用該文件。這里為 Stack 起名 seastack。
在 Swarm 管理節點的 atsea-sample-shop-app 目錄下運行下面的命令。
$ docker stack deploy -c docker-stack.yml seastack
Creating network seastack_default
Creating network seastack_back-tier
Creating network seastack_front-tier
Creating network seastack_payment
Creating service seastack_database
Creating service seastack_appserver
Creating service seastack_visualizer
Creating service seastack_payment_gateway
Creating service seastack_reverse_proxy
可以運行 docker network ls 以及 docker service ls 命令來查看應用的網絡和服務情況。
下面是命令輸出中幾個需要注意的地方。
網絡是先于服務創建的。這是因為服務依賴于網絡,所以網絡需要在服務啟動前創建。
Docker 將 Stack 名稱附加到由他創建的任何資源名稱前作為前綴。在本例中,Stack 名為 seastack,所以所有資源名稱的格式都如:seastack_。例如,payment 網絡的名稱是 seastack_payment。而在部署之前創建的資源則沒有被重命名,比如密鑰。
另一個需要注意的點是出現了新的名為 seastack_default 的網絡。該網絡并未在Stack文件中定義,那為什么會創建呢?每個服務都需要連接到網絡,但是 visualizer 服務并沒有指定具體的網絡。因此,Docker 創建了名為 seastack_default 的網絡,并將 visualizer 連接到該網絡。
可以通過兩個命令來確認當前 Stack 的狀態。docker stack ls 列出了系統中全部 Stack,包括每個 Stack 下面包含多少服務。docker stack ps <stack-name> 針對某個指定 Stack 展示了更詳細的信息,例如期望狀態以及當前狀態。下面一起來了解下這兩條命令。
$ docker stack ls
NAME SERVICES
Seastack 5
$ docker stack ps seastack
NAME NODE DESIRED STATE CURRENT STATE
seastack_reverse_proxy.1 wrk-2 Running Running 7 minutes ago
seastack_payment_gateway.1 wrk-1 Running Running 7 minutes ago
seastack_visualizer.1 mgr-1 Running Running 7 minutes ago
seastack_appserver.1 wrk-2 Running Running 7 minutes ago
seastack_database.1 wrk-2 Running Running 7 minutes ago
seastack_appserver.2 wrk-1 Running Running 7 minutes ago
在服務啟動失敗時,docker stack ps 命令是首選的問題定位方式。該命令展示了 Stack 中每個服務的概況,包括服務副本所在節點、當前狀態、期望狀態以及異常信息。從下面的輸出信息中能看出 reverse_proxy 服務在 wrk-2 節點上兩次嘗試啟動副本失敗。
$ docker stack ps seastack
NAME NODE DESIRED CURRENT ERROR
STATE STATE
reverse_proxy.1 wrk-2 Shutdown Failed "task: non-zero exit (1)"
\_reverse_proxy.1 wrk-2 Shutdown Failed "task: non-zero exit (1)"
如果想查看具體某個服務的詳細信息,可以使用 docker service logs 命令。讀者需要將服務名稱 /ID 或者副本 ID 作為參數傳入。如果傳入服務名稱或 ID,可以看到所有服務副本的日志信息。如果傳入的是副本 ID,則只會看到對應副本的日志信息。
下面的 docker service logs 命令展示了 seastack_reverse_proxy 服務的全部副本日志,其中包含了前面輸出中的兩次副本啟動失敗的日志。
#1host not found#1host not found
輸出內容為了適應頁面展示,已經經過裁剪,但是還是可以看到全部 3 個服務副本的日志(兩個啟動失敗,1 個正在運行)。每行的開始都是副本的名稱,包括服務名稱、副本序號、副本 ID 以及副本所在主機的名稱。接下來是具體的日志輸出。
提示:大家可能已經注意到前面日志中全部副本的序號都是 1。這是因為 Docker 每次只創建一個副本,并且只有當前面的副本啟動失敗時才會創建新的。
因為輸出內容經過裁剪,所以具體原因很難明確,但看起來前兩次副本啟動失敗原因是其依賴的某個服務仍然在啟動中(一種啟動時服務間依賴導致的競爭條件)。
可以繼續跟蹤日志(--follow),查看日志尾部內容(--tail),或者獲取額外的詳細信息(--details)。