docker 相关 -- 开始使用 swarm 模式

本贴最后更新于 2488 天前,其中的信息可能已经沧海桑田

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 集群:
docker swarm init --advertise-addr <MANAGER1-IP>
  • 本教程中使用如下命令在 manager1 上创建 swarm 集群:
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 集群的状态:
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 来查看节点信息:
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 加入到集群中:
docker@default:~$ docker swarm join --token SWMTKN-1-2bgkinnbc0rmlj6kpotyrlj0uz51l2ikinttsk960dxro558x4-6zajfnahtv9ye39momd
dh5kru 192.168.99.1:2377
This node joined a swarm as a worker.
  • 如果你找不到加入命令了,可以在管理节点运行下列命令找回加入命令:
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 加入到集群:
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 命令来查看集群节点情况:
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. 运行如下命令:
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 来查看运行的服务:
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 来查看优化显示的服务详情
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 将查看到哪些节点在运行该服务实例:
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 也能看到这个任务运行的容器
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. 运行以下命令来改变服务的期望实例数:
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. 运行以下命令来查看更新的任务列表:
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 查看运行的容器:
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 来删除服务:
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 会发现服务不存在了
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 的更新间隔:
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 服务:
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 来更新各个节点:
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 完成。
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:~ >
  • 如果中间有升级失败的,则会显示如下信息:
$ 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 来查看本次滚动更新的过程:
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:~ >
  • 注意升级后老的容器只是停止了,并没有删除
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 的:
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 查看管理节点如何分配任务到不同节点:
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 来下线一个节点:
james@james-CW65:~ > docker node update --availability drain default
default
  1. 运行以下来检查节点的可用性:
  • 可以看到该节点的可用性是 Drain
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 的节点上调度了任务。
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 该节点:
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:
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,就会为每个服务绑定一个随机的高数字端口。你需要检查任务才能确定端口
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
  • 你可以用以下命令给一个已经存在的服务暴露端口。
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 来查看服务暴露的端口:
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
长语法
$ 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 服务:
    image
  • 在这个例子中负载均衡器和集群节点之间的 8080 端口必须是开放的。swarm 集群节点在一个外部不可访问的内网中,节点可以与 HAProxy 通信。
  • 你可以配置负载均衡器分流请求到不同的集群节点,即使节点上没有服务运行。例如你可以如下配置 HAProxy:/etc/haproxy/haproxy.cfg:
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.
  • swarm
    4 引用 • 2 回帖
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    492 引用 • 926 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...