深度优先

这个家伙好懒,除了文章什么都没留下

0%

【Docker】Swarm从部署到基本操作

原文地址:https://www.cnblogs.com/drawnkid/p/8487337.html

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模式

  • 本教程进行如下指导:
    • 在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
管理节点的IP地址
  • 所有swarm集群中的节点都会连接到管理节点的IP地址
主机间开放端口
  • 以下端口必须是开放的:
    • TCP port 2377为集群管理通信
    • TCP and UDP port 7946 为节点间通信
    • UDP port 4789 为网络间流量
  • 如果你想使用加密网络(--opt encrypted)也需要确保ip protocol 50 (ESP)是可用的

创建一个Swarm集群

  • 完成上面的开始过程后,可以开始创建一个swarm集群。确保docker的后台应用已经在主机上运行了。
  1. 登陆到manager1上,如果使用docker-machine创建的主机,可以docker-machine ssh manager1
  2. 运行以下命令来创建一个新的swarm集群:
1
2
docker swarm init --advertise-addr <MANAGER1-IP>

  • 本教程中使用如下命令在manager1上创建swarm集群:
1
2
3
4
5
6
7
8
9
james@james-CW65:~ > docker swarm init --advertise-addr 192.168.99.1
Swarm initialized: current node (5n1l6261akogeuxysrgn2ipxz) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-2bgkinnbc0rmlj6kpotyrlj0uz51l2ikinttsk960dxro558x4-6zajfnahtv9ye39momddh5kru 192.168.99.1: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集群的状态:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
james@james-CW65:~ > docker info
Containers: 4
Running: 2
Paused: 0
Stopped: 2
Images: 7
Server Version: 17.12.0-ce
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 37
Dirperm1 Supported: 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 logentries splunk syslog
Swarm: active
NodeID: 5n1l6261akogeuxysrgn2ipxz
Is Manager: true
ClusterID: nhkp9f1l5yq76e0zu0bage2h4
Managers: 1
Nodes: 1
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot Interval: 10000
Number of Old Snapshots to Retain: 0
Heartbeat Tick: 1
Election Tick: 3
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.99.1
Manager Addresses:
192.168.99.1:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 89623f28b87a6004d4b785663257362d1658a729
runc version: b2567b37d7b75eb4cf325b77297b140ea686ce8f
init version: 949e6fa
Security Options:
apparmor
Kernel Version: 3.19.0-32-generic
Operating System: Ubuntu 14.04.3 LTS
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 3.755GiB
Name: james-CW65
ID: EMVF:D3TL:KMEY:2QTR:HESQ:J5ZA:WDYM:GSEV:INSU:Z4QI:DCIX:LMGK
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

  1. 运行docker node ls来查看节点信息:
1
2
3
4
james@james-CW65:~ > docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
5n1l6261akogeuxysrgn2ipxz * james-CW65 Ready Active Leader

  • nodeId旁边的*号表示你当前连接到的节点。
  • docker引擎的swarm模式自动使用宿主机的主机名作为节点名。

将节点加入到swarm集群中

  • 一旦前面的创建swarm集群完成,你就可以加入工作节点了。
  1. ssh到要加入集群的节点上,我们要加入worker1.
  2. 运行创建swarm集群时候产生的命令来将woker1加入到集群中:
1
2
3
4
docker@default:~$ docker swarm join --token SWMTKN-1-2bgkinnbc0rmlj6kpotyrlj0uz51l2ikinttsk960dxro558x4-6zajfnahtv9ye39momd
dh5kru 192.168.99.1:2377
This node joined a swarm as a worker.

  • 如果你找不到加入命令了,可以在管理节点运行下列命令找回加入命令:
1
2
3
4
5
james@james-CW65:~ > docker swarm join-token worker
To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-2bgkinnbc0rmlj6kpotyrlj0uz51l2ikinttsk960dxro558x4-6zajfnahtv9ye39momddh5kru 192.168.99.1:2377

  1. ssh到worker2
  2. 运行加入集群的命令来将worker2加入到集群:
1
2
3
4
5
6
Boot2Docker version 17.12.0-ce, build HEAD : 378b049 - Wed Dec 27 23:39:20 UTC 2017
Docker version 17.12.0-ce, build c97c6d6
docker@lab:~$ docker swarm join --token SWMTKN-1-2bgkinnbc0rmlj6kpotyrlj0uz51l2ikinttsk960dxro558x4-6zajfnahtv9ye39momddh5k
ru 192.168.99.1:2377
This node joined a swarm as a worker.

  1. ssh到manager节点运行docker node ls命令来查看集群节点情况:
1
2
3
4
5
6
james@james-CW65:~ > docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
k89s71elf81vbn7pytwszmgr5 default Ready Active
5n1l6261akogeuxysrgn2ipxz * james-CW65 Ready Active Leader
ye5x8hci1chmo8nyjx8y4thhy lab Ready Active

  • MANAGER列表明了集群中的管理节点。worker节点的空意味着它们是工作节点

在swarm集群上部署一个服务

  • 在创建一个swarm集群后,就可以部署服务了。本教程中你也可以加入工作节点,但是不是必须的。
  1. ssh到manager节点
  2. 运行如下命令:
1
2
3
4
5
6
james@james-CW65:~ > docker service create --replicas 1 --name helloworld alpine ping docker.com
060zo3u0g3mjdmrilezzbckbe
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
  1. 运行docker service ls来查看运行的服务:
1
2
3
4
james@james-CW65:~ > docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
060zo3u0g3mj helloworld replicated 1/1 alpine:latest

检查Swarm集群上的服务

  • 在你部署服务到Swarm集群上后,可以使用命令行来检查运行的服务
  1. ssh到管理节点
  2. 运行命令docker service inspect --pretty 来查看优化显示的服务详情
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
james@james-CW65:~ > docker service inspect --pretty 060zo3u0g3mj

ID: 060zo3u0g3mjdmrilezzbckbe
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:7b848083f93822dd21b0a2f14a110bd99f6efb4b838d499df6d04a49d0debf8b
Args: ping docker.com
Resources:
Endpoint Mode: vip

  • 去掉--pretty选项将以json格式输出
  1. 运行docker service ps 将查看到哪些节点在运行该服务实例:
1
2
3
4
james@james-CW65:~ > docker service ps  060zo3u0g3mj
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
cbiq1ne3ij9a helloworld.1 alpine:latest james-CW65 Running Running 9 minutes ago

  • 服务可能运行在管理或工作节点上,默认的管理节点可以像工作节点一样运行任务。
  • 该命令也显示服务期望的状态DESIRED STATE ,和实际的状态CURRENT STATE。
  1. 在运行任务的节点上运行docker ps也能看到这个任务运行的容器
1
2
3
4
james@james-CW65:~ > docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cad59e7398de alpine:latest "ping docker.com" 2 minutes ago Up 2 minutes helloworld.1.ngbknb89dzyxdas81emw0jz63

在swarm集群中动态伸缩服务实例数

  • 一旦你在swarm集群中部署一个服务后,你就可以使用命令行来改变服务的实例个数。在服务中运行的容器称为“任务”
  1. ssh到manager节点
  2. 运行以下命令来改变服务的期望实例数:
1
2
3
4
5
6
7
8
9
james@james-CW65:~ > docker service scale 060zo3u0g3mj=3
060zo3u0g3mj scaled to 3
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Waiting 1 seconds to verify that tasks are stable...
verify: Service converged

  1. 运行以下命令来查看更新的任务列表:
1
2
3
4
5
6
7
8
9
10
james@james-CW65:~ > docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
060zo3u0g3mj helloworld replicated 3/3 alpine:latest
james@james-CW65:~ > docker service ps 060zo3u0g3mj
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ngbknb89dzyx helloworld.1 alpine:latest james-CW65 Running Running 9 minutes ago
cbiq1ne3ij9a \_ helloworld.1 alpine:latest james-CW65 Shutdown Failed 9 minutes ago "task: non-zero exit (1)"
3fl3mfrvubu1 helloworld.2 alpine:latest default Running Running about a minute ago
hy5pqcmqfw67 helloworld.3 alpine:latest lab Running Running about a minute ago

  • 可以看到这3个任务被分布到了集群中的不同节点
  1. ssh到运行服务的主机上运行docker ps查看运行的容器:
1
2
3
4
docker@default:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cad897086027 alpine:latest "ping docker.com" 4 minutes ago Up 4 minutes helloworld.2.3fl3mfrvubu1hf16argabe5qt

从swarm集群上删除应用

  • 接下来删除应用
  1. ssh到管理节点
  2. 运行docker service rm helloworld来删除服务:
1
2
3
4
5
6
7
8
james@james-CW65:~ > docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
060zo3u0g3mj helloworld replicated 3/3 alpine:latest
james@james-CW65:~ > docker service rm 060zo3u0g3mj
060zo3u0g3mj
james@james-CW65:~ > docker service ls
ID NAME MODE REPLICAS IMAGE PORTS

  1. 运行docker service inspect 会发现服务不存在了
1
2
3
4
james@james-CW65:~ > docker service inspect  060zo3u0g3mj
[]
Status: Error: no such service: 060zo3u0g3mj, Code: 1

  1. 尽管服务不存在了,任务容器还需要几秒钟来清理,你可以在节点上docker ps查看任务什么时候被移除。

滚动更新

  • 在前面的章节中,修改了实例数。本节使用Ghost0.11.12 镜像来部署服务,然后滚动升级到Ghost1.21.3
  1. ssh到管理节点
  2. 部署Ghost0.11.12 服务,配置10s的更新间隔:
1
2
3
4
5
6
7
james@james-CW65:~ > docker service create --replicas 2 --name ghost --update-delay 10s ghost:0.11.12
tynb9d9pu0nqm7f1vmmffy9j0
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged

  • 注意:教程使用的是redis镜像,我使用的是Ghost博客镜像,拉
  • 在服务部署阶段就指定滚动升级策略
  • --update-delay配置了更新服务的时间间隔,你可以指定时间T为秒是Ts,分是Tm,或时是Th,所以10m30s就是10分30秒的延迟
  • 默认的调度器scheduler一次更新一个任务.你可以传入参数--update-parallelism来配置调度器同时更新的最大任务数量
  • 默认的当一个更新任务返回RUNNING状态后,调度器才调度另一个更新任务,直到所有任务都更新了。如果更新过程中任何任务返回了FAILED,调度器就会停止更新。你可以给命令docker service create or docker service update配置配置--update-failure-action,来配置这个行为。
  1. 查看redis服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
james@james-CW65:~ > docker service inspect --pretty ghost

ID: tynb9d9pu0nqm7f1vmmffy9j0
Name: ghost
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: ghost:0.11.12@sha256:45811b5a50254bdf0a05d683ddf1dd9eb1be98640305fb82317bcaa35a00c20e
Resources:
Endpoint Mode: vip

  1. 现在可以更新redis的容器镜像了。运行以下命令,swarm的管理节点将会根据更新策略UpdateConfig来更新各个节点:
1
2
3
4
5
6
7
james@james-CW65:~ > docker service update --image ghost:1.21.3 ghost
ghost
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged

  • 调度器依照以下步骤来滚动更新:
    • 停止第一个任务
    • 对停止的任务进行更新
    • 对更新的任务进行启动
    • 如果更新的任务返回RUNNING,等待特定间隔后启动下一个任务
    • 如果在任何更新的时间,任务返回了FAILED,则停止更新。
  1. 运行命令docker service inspect --pretty redis来查看新镜像的期望状态,可以看到显示了UpdateStatus完成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
james@james-CW65:~ > docker service  inspect  --pretty ghost

ID: tynb9d9pu0nqm7f1vmmffy9j0
Name: ghost
Service Mode: Replicated
Replicas: 2
UpdateStatus:
State: completed
Started: 2 minutes ago
Completed: 2 minutes 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: ghost:1.21.3@sha256:4c8868f41180589583e6eb208a8529ca8dad3d18bddf56834740b715f3e6b691
Resources:
Endpoint Mode: vip
james@james-CW65:~ >

  • 如果中间有升级失败的,则会显示如下信息:
1
2
3
4
5
6
7
8
9
10
11
$ docker service inspect --pretty redis

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
  1. 运行docker service ps 来查看本次滚动更新的过程:
1
2
3
4
5
6
7
8
james@james-CW65:~ > docker service ps ghost
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
5ae8hwemegrg ghost.1 ghost:1.21.3 james-CW65 Running Running 54 seconds ago
akwqfsarjvy1 \_ ghost.1 ghost:0.11.12 james-CW65 Shutdown Shutdown 54 seconds ago
hzzq00ckovdg ghost.2 ghost:1.21.3 default Running Running 41 seconds ago
ivtd60xuggk0 \_ ghost.2 ghost:0.11.12 default Shutdown Shutdown 42 seconds ago
james@james-CW65:~ >

  • 注意升级后老的容器只是停止了,并没有删除
1
2
3
4
5
docker@default:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f855c00da7b7 ghost:1.21.3 "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 2368/tcp ghost.2.hzzq00ckovdgb48373lwn8xp6
c151f3535a3b ghost:0.11.12 "docker-entrypoint.s…" 32 minutes ago Exited (0) 6 minutes ago ghost.2.ivtd60xuggk0y56oguehtirni

从集群中下线一个节点

  • 前面的教程中管理节点会把任务分配给ACTIVE的节点,所有ACTIVE的节点都能接到任务
  • 有时候,例如特定的维护时间,我们就需要从集群中下线一个节点。下线节点使节点不会接受新任务,管理节点会停止该节点上的任务,分配到别的ACTIVE的节点上。
  • 注意:下线一个节点不移除节点中的独立容器,如docker run,docker-compose up或docker API启动的容器都不会删除。节点的状态仅影响集群服务的负载是否分到该节点。
  1. ssh到manageer1
  2. 运行docker node ls,验证所有节点都是ACTIVE的:
1
2
3
4
5
james@james-CW65:~ > docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
k89s71elf81vbn7pytwszmgr5 default Ready Active
5n1l6261akogeuxysrgn2ipxz * james-CW65 Ready Active Leader

  1. 如果弄的redis服务还没有从滚动更新中起来,需要启动起来:
  2. 运行docker service ps redis查看管理节点如何分配任务到不同节点:
1
2
3
4
5
6
7
james@james-CW65:~ > docker service ps ghost
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
5ae8hwemegrg ghost.1 ghost:1.21.3 james-CW65 Running Running 19 minutes ago
akwqfsarjvy1 \_ ghost.1 ghost:0.11.12 james-CW65 Shutdown Shutdown 19 minutes ago
hzzq00ckovdg ghost.2 ghost:1.21.3 default Running Running 19 minutes ago
ivtd60xuggk0 \_ ghost.2 ghost:0.11.12 default Shutdown Shutdown 19 minutes ago

  1. 运行docker node update --availability drain 来下线一个节点:
1
2
3
james@james-CW65:~ > docker node update --availability drain default
default

  1. 运行以下来检查节点的可用性:
  • 可以看到该节点的可用性是Drain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
james@james-CW65:~ > docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
k89s71elf81vbn7pytwszmgr5 default Ready Drain
5n1l6261akogeuxysrgn2ipxz * james-CW65 Ready Active Leader
james@james-CW65:~ > docker node inspect --pretty default
ID: k89s71elf81vbn7pytwszmgr5
Hostname: default
Joined at: 2018-02-28 06:25:23.718220559 +0000 utc
Status:
State: Ready
Availability: Drain
Address: 192.168.99.100
Platform:
Operating System: linux
Architecture: x86_64
Resources:
CPUs: 1
Memory: 995.9MiB
Plugins:
Log: awslogs, fluentd, gcplogs, gelf, journald, json-file, logentries, splunk, syslog
Network: bridge, host, macvlan, null, overlay
Volume: local
Engine Version: 17.12.0-ce
Engine Labels:
- provider=virtualbox
TLS Info:
TrustRoot:
-----BEGIN CERTIFICATE-----
MIIBajCCARCgAwIBAgIUJdysIbjEKr/Xr+SvWKd8S0UpgqcwCgYIKoZIzj0EAwIw
EzERMA8GA1UEAxMIc3dhcm0tY2EwHhcNMTgwMjI4MDYwNDAwWhcNMzgwMjIzMDYw
NDAwWjATMREwDwYDVQQDEwhzd2FybS1jYTBZMBMGByqGSM49AgEGCCqGSM49AwEH
A0IABFgzZnc/77Zo87KKNrJK83z6ASk1YNHwXYWQvfnyf5aqhLUuOOdGXMgvEj5s
GHGkNitCK2y11XQdSzsRQE5JsGKjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBSaliomGnuL2p+xndnzrIfncS9TezAKBggqhkjO
PQQDAgNIADBFAiA8c7Qn3OA62I4APdAqzwK8z4rNgJug7Nheuo7pOOBybgIhAM5W
t2NvL1EBMjCQZGRk45W/X0C2UN2NQ+cA7CVBHh7I
-----END CERTIFICATE-----

Issuer Subject: MBMxETAPBgNVBAMTCHN3YXJtLWNh
Issuer Public Key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWDNmdz/vtmjzsoo2skrzfPoBKTVg0fBdhZC9+fJ/lqqEtS4450ZcyC8SPmwYcaQ2K0IrbLXVdB1LOxFATkmwYg==

  1. 运行docker service ps redis来查看管理节点是如何重新分配任务的:
  • 可以看到管理节点将下线节点的任务停止了,为了保障副本数量,重新在active的节点上调度了任务。
1
2
3
4
5
6
7
8
james@james-CW65:~ > docker service ps ghost
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
5ae8hwemegrg ghost.1 ghost:1.21.3 james-CW65 Running Running 21 minutes ago
akwqfsarjvy1 \_ ghost.1 ghost:0.11.12 james-CW65 Shutdown Shutdown 21 minutes ago
lefwcfo1s44k ghost.2 ghost:1.21.3 james-CW65 Running Running 22 seconds ago
hzzq00ckovdg \_ ghost.2 ghost:1.21.3 default Shutdown Shutdown 22 seconds ago
ivtd60xuggk0 \_ ghost.2 ghost:0.11.12 default Shutdown Shutdown 21 minutes ago

  1. 运行docker node update --availability active 来重新active该节点:
1
2
3
4
5
6
7
james@james-CW65:~ > docker node update --availability active default
default
james@james-CW65:~ > docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
k89s71elf81vbn7pytwszmgr5 default Ready Active
5n1l6261akogeuxysrgn2ipxz * james-CW65 Ready Active Leader

  1. 查看节点状态,可以看到节点状态重新为ACtive:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
james@james-CW65:~ > docker node inspect --pretty default
ID: k89s71elf81vbn7pytwszmgr5
Hostname: default
Joined at: 2018-02-28 06:25:23.718220559 +0000 utc
Status:
State: Ready
Availability: Active
Address: 192.168.99.100
Platform:
Operating System: linux
Architecture: x86_64
Resources:
CPUs: 1
Memory: 995.9MiB
Plugins:
Log: awslogs, fluentd, gcplogs, gelf, journald, json-file, logentries, splunk, syslog
Network: bridge, host, macvlan, null, overlay
Volume: local
Engine Version: 17.12.0-ce
Engine Labels:
- provider=virtualbox
TLS Info:
TrustRoot:

  • 当节点重新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,就会为每个服务绑定一个随机的高数字端口。你需要检查任务才能确定端口
1
2
3
4
5
6
7
8
9
james@james-CW65:~ > docker service create --name ghostBlog --publish published=80,target=2368 --replicas 1 ghost:1.21.3
xpnc3ga8yvh71zx5dvq94fbsn
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
james@james-CW65:~ > docker service ps ghostBlog
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
5a0tepfqasqu ghostBlog.1 ghost:1.21.3 default Running Running 18 seconds ago

  • 注意旧版的语法是冒号分开的published:target,例如 -p 8080:80。新语法更易读且灵活。
  • 当你在任何节点访问8080端口时,路由网络将把请求分发到一个active的容器中。在各个节点,8080端口可能并没有绑定,但是路由网络知道如何路由流量,并防止任何端口冲突。
  • 路由网络监听各个节点的IP上的 published port 。从外面看,这些端口是各个节点暴露的。对于别的IP地址,只在该主机内可以访问。
    image
    https://docs.docker.com/engine/swarm/images/ingress-routing-mesh.png
  • 你可以用以下命令给一个已经存在的服务暴露端口。
1
2
3
4
5
6
7
8
9
10
11
james@james-CW65:~ > docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
tynb9d9pu0nq ghost replicated 2/2 ghost:1.21.3
xpnc3ga8yvh7 ghostBlog replicated 1/1 ghost:1.21.3 *:80->2368/tcp
james@james-CW65:~ > docker service update --publish-add published=8080,target=2368 ghost
ghost
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged

  • 你可以使用docker service inspect来查看服务暴露的端口:
1
2
3
4
5
james@james-CW65:~ > docker service inspect --format="{{json .Endpoint.Spec.Ports}}" ghost
[{"Protocol":"tcp","TargetPort":2368,"PublishedPort":8080,"PublishMode":"ingress"}]
james@james-CW65:~ > docker service inspect --format="{{json .Endpoint.Spec.Ports}}" ghostBlog
[{"Protocol":"tcp","TargetPort":2368,"PublishedPort":80,"PublishMode":"ingress"}]

  • The output shows the (labeled TargetPort) from the containers and the (labeled PublishedPort) where nodes listen for requests for the service.

仅暴露一个TCP或UDP端口

  • 默认你暴露的端口都是TCP的。如果你使用长语法(Docker 1.13 and higher),设置protocol为tcp或udp即可暴露相应端口
仅TCP
1
2
3
4
5
6
7
8
9
长语法
$ 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
1
2
3
4
5
6
7
8
9
10
11
长语法
$ 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
1
2
3
4
5
6
7
8
9
长语法
$ 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模式绕过路由网络:
1
2
3
4
5
$ docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp,mode=host \
--mode global \
dns-cache

配置外部的负载均衡

  • 你可以为swarm集群配置外部的负载均衡,或者结合路由网络使用或者完全不使用:

使用路由网络

  • 你可以使用一个外部的HAProxy来负载均衡,服务是8080端口上的nginx服务:
    image
  • 在这个例子中负载均衡器和集群节点之间的8080端口必须是开放的。swarm集群节点在一个外部不可访问的内网中,节点可以与HAProxy通信。
  • 你可以配置负载均衡器分流请求到不同的集群节点,即使节点上没有服务运行。例如你可以如下配置HAProxy:/etc/haproxy/haproxy.cfg:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
global
log /dev/log local0
log /dev/log local1 notice
...snip...

# 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.99.100:8080 check
server node2 192.168.99.101:8080 check
server node3 192.168.99.102:8080 check

  • 当你请求HAProxy的80端口的时候,它会转发请求到后端节点。swarm的路由网络会路由到相应的服务节点。这样无论任何原因swarm的调度器调度服务到不同节点,都不需要重新配置负载均衡。
  • 你可以配置任何类型的负载均衡来分流请求。关于HAProxy参考 HAProxy documentation

不使用路由网络

  • 如果不使用路由网络,配置--endpoint-mode的值为dnsrr,而不是vip。在本例子中没有一个固定的虚拟IP。Docker为服务做了DNS注册,这样一个服务的DNS查询会返回一系列IP地址。客户端就可以直接连接其中一个节点。你负责提供这一系列的IP地址,开放端口给你的负载均衡器。参考Configure service discovery.

相关补充内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# 三台虚拟机
192.168.43.129 node1
192.168.43.130 node2
192.168.43.131 node3

# 分别设置hosts

vi /etc/hosts

添加

192.168.43.129 node1
192.168.43.130 node2
192.168.43.131 node3

### copy hosts文件
scp /etc/hosts root@192.168.43.130:/etc/
scp /etc/hosts root@192.168.43.131:/etc/

### 分别设置hostname
hostname node1
bash
hostname node2
bash
hostname node3
bash

### 免密登录

ssh-keygen

ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.43.130
ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.43.131

### 初始化 swarm

# 开放端口
firewall-cmd --zone=public --add-port=2377/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --query-port=2377/tcp

docker swarm init --advertise-addr 192.168.43.129

# 会输出:
docker swarm join --token SWMTKN-1-24y9d5k1hzc8lcdg38kyhj7belzmxp0m7i46eeaj446exmp9gx-5inweyo0dmkqz43kkye2887k5 192.168.43.129:2377

# 在node2、node3中执行

docker swarm join --token SWMTKN-1-24y9d5k1hzc8lcdg38kyhj7belzmxp0m7i46eeaj446exmp9gx-5inweyo0dmkqz43kkye2887k5 192.168.43.129:2377

# 升级/降级
docker node promote node2
docker node demote node2



### 搭建本地私有仓库

* 在node1节点下


vi /etc/sysctl.conf

# 添加
net.ipv4.ip_forward = 1

# 退出执行
sysctl -p

# scp到其他节点
scp /etc/sysctl root@192.168.43.130:/etc/
sysctl -p

scp /etc/sysctl root@192.168.43.130:/etc/
sysctl -p


* 在node1节点下


docker pull registry:2

# 创建一个mul
mkdir - p /opt/docker/registry

# 运行仓库
docker run -itd -p 5000:5000 --restart always -v /opt/docker/registry/:/var/lib/registry --name registry registry:2

# 查看数据
curl 192.168.43.129:5000/v2/_catalog
{"repositories":[]} # 空的

# 使用私有仓库
vi /usr/lib/systemd/system/docker.service

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
BindsTo=containerd.service
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 192.168.43.129:5000 #修改此处
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always

# Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229.
# Both the old, and new location are accepted by systemd 229 and up, so using the old location
# to make them work for either version of systemd.
StartLimitBurst=3

# Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230.
# Both the old, and new name are accepted by systemd 230 and up, so using the old name to make
# this option work for either version of systemd.
StartLimitInterval=60s

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity

# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

# kill only the docker process, not all processes in the cgroup
KillMode=process

[Install]
WantedBy=multi-user.target

# scp 到其他节点
scp /usr/lib/systemd/system/docker.service root@192.168.43.130:/usr/lib/systemd/system/
scp /usr/lib/systemd/system/docker.service root@192.168.43.131:/usr/lib/systemd/system/

# 重新启动下docker
systemctl daemon-reload
systemctl restart docker.service

# 给镜像打标签
docker tag mysql:latest 192.168.43.129:5000/mysql

# 推送镜像
docker push 192.168.43.129:5000/mysql

# 在其他节点获取
docker pull 192.168.43.129:5000/mysql

# 创建网络
docker network create --driver overlay docker-network

# 查看
docker network ls


### portainer 集群配置

~~修改 <kbd>vi /usr/lib/systemd/system/docker.service</kbd>~~
~~在 <kbd> ExecStart= </kbd> 后面添加 <kbd>-H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock</kbd>~~

~~重新加载配置~~

~~systemctl daemon-reload~~

~~重启docker~~

~~systemctl restart docker.service~~

~~开发2375端口或关闭防火墙~~

不需要开发2375端口 开了还很危险

# 注意开放端口
docker network create --driver overlay --attachable portainer_agent_network

docker service create \
--name portainer_agent \
--network portainer_agent_network \
--mode global \
--constraint 'node.platform.os == linux' \
--mount type=bind,src=//var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=//var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent

docker service create \
--name portainer \
--network portainer_agent_network \
--publish 8900:9000 \
--publish 8800:8000 \
--replicas=1 \
--constraint 'node.role == manager' \
portainer/portainer -H "tcp://tasks.portainer_agent:9001" --tlsskipverify

添加标签

1
docker node update --label-add role=web node1

删除标签

1
docker node update --label-rm role node1

https://www.jianshu.com/p/2a11a40a9573