Docker Swarm部署集群
- 2020 年 3 月 5 日
- 筆記
一、Swarm簡介
Swarm是Docker的一個編排工具,參考官網:https://docs.docker.com/engine/swarm/
Swarm 模式簡介
- 要在Swarm模式下運行docker,需要先安裝docker,參考安裝教程
- 當前版本的docker包含了swarm模式,用於管理docker集群。可以使用命令行來創建swarm集群,部署應用,管理swarm的行為。
如果你使用低於1.12.0版本的docker,可以使用獨立模式的是swarm,但是建議使用最新版本
特性
- 與docker集成的集群管理工具
- 去中心化設計,只使用docker引擎即可創建各類節點
- 聲明式服務模型。可以聲明的方式來定義應用。
- 動態伸縮。管理節點自動調整服務數量。
- 高可用,對於服務期望狀態做到動態調整,swarm的管理節點會持續監控集群狀態,集群中有沒有達到期望狀態的服務,管理節點會自動調度來達到期望狀態。
- 自定義網絡。可以為你的服務指定一個網絡,容器創建的時候分配一個IP
- 服務發現。管理節點給集群中每個服務一個特定的DNS名字,並給運行的容器提供負載均衡。
- 負載均衡。你可以暴露服務端口給外部的負載均衡。內部swarm提供可配置的容器分配到節點的策略。
- 默認的安全機制。swarm集群中各個節點強制TLS協議驗證。連接加密,你可以自定義根證書。
滾動更新。增量跟新,可以自定義更新下個節點的時間間隔,如果有問題,可以會滾到上個版本。
二、安裝Swarm
本教程進行如下指導:
- 在swarm模式下初始化一個基於docker引擎的swarm集群
- 在swarm集群中添加節點
- 部署應用服務到swarm集群中
- 管理swarm集群
本教程使用docker命令行的方式交互
安裝
安裝環境要求
- 3台可以網絡通信的Linux主機,並且安裝了docker
- 安裝1.12.0以上的docker
- 管理節點的IP地址
- 主機之間開放端口
準備3台主機
- 3台主機可以是物理機,虛擬機,雲主機,甚至是docker machine創建的主機。並安裝docker。三台主機分別是manager1,work1和worker2. 安裝1.12.0以上的docker
- 參考:在linux上安裝docker
- 管理節點的IP地址
- 所有swarm集群中的節點都會連接到管理節點的IP地址 主機間開放端口
- 以下端口必須是開放的:
- TCP port 2377為集群管理通信
- TCP and UDP port 7946 為節點間通信
- UDP port 4789 為網絡間流量
- 如果你想使用加密網絡(–opt encrypted)也需要確保ip protocol 50 (ESP)是可用的
環境說明
操作系統 |
主機名 |
ip地址 |
docker版本 |
---|---|---|---|
ubuntu-16.04.4-server-amd64 |
manager1 |
192.168.10.104 |
Docker version 18.09.2 |
ubuntu-16.04.4-server-amd64 |
work1 |
192.168.10.108 |
Docker version 18.09.2 |
ubuntu-16.04.4-server-amd64 |
work2 |
192.168.10.110 |
Docker version 18.09.2 |
創建一個Swarm集群
完成上面的開始過程後,可以開始創建一個swarm集群。確保docker的後台應用已經在主機上運行了。
登陸到manager1上,如果使用docker-machine創建的主機,可以docker-machine ssh manager1
運行以下命令來創建一個新的swarm集群:
docker swarm init --advertise-addr <MANAGER1-IP>
MANAGER1-IP 表示管理節點
本教程中使用如下命令在manager1上創建swarm集群:

root@manager1:~# docker swarm init --advertise-addr 192.168.10.104 Swarm initialized: current node (zmvmswnwv6jcvjt1tmq65zzkg) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-4q7uby9b9vjrjryrvl9r7kgq23hx0y6nwmdt3b9kmxpfcn7vmu-97op3d7nkn8rp31e0boz0308w 192.168.10.104:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

- –advertise-addr 選項表示管理節點公布它的IP是多少。其它節點必須能通過這個IP找到管理節點。
- 命令輸出了加入swarm集群的命令。通過–token選項來判斷是加入為管理節點還是工作節點
1. 運行docker info來查看當前swarm集群的狀態:
root@manager1:~# docker -v Docker version 18.09.2, build 6247962 root@manager1:~# docker info Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 18.09.2 Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: active NodeID: zmvmswnwv6jcvjt1tmq65zzkg Is Manager: true ClusterID: 04doas9mydex8aq4vadh0b0go Managers: 1 Nodes: 1 Default Address Pool: 10.0.0.0/8 SubnetSize: 24 Orchestration: Task History Retention Limit: 5 Raft: Snapshot Interval: 10000 Number of Old Snapshots to Retain: 0 Heartbeat Tick: 1 Election Tick: 10 Dispatcher: Heartbeat Period: 5 seconds CA Configuration: Expiry Duration: 3 months Force Rotate: 0 Autolock Managers: false Root Rotation In Progress: false Node Address: 192.168.10.104 Manager Addresses: 192.168.10.104:2377 Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 9754871865f7fe2f4e74d43e2fc7ccd237edcbce runc version: 09c8266bf2fcf9519a651b04ae54c967b9ab86ec init version: v0.18.0 (expected: fec3683b971d9c3ef73f284f176672c44b448662) Security Options: apparmor seccomp Profile: default Kernel Version: 4.4.0-116-generic Operating System: Ubuntu 16.04.4 LTS OSType: linux Architecture: x86_64 CPUs: 1 Total Memory: 3.859GiB Name: manager1 ID: 7N32:4Z4C:V5JN:L4I4:PR3K:KRN7:RR6M:MYR6:TBYG:EB5C:MDTA:CRTY Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Live Restore Enabled: false WARNING: No swap limit support
運行docker node ls來查看節點信息
root@manager1:~# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zmvmswnwv6jcvjt1tmq65zzkg * manager1 Ready Active Leader 18.09.2
- nodeId 旁邊的*號表示你當前連接到的節點。
- docker引擎的swarm模式自動使用宿主機的主機名作為節點名。
將節點加入到swarm集群中
一旦前面的創建swarm集群完成,你就可以加入工作節點了。
ssh到要加入集群的節點上,我們要加入worker1.
運行創建swarm集群時候產生的命令來將woker1加入到集群中:
root@work1:~# docker swarm join --token SWMTKN-1-4q7uby9b9vjrjryrvl9r7kgq23hx0y6nwmdt3b9kmxpfcn7vmu-97op3d7nkn8rp31e0boz0308w 192.168.10.104:2377 This node joined a swarm as a worker.
如果你找不到加入命令了,可以在管理節點運行下列命令找回加入命令:
root@manager1:~# docker swarm join-token worker To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-4q7uby9b9vjrjryrvl9r7kgq23hx0y6nwmdt3b9kmxpfcn7vmu-97op3d7nkn8rp31e0boz0308w 192.168.10.104:2377
ssh到worker2 運行加入集群的命令來將worker2加入到集群:
root@worker2:~# docker swarm join --token SWMTKN-1-4q7uby9b9vjrjryrvl9r7kgq23hx0y6nwmdt3b9kmxpfcn7vmu-97op3d7nkn8rp31e0boz0308w 192.168.10.104:2377 This node joined a swarm as a worker.
ssh到manager1節點運行docker node ls命令來查看集群節點情況:
root@manager1:~# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zmvmswnwv6jcvjt1tmq65zzkg * manager1 Ready Active Leader 18.09.2 pi6ori8t1tuestb3hzhnn265v work1 Ready Active 18.09.2 ohivom1sdi1vz1oaer1b9wpl0 work2 Ready Active 18.09.2
MANAGER列表明了集群中的管理節點。worker節點的空意味着它們是工作節點
三、部署服務
在創建一個swarm集群後,就可以部署服務了。本教程中你也可以加入工作節點,但是不是必須的。
ssh到manager1節點 運行如下命令:
root@manager1:~# docker service create --replicas 1 --name helloworld alpine ping docker.com qf8qydwuah1ym9xj5yxrxvhak overall progress: 1 out of 1 tasks 1/1: running verify: Service converged
- docker service create用來創建服務
- –name表明服務名字是helloworld
- –replicas 表示期望1個服務實例
- alpine ping docker.com 表示運行鏡像是alpine,命令是ping
運行docker service ls來查看運行的服務:
root@manager1:~# docker service lsID NAME MODE REPLICAS IMAGE PORTS qf8qydwuah1y helloworld replicated 1/1 alpine:latest
四、檢查服務
在你部署服務到Swarm集群上後,可以使用命令行來檢查運行的服務
ssh到管理節點 運行命令docker service inspect –pretty <ID> 來查看優化顯示的服務詳情
root@manager1:~# docker service inspect --pretty qf8qydwuah1y ID: qf8qydwuah1ym9xj5yxrxvhak 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: alpine:latest@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb Args: ping docker.com Init: false Resources: Endpoint Mode: vip
去掉–pretty選項將以json格式輸出
運行docker service ps <ID> 將查看到哪些節點在運行該服務實例:
root@manager1:~# docker service ps qf8qydwuah1y ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 6u05btfqzo6j helloworld.1 alpine:latest manager1 Running Running 5 minutes ago
- 服務可能運行在管理或工作節點上,默認的管理節點可以像工作節點一樣運行任務。
- 該命令也顯示服務期望的狀態DESIRED STATE ,和實際的狀態CURRENT STATE。
在運行任務的節點上運行docker ps也能看到這個任務運行的容器。備註:目前運行在manager1上面
root@manager1:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 236ed4a13f7a alpine:latest "ping docker.com" 6 minutes ago Up 6 minutes helloworld.1.6u05btfqzo6j4mo4uxm5543mi
五、動態伸縮服務實例數
一旦你在swarm集群中部署一個服務後,你就可以使用命令行來改變服務的實例個數。在服務中運行的容器稱為「任務」
語法:
docker service scale <ID>=數量
ssh到manager1節點 運行以下命令來改變服務的期望實例數:

root@manager1:~# docker service scale qf8qydwuah1y=3qf8qydwuah1y scaled to 3overall progress: 3 out of 3 tasks 1/3: running 2/3: running 3/3: running verify: Service converged

運行以下命令來查看更新的任務列表:
root@manager1:~# docker service ls ID NAME MODE REPLICAS IMAGE PORTS qf8qydwuah1y helloworld replicated 3/3 alpine:latest root@manager1:~# docker service ps qf8qydwuah1y ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 6u05btfqzo6j helloworld.1 alpine:latest manager1 Running Running 10 minutes ago m96ohuz60dw4 helloworld.2 alpine:latest work1 Running Running about a minute ago 9dldkulmsvwj helloworld.3 alpine:latest work2 Running Running about a minute ago
可以看到這3個任務被分佈到了集群中的不同節點
ssh到運行服務的主機work1上運行docker ps查看運行的容器:
root@work1:~# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES fafaa17a2c6a alpine:latest "ping docker.com" 2 minutes ago Up 2 minutes helloworld.2.m96ohuz60dw4twr9np4kd8hz3
六、刪除應用
接下來刪除應用
ssh到管理節點 運行docker service rm <ID>來刪除服務:

root@manager1:~# docker service ls ID NAME MODE REPLICAS IMAGE PORTS qf8qydwuah1y helloworld replicated 3/3 alpine:latest root@manager1:~# docker service rm qf8qydwuah1yqf8qydwuah1y root@manager1:~# docker service ls ID NAME MODE REPLICAS IMAGE PORTS

運行docker service inspect <ID>會發現服務不存在了
root@manager1:~# docker service inspect qf8qydwuah1y [] Status: Error: no such service: qf8qydwuah1y, Code: 1
儘管服務不存在了,任務容器還需要幾秒鐘來清理,你可以在節點上docker ps查看任務什麼時候被移除。
七、滾動更新
在前面的章節中,修改了實例數。本節使用etcd:2.0.5 鏡像來部署服務,然後滾動升級到etcd:2.0.10
ssh到管理節點 部署etcd:2.0.5 服務,配置10s的更新間隔:

root@manager1:~# docker service create --replicas 2 --name etcd --update-delay 10s elcolio/etcd:2.0.5 vh7w3mq5q0vc634w8x6m8r3m6 overall progress: 2 out of 2 tasks 1/2: running 2/2: running verify: Service converged

- 注意:教程使用的是redis鏡像,我使用的是etcd鏡像拉
- 在服務部署階段就指定滾動升級策略
- –update-delay配置了更新服務的時間間隔,你可以指定時間T為秒是Ts,分是Tm,或時是Th,所以10m30s就是10分30秒的延遲
- 默認的調度器scheduler一次更新一個任務.你可以傳入參數–update-parallelism來配置調度器同時更新的最大任務數量
- 默認的當一個更新任務返回RUNNING狀態後,調度器才調度另一個更新任務,直到所有任務都更新了。如果更新過程中任何任務返回了FAILED,調度器就會停止更新。你可以給命令docker service create or docker service update配置配置–update-failure-action,來配置這個行為。
查看etcd服務
root@manager1:~# docker service inspect --pretty etcd ID: vh7w3mq5q0vc634w8x6m8r3m6 Name: etcd Service Mode: Replicated Replicas: 2 Placement: UpdateConfig: Parallelism: 1 Delay: 10s 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: elcolio/etcd:2.0.5@sha256:fa9c5bdfd7164b75d944da3693d891e1fd18c7c757bbb5c00caa99aef312a428 Init: false Resources: Endpoint Mode: vip
現在可以更新etcd的容器鏡像了,語法:
docker service update --image <鏡像名> <服務名>
運行以下命令,swarm的管理節點將會根據更新策略UpdateConfig來更新各個節點:

root@manager1:~# docker service update --image elcolio/etcd:2.0.10 etcd etcd overall progress: 2 out of 2 tasks 1/2: running 2/2: running verify: Service converged

調度器依照以下步驟來滾動更新:
- 停止第一個任務
- 對停止的任務進行更新
- 對更新的任務進行啟動
- 如果更新的任務返回RUNNING,等待特定間隔後啟動下一個任務
- 如果在任何更新的時間,任務返回了FAILED,則停止更新。
運行命令docker service inspect –pretty etcd來查看新鏡像的期望狀態,可以看到顯示了UpdateStatus完成。
root@manager1:~# docker service inspect --pretty etcd ID: vh7w3mq5q0vc634w8x6m8r3m6 Name: etcd Service Mode: Replicated Replicas: 2 UpdateStatus: State: completed Started: 2 minutes ago Completed: About a minute ago Message: update completed Placement: UpdateConfig: Parallelism: 1 Delay: 10s 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: elcolio/etcd:2.0.10@sha256:9a2e9a6ad26ddd87204b248c38d18b397881fc16283e4ac4ed5bfbf2ce03fa4c Init: false Resources: Endpoint Mode: vip
如果中間有升級失敗的,則會顯示如下信息:

$ docker service inspect --pretty etcd ID: 0u6a4s31ybk7yw2wyvtikmu50 Name: redis ...snip... Update status: State: paused Started: 11 seconds ago Message: update paused due to failure or early termination of task 9p7ith557h8ndf0ui9s0q951b ...snip...

- 重新開始一個升級過程:docker service update
- 為了避免重複失敗升級,要重新配置服務服務,添加適當的參數在運行docker service update
運行docker service ps <服務名>來查看本次滾動更新的過程:

root@manager1:~# docker service ps etcd ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS nzwtsi4p8stw etcd.1 elcolio/etcd:2.0.10 work1 Running Running 3 minutes ago lom9z7y8rlps _ etcd.1 elcolio/etcd:2.0.5 work1 Shutdown Shutdown 3 minutes ago 8h8xjzyhlq1a etcd.2 elcolio/etcd:2.0.10 manager1 Running Running 3 minutes ago 6hpxbv34jnfz _ etcd.2 elcolio/etcd:2.0.5 manager1 Shutdown Shutdown 3 minutes ago

注意升級後老的容器只是停止了,並沒有刪除

root@manager1:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e905f60e2ec3 elcolio/etcd:2.0.10 "/bin/run.sh" 4 minutes ago Up 4 minutes 2379-2380/tcp, 4001/tcp, 7001/tcp etcd.2.8h8xjzyhlq1a7o5wu5tfqq17z 13886eb8ea94 elcolio/etcd:2.0.5 "/bin/run.sh" 7 minutes ago Exited (137) 4 minutes ago etcd.2.6hpxbv34jnfz0bjl1yx4xnwdd b0963cce9bf3 elcolio/etcd:2.0.5 "/bin/run.sh /bin/ba…" 12 minutes ago Exited (130) 11 minutes ago hopeful_feistel

八、從集群中下線一個節點
- 前面的教程中管理節點會把任務分配給ACTIVE的節點,所有ACTIVE的節點都能接到任務
- 有時候,例如特定的維護時間,我們就需要從集群中下線一個節點。下線節點使節點不會接受新任務,管理節點會停止該節點上的任務,分配到別的ACTIVE的節點上。
- 注意:下線一個節點不移除節點中的獨立容器,如docker run,docker-compose up或docker API啟動的容器都不會刪除。節點的狀態僅影響集群服務的負載是否分到該節點。
ssh到manageer1 運行docker node ls,驗證所有節點都是ACTIVE的:

root@manager1:~# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zmvmswnwv6jcvjt1tmq65zzkg * manager1 Ready Active Leader 18.09.2pi6ori8t1tuestb3hzhnn265v work1 Ready Active 18.09.2ohivom1sdi1vz1oaer1b9wpl0 work2 Ready Active 18.09.2

如果弄的etcd服務還沒有從滾動更新中起來,需要啟動起來: 運行docker service ps etcd查看管理節點如何分配任務到不同節點:

root@manager1:~# docker service ps etcd ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS nzwtsi4p8stw etcd.1 elcolio/etcd:2.0.10 work1 Running Running 6 minutes ago lom9z7y8rlps _ etcd.1 elcolio/etcd:2.0.5 work1 Shutdown Shutdown 6 minutes ago 8h8xjzyhlq1a etcd.2 elcolio/etcd:2.0.10 manager1 Running Running 6 minutes ago 6hpxbv34jnfz _ etcd.2 elcolio/etcd:2.0.5 manager1 Shutdown Shutdown 6 minutes ago

運行docker node update –availability drain <NODE>來下線一個節點:
root@manager1:~# docker node update --availability drain manager1 manager1
運行以下來檢查節點的可用性: 可以看到該節點的可用性是Drain

root@manager1:~# docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zmvmswnwv6jcvjt1tmq65zzkg * manager1 Ready Drain Leader 18.09.2pi6ori8t1tuestb3hzhnn265v work1 Ready Active 18.09.2ohivom1sdi1vz1oaer1b9wpl0 work2 Ready Active 18.09.2

docker node inspect –pretty manager1
root@manager1:~# docker node inspect --pretty manager1 ID: zmvmswnwv6jcvjt1tmq65zzkg Hostname: manager1 Joined at: 2019-08-24 12:11:37.150001136 +0000 utc Status: State: Ready Availability: Drain Address: 192.168.10.104 Manager Status: Address: 192.168.10.104:2377 Raft Status: Reachable Leader: Yes Platform: Operating System: linux Architecture: x86_64 Resources: CPUs: 1 Memory: 3.859GiB Plugins: Log: awslogs, fluentd, gcplogs, gelf, journald, json-file, local, logentries, splunk, syslog Network: bridge, host, macvlan, null, overlay Volume: local Engine Version: 18.09.2 TLS Info: TrustRoot: -----BEGIN CERTIFICATE----- MIIBajCCARCgAwIBAgIUHwOd2JFLTCBePSGfOYdPvomygdEwCgYIKoZIzj0EAwIw EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTkwODI0MTIwNzAwWhcNMzkwODE5MTIw NzAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABDQ1v1QxJoRfkoo6hWcKkYD6ixGtd/YCnTVuqOcpyh97dQ3qVPUIEJoafORt 5yQCu8mLOCH1mWrXjA2yVo/Z6DqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBT3zbMseoYHkZ60+VhVDGn1qdv4njAKBggqhkjO PQQDAgNIADBFAiA/nXEN/f6wpUtOWwUBDNAXlKmhp7j+MjfD84+ksu+JEgIhAL6O ZYp25KHMOGQaVWDPJZIzObWofJvxFwE4hHRkbCaH -----END CERTIFICATE----- Issuer Subject: MBMxETAPBgNVBAMTCHN3YXJtLWNh Issuer Public Key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENDW/VDEmhF+SijqFZwqRgPqLEa139gKdNW6o5ynKH3t1DepU9QgQmhp85G3nJAK7yYs4IfWZateMDbJWj9noOg==
運行docker service ps etcd來查看管理節點是如何重新分配任務的: 可以看到管理節點將下線節點的任務停止了,為了保障副本數量,重新在active的節點上調度了任務。

root@manager1:~# docker service ps etcd ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS nzwtsi4p8stw etcd.1 elcolio/etcd:2.0.10 work1 Running Running 9 minutes ago lom9z7y8rlps _ etcd.1 elcolio/etcd:2.0.5 work1 Shutdown Shutdown 9 minutes ago 31x8luhz56zn etcd.2 elcolio/etcd:2.0.10 work2 Running Running about a minute ago 8h8xjzyhlq1a _ etcd.2 elcolio/etcd:2.0.10 manager1 Shutdown Shutdown about a minute ago 6hpxbv34jnfz _ etcd.2 elcolio/etcd:2.0.5 manager1 Shutdown Shutdown 9 minutes ago

運行docker node update –availability active <NODE>來重新active該節點:
root@manager1:~# docker node update --availability active manager1 manager1
查看節點狀態,可以看到節點狀態重新為Active
root@manager1:~# docker node inspect --pretty manager1 ID: zmvmswnwv6jcvjt1tmq65zzkg Hostname: manager1 Joined at: 2019-08-24 12:11:37.150001136 +0000 utc Status: State: Ready Availability: Active Address: 192.168.10.104 Manager Status: Address: 192.168.10.104:2377 Raft Status: Reachable Leader: Yes Platform: Operating System: linux Architecture: x86_64 Resources: CPUs: 1 Memory: 3.859GiB Plugins: Log: awslogs, fluentd, gcplogs, gelf, journald, json-file, local, logentries, splunk, syslog Network: bridge, host, macvlan, null, overlay Volume: local Engine Version: 18.09.2 TLS Info: TrustRoot: -----BEGIN CERTIFICATE----- MIIBajCCARCgAwIBAgIUHwOd2JFLTCBePSGfOYdPvomygdEwCgYIKoZIzj0EAwIw EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTkwODI0MTIwNzAwWhcNMzkwODE5MTIw NzAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH A0IABDQ1v1QxJoRfkoo6hWcKkYD6ixGtd/YCnTVuqOcpyh97dQ3qVPUIEJoafORt 5yQCu8mLOCH1mWrXjA2yVo/Z6DqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBT3zbMseoYHkZ60+VhVDGn1qdv4njAKBggqhkjO PQQDAgNIADBFAiA/nXEN/f6wpUtOWwUBDNAXlKmhp7j+MjfD84+ksu+JEgIhAL6O ZYp25KHMOGQaVWDPJZIzObWofJvxFwE4hHRkbCaH -----END CERTIFICATE----- Issuer Subject: MBMxETAPBgNVBAMTCHN3YXJtLWNh Issuer Public Key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENDW/VDEmhF+SijqFZwqRgPqLEa139gKdNW6o5ynKH3t1DepU9QgQmhp85G3nJAK7yYs4IfWZateMDbJWj9noOg==
當節點重新active的時候,在以下情況下它會重新接受任務:
- 當一個服務縮容擴容時
- 在滾動更新的時候
- 當另一個節點Drain下線的時候
- 當一個任務在另一個active節點上運行失敗的時候
九、使用swarm模式的路由網絡
- docker的swarm模式使服務暴露給外部端口更加方便。所有的節點都在一個路由網絡里。這個路由網絡使得集群內的所有節點都能在開放的端口上接受請求。即使節點上沒有任務運行,這個服務的端口也暴露的。路由網絡路由所有的請求到暴露端口的節點上。
- 前提是需要暴露以下端口來使節點間能通信
- Port 7946 TCP/UDP for container network discovery.用於容器間網絡發現
- Port 4789 UDP for the container ingress network.用於容器進入網絡
- 你也必須開放節點之間的公開端口,和任何外部資源端口,例如一個外部的負載均衡。
- 你也可以使特定服務繞過路由網絡
為一個服務暴露端口
使用–publish來在創建一個服務的時候暴露端口。target指明容器內暴露的端口。published指明綁定到路由網絡上的端口。如果不寫published,就會為每個服務綁定一個隨機的高數字端口。你需要檢查任務才能確定端口
先刪除etcd,再重新部署etcd,指定映射端口,查看進程
root@manager1:~# docker service rm etcd etcd root@manager1:~# docker service create --name etcd --publish published=2379,target=2379 --replicas 1 elcolio/etcd:2.0.10 0xej3ym93411svulph7f5l0m0 overall progress: 1 out of 1 tasks 1/1: running verify: Service converged root@manager1:~# docker service ps etcd ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS tqmgklo7fbmb etcd.1 elcolio/etcd:2.0.10 manager1 Running Running 14 seconds ago
- 注意舊版的語法是冒號分開的published:target,例如 -p 8080:80。新語法更易讀且靈活。
- 當你在任何節點訪問8080端口時,路由網絡將把請求分發到一個active的容器中。在各個節點,8080端口可能並沒有綁定,但是路由網絡知道如何路由流量,並防止任何端口衝突。
- 路由網絡監聽各個節點的IP上的 published port 。從外面看,這些端口是各個節點暴露的。對於別的IP地址,只在該主機內可以訪問。

https://docs.docker.com/engine/swarm/images/ingress-routing-mesh.png
你可以用以下命令給一個已經存在的服務暴露端口

root@manager1:~# docker service ls ID NAME MODE REPLICAS IMAGE PORTS 0xej3ym93411 etcd replicated 1/1 elcolio/etcd:2.0.10 *:2379->2379/tcp root@manager1:~# root@manager1:~# docker service update --publish-add published=20379,target=2379 etcd etcd overall progress: 1 out of 1 tasks 1/1: running verify: Service converged

你可以使用docker service inspect來查看服務暴露的端口:
root@manager1:~# docker service inspect --format="{{json .Endpoint.Spec.Ports}}" etcd [{"Protocol":"tcp","TargetPort":2379,"PublishedPort":20379,"PublishMode":"ingress"},{"Protocol":"tcp","TargetPort":2379,"PublishedPort":2379,"PublishMode":"ingress"}]
- The output shows the (labeled TargetPort) from the containers and the (labeled PublishedPort) where nodes listen for requests for the service.
訪問etcd api,查看版本
使用命令:docker service ps etcd 得知etcd運行在manager1,因此訪問地址為:
root@manager1:~# curl http://192.168.10.104:20379/version etcd 2.0.10
僅暴露一個TCP或UDP端口
注意:這部分內容出現的命令,不需要執行
默認你暴露的端口都是TCP的。如果你使用長語法(Docker 1.13 and higher),設置protocol為tcp或udp即可暴露相應端口
僅TCP
長語法 $ docker service create --name dns-cache --publish published=53,target=53 dns-cache 短語法 $ docker service create --name dns-cache -p 53:53 dns-cache
TCP和UDP
長語法 $ docker service create --name dns-cache --publish published=53,target=53 --publish published=53,target=53,protocol=udp dns-cache 短語法 $ docker service create --name dns-cache -p 53:53 -p 53:53/udp dns-cache
只暴露UDP
長語法 $ docker service create --name dns-cache --publish published=53,target=53,protocol=udp dns-cache 短語法 $ docker service create --name dns-cache -p 53:53/udp dns-cache
繞過路由網絡
- 你可以繞過路由網絡,直接和一個節點上的端口通信,來訪問服務。這叫做Host模式:
- 如果該節點上沒有服務運行,服務也沒有監聽端口,則可能無法通信。
- 你不能在一個節點上運行多個服務實例他們綁定同一個靜態target端口。或者你讓docker分配隨機高數字端口(通過空配置target),或者確保該節點上只運行一個服務實例(通過配置全局服務global service 而不是副本服務,或者使用配置限制)。
- 為了繞過路由網絡,必須使用長格式–publish,設置模式mode為host模式。如果你忽略了mode設置或者設置為內網ingress,則路由網絡將啟動。下面的命令創建了全局應用使用host模式繞過路由網絡:
$ docker service create --name dns-cache --publish published=53,target=53,protocol=udp,mode=host --mode global dns-cache
十、配置外部的負載均衡
- 你可以為swarm集群配置外部的負載均衡,或者結合路由網絡使用或者完全不使用: 使用路由網絡
- 你可以使用一個外部的HAProxy來負載均衡,服務是8080端口上的nginx服務:

- 在這個例子中負載均衡器和集群節點之間的8080端口必須是開放的。swarm集群節點在一個外部不可訪問的內網中,節點可以與HAProxy通信。
- 你可以配置負載均衡器分流請求到不同的集群節點,即使節點上沒有服務運行。例如你可以如下配置HAProxy:/etc/haproxy/haproxy.cfg:
安裝haproxy
由於機器資源不夠,這裡在manager1節點,安裝haproxy
apt-get install -y haproxy
配置haproxy
vim /etc/haproxy/haproxy.cfg
最後一行添加
# Configure HAProxy to listen on port 80 frontend http_front bind *:80 stats uri /haproxy?stats default_backend http_back # Configure HAProxy to route requests to swarm nodes on port 8080 backend http_back balance roundrobin server node1 192.168.10.104:2379 check server node2 192.168.10.108:2379 check server node3 192.168.10.110:2379 check
- 當你請求HAProxy的80端口的時候,它會轉發請求到後端節點。swarm的路由網絡會路由到相應的服務節點。這樣無論任何原因swarm的調度器調度服務到不同節點,都不需要重新配置負載均衡。
- 你可以配置任何類型的負載均衡來分流請求。關於HAProxy參考 HAProxy documentation
- 不使用路由網絡
- 如果不使用路由網絡,配置–endpoint-mode的值為dnsrr,而不是vip。在本例子中沒有一個固定的虛擬IP。Docker為服務做了DNS註冊,這樣一個服務的DNS查詢會返回一系列IP地址。客戶端就可以直接連接其中一個節點。你負責提供這一系列的IP地址,開放端口給你的負載均衡器。參考Configure service discovery.
重新加載配置
service haproxy reload
訪問haproxy
http://192.168.10.104/haproxy?stats
效果如下:

可以發現3台node的Act狀態為Y,表示活躍。
訪問etcd api的版本
http://192.168.10.104/version
效果如下:

本文參考鏈接:
https://www.cnblogs.com/drawnkid/p/8487337.html