Docker-管理设计模式-二-

83 阅读33分钟

Docker 管理设计模式(二)

原文:Docker Management Design Patterns

协议:CC BY-NC-SA 4.0

五、扩展服务

Docker Engine 适合开发运行在彼此隔离的 Docker 容器中的轻量级应用。Docker 容器能够提供自己的网络和文件系统。

问题

Docker 引擎(在原生群模式之前)被设计用来运行必须单独启动的 Docker 容器。考虑需要创建服务的多个副本或实例的用例。随着 Docker 容器中运行的应用的客户端负载增加,该应用可能需要在多个节点上运行。Docker 引擎的一个限制是,每次为 Docker 映像启动 Docker 容器时,必须运行docker run命令。如果 Docker 应用必须在三个节点上运行,那么docker run <img>命令也必须在每个节点上运行,如图 5-1 所示。Docker 引擎中不提供扩展应用或运行多个副本的功能(在 Docker 1.12 原生群模式支持之前)。

A454123_1_En_5_Fig1_HTML.gif

图 5-1。

Docker engine without provision for scaling

解决方案

Docker 群模式提供了扩展 Docker 服务的功能。服务抽象与零个或多个副本(任务)相关联,每个任务为服务启动一个 Docker 容器。该服务可以根据需要扩大或缩小规模,以运行更多/更少的副本。只需一个docker service scale <svc>=<replicas>命令,服务就可以运行所需数量的副本,如图 5-2 所示。如果要跨分布式集群启动 10 个服务副本,那么一个命令就能够提供扩展。

A454123_1_En_5_Fig2_HTML.gif

图 5-2。

Docker Swarm mode with provision for scaling

只有复制的服务才支持伸缩。全局服务在集群中的每个节点上运行一个服务任务。第三章介绍了扩展服务,在本章中,我们将讨论第三章中未讨论的扩展服务的其他一些方面。本章涵盖以下主题:

  • 设置环境
  • 创建复制的服务
  • 扩大服务规模
  • 缩小服务规模
  • 移除服务
  • 全球服务无法扩展
  • 在同一命令中扩展多个服务
  • 离开集群的节点上的服务副本替换

设置环境

在 Docker 上为 Swarm 创建一个三节点 Swarm,这在第三章讨论。你在另一章中为 AWS Swarm 创建的 Docker 可能会在本章中使用。为 Swarm manager 获取 EC2 实例的公共 IP 地址。

使用用户“docker”通过 SSH 登录到 Swarm manager EC2 实例。

[root@localhost ∼]# ssh -i   "docker.pem"  docker@34.200.225.39
Welcome to Docker!

命令列出了集群中的节点。

∼ $ docker node ls
ID                         HOSTNAME                     STATUS  AVAILABILITY  MANAGER STATUS
ilru4f0i280w2tlsrg9hglwsj   ip-172-31-10-132.ec2.internal  Ready   Active             
w5to186ipblpcq390625wyq2e   ip-172-31-37-135.ec2.internal  Ready   Active             
zkxle7kafwcmt1sd93kh5cy5e * ip-172-31-13-155.ec2.internal  Ready   Active        Leader

创建复制的服务

正如第四章所讨论的,Docker Swarm 模式支持两种类型的服务——全局服务和复制服务。默认为复制模式。只有复制的服务可以扩展。接下来,使用docker service create命令为 MySQL 数据库创建一个复制服务,最初由一个副本组成,如--replicas选项中所指定的。如果没有指定--replicas选项,默认的副本数量也是一个。

∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 1 \

>   --name mysql \

>  mysql
ndu4kwqk9ol7e7wxvv5bremr4

使用docker service ls列出服务。

∼ $ docker service ls
ID              NAME          MODE                REPLICAS            IMAGE          PORTS
ndu4kwqk9ol7    mysql         replicated          1/1                 mysql:latest        

由于服务副本需要一段时间(尽管只有几秒钟)才能启动,最初 0/1 个副本可能会列在REPLICAS列中,这意味着运行一个服务副本的理想状态还没有达到。几秒钟后运行相同的命令,并且1/1 REPLICAS应该被列为正在运行。

可选地,也可以通过设置--mode选项来运行docker service create命令。如果先前创建了mysql服务,则删除该服务,并按如下方式使用--mode选项。

∼ $ docker service rm mysql
mysql
∼ $ docker service create \

>   --mode replicated \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 1 \

>   --name mysql \

>  mysql

rl2s2ptgbs9z2t7fy5e63wf2j

创建的mysql服务没有--mode复制选项。用docker service ps mysql列出服务副本或任务。将列出一个副本。

∼ $ docker service ps mysql
ID            NAME    IMAGE   NODE              DESIRED STATE  CURRENT STATE  ERROR   PORTS
yrikmh7mciv7  mysql.1 mysql:  ip-172-31-13-     Running        Running 21                       latest  155.ec2.internal                 seconds ago                         

如果省略了--replicas选项,默认情况下会创建一个服务副本。应该提到的是,运行 MySQL 数据库的多个副本并不自动意味着它们共享数据,因此访问一个副本不会给你与另一个副本相同的数据。使用挂载共享数据将在第六章中讨论。

扩大服务规模

具有以下语法的docker service scale命令可用于扩大/缩小服务,这改变了服务的期望状态。

docker service scale SERVICE=REPLICAS [SERVICE=REPLICAS...]

首先,将服务扩展到三个副本。

∼ $ docker service scale mysql=3
mysql scaled to 3

随后,三个任务被按计划列在群中的三个节点上。

∼ $ docker service ps mysql
ID            NAME     IMAGE   NODE             DESIRED STATE CURRENT STATE    ERROR   PORTS
yrikmh7mciv7  mysql.1  mysql:  ip-172-31-13-    Running       Running 37                       latest  155.ec2.internal               seconds ago
3zxmotmy6n2t  mysql.2  mysql:  ip-172-31-37-    Running       Running 7                       latest  135.ec2.internal               seconds ago
rdfsowttd3b9  mysql.3  mysql:  ip-172-31-10-    Running       Running 7                       latest  132.ec2.internal               seconds ago

除了 manager 节点上的一个副本之外,两个 worker 节点上还各启动了一个副本。如果在管理器节点上运行docker ps命令,那么只列出一个用于mysql Docker 映像的 Docker 容器。

$ docker ps
CONTAINER ID  IMAGE   COMMAND           CREATED        STATUS  PORTS     NAMES
6d2161a3b282  mysql:  "docker-          50 seconds ago Up 49   3306/tcp  mysql.1.yrikmh7mci              latest   entrypoint..."                  seconds           v7dsmql1nhdi62l

还可以使用带有--replicas选项的docker service update命令来扩展服务。例如,将其扩展到 50 个副本。

∼ $ docker service update --replicas=50  mysql
mysql

该服务扩展到 50 个副本,随后列出了 50 个服务任务。

∼ $ docker service ps -f desired-state=running mysql
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE              ERROR               PORTS
t026kjbsgzmq        mysql.1             mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 11 seconds ago                        
f3tx2kbe55dh        mysql.2             mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 20 seconds ago                        
5mzej75us115        mysql.3             mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 13 seconds ago                        
wluix1b3z863        mysql.4             mysql:latest        ip-172-31-13-155.ec2.internal   Running             Preparing 13 seconds ago                      
9ld8smvahk9g        mysql.5             mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 47 seconds ago                        
3tgw8ni5mfi1        mysql.6             mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
1gm8e7pxkg0o        mysql.7             mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 46 seconds ago                        
iq5p2g48oagq        mysql.8             mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
i4yh072h1gs6        mysql.9             mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 46 seconds ago                        
r1z5tgu0dg13        mysql.10            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
mekfjvxi9pds        mysql.11            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
nd8f2pr4oivc        mysql.12            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
xou9hztlj637        mysql.13            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
t95flokvca2y        mysql.14            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
rda5shwwfmsc        mysql.15            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
ibb2fk2llm3w        mysql.16            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 47 seconds ago                        
st4ofpvrfaip        mysql.17            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
iw4daunt6s63        mysql.18            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 47 seconds ago                        
vk4nzq7utyl2        mysql.19            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
oj59qjcy51qw        mysql.20            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
wiou769z8xeh        mysql.21            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 47 seconds ago                        
5exwimn64w94        mysql.22            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 48 seconds ago                        
agqongnh9uu3        mysql.23            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
ynkvjwgqqqlx        mysql.24            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 47 seconds ago                        
yf87kbsn1cga        mysql.25            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 10 seconds ago                        
xxqj62007cxd        mysql.26            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
50ym9i8tjwd5        mysql.27            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
7btl2pga1l5o        mysql.28            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
62dqj60q1ol8        mysql.29            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
psn7zl4th2zb        mysql.30            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Preparing 16 seconds ago                      
khsj2an2f5gk        mysql.31            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
rzpndzjpmuj7        mysql.32            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
9zrcga93u5fi        mysql.33            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
x565ry5ugj8m        mysql.34            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 48 seconds ago                        
o1os5dievj37        mysql.35            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
dritgxq0zrua        mysql.36            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                         

n8hs01m8picr        mysql.37            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 47 seconds ago                        
dk5w0qnkfb63        mysql.38            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
joii103na4ao        mysql.39            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
db5hz7m2vac1        mysql.40            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 46 seconds ago                        
ghk6s12eeo48        mysql.41            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 45 seconds ago                        
jbi8aksksozs        mysql.42            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 47 seconds ago                        
rx3rded30oa4        mysql.43            mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 47 seconds ago                        
c3zaacke440s        mysql.44            mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 45 seconds ago                        
l6ppiurx4306        mysql.46            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
of06zibtlsum        mysql.47            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
kgjjwlc9zmp8        mysql.48            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
rw1icgkyw61u        mysql.49            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 46 seconds ago                        
j5jpl9a5jgbj        mysql.50            mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 47 seconds ago                         

小规模的 MySQL 数据库服务可能不会从扩展到 50 个副本中受益,但是企业规模的应用可以使用 50 个甚至更多的副本。

缩小服务规模

一项服务可以在扩大的同时缩小。一个服务甚至可以缩减到没有复制品。通过使用docker service updatedocker service scale命令将副本数量设置为0,可以将mysql服务缩小到没有副本。

∼ $ docker service scale mysql=0
mysql scaled to 0

服务缩减到没有副本。没有列出正在运行的服务副本。

∼ $ docker service ps -f desired-state=running mysql
ID               NAME                IMAGE               NODE         DESIRED STATE       CURRENT STATE       ERROR               PORTS

实际的服务任务可能需要一段时间才能关闭,但是所有任务的期望状态都被设置为Shutdown

将服务扩展为无任务不会运行任何任务,但服务不会被删除。例如,mysql服务可以再次从无任务扩大到三个任务。

∼ $ docker service scale mysql=3
mysql scaled to 3

三个服务任务开始运行。

∼ $ docker service ps -f desired-state=running mysql
ID               NAME           IMAGE         NODE                   DESIRED STATE    CURRENT STATE           ERROR               PORTS
py7aqwy2reku     mysql.1        mysql:latest  ip-172-31-37-135.ec2.internal   Running          Running 9 seconds ago  
re1l3q3iwmvo     mysql.2        mysql:latest  ip-172-31-37-135.ec2.internal   Running          Running 9 seconds ago   
h7my2ucpfz3u     mysql.3        mysql:latest  ip-172-31-37-135.ec2.internal   Running          Running 9 seconds ago  

移除服务

可以使用docker service rm命令删除服务。

∼ $ docker service rm mysql
mysql

mysql服务被删除后不再列出。

∼ $ docker service ls
ID            NAME         MODE                REPLICAS            IMAGE               PORTS

使用docker service rm命令可以删除多个服务。为了进行演示,您可以创建两个服务,hello-worldnginx

∼ $ docker service create \
>   --name hello-world \
>   --publish 8080:80 \
>   --replicas 2 \
>   tutum/hello-world
t3msb25rc8b6xcm30k0zoh4ws
∼ $ docker service create --name nginx nginx
ncn4aqkgzrcjc8w1uorjo5jrd
∼ $ docker service ls
ID             NAME         MODE         REPLICAS   IMAGE                    PORTS
ncn4aqkgzrcj   nginx        replicated   1/1        nginx:latest              
t3msb25rc8b6   hello-world   replicated   2/2        tutum/hello-world:latest  *:8080->80/tcp

随后,用一个docker service rm命令删除这两个服务。如果命令成功,则输出删除的服务。

∼ $ docker service rm nginx hello-world
nginx
hello-world

全球服务无法扩展

全局服务在群中的每个节点上创建一个服务任务,并且不能扩展。使用docker service create命令为 MySQL 数据库创建一个全局服务。该命令的显著区别是--mode被设置为global,并且不包括--replicas选项。

∼ $ docker service create \

>   --mode global \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --name mysql-global \

>  mysql

nxhnrsiulymd9n4171cie9a8j

创建了全局服务,并且列出服务应该指示设置为globalMode

∼ $ docker service ls
ID                NAME            MODE            REPLICAS            IMAGE          PORTS
nxhnrsiulymd      mysql-global    global          3/3                 mysql:latest        

在群中的每个节点上创建一个服务任务。

∼ $ docker service ps mysql-global
ID                  NAME                                     IMAGE              NODE                           DESIRED STATE    CURRENT STATE           ERROR      PORTS
nfbmkqdh46k0        mysql-global.zkxle7kafwcmt1sd93kh5cy5e   mysql:latest        ip-172-31-13-155.ec2.internal  Running          Running 22 seconds ago                      
t55ba3bobwzf        mysql-global.w5to186ipblpcq390625wyq2e   mysql:latest        ip-172-31-37-135.ec2.internal  Running          Running 22 seconds ago                      
kqg656m30lj3        mysql-global.ilru4f0i280w2tlsrg9hglwsj   mysql:latest        ip-172-31-10-132.ec2.internal  Running          Running 22 seconds ago                      

如果将另一个节点添加到群中,服务任务会在新节点上自动开始。

如果对全局服务运行docker service scale命令,则服务不会扩展。相反,会输出以下消息。

∼ $ docker service scale mysql-global=5
mysql-global: scale can only be used with replicated mode

使用docker service rm命令,可以像删除复制服务一样删除全局服务。

∼ $ docker service rm mysql-global
mysql-global

使用同一命令扩展多个服务

使用单个docker service scale命令可以扩展多个服务。为了演示,创建两个服务:nginxmysql

∼ $ docker service create \

>   --replicas 1 \

>   --name nginx \

>   nginx
u6i4e8eg720dwzz425inhxqrp
∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --name mysql \

>  mysql
1umb7e2gr68s54utujr6khjgd

请列出这两种服务。每个服务应该运行一个副本。

∼ $ docker service ls
ID                 NAME         MODE             REPLICAS         IMAGE           PORTS
1umb7e2gr68s       mysql        replicated       1/1              mysql:latest         
u6i4e8eg720d       nginx        replicated       1/1              nginx:latest         

用一个命令扩展nginx服务和mysql服务。不同的服务可以扩展到不同数量的副本。

∼ $ docker service scale mysql=5 nginx=10
mysql scaled to 5
nginx scaled to 10

mysql服务扩展到 5 个任务,而nginx服务扩展到 10 个副本。最初,服务的一些新任务可能还没有开始,比如nginx服务,它只列出了 10 个任务中的 8 个正在运行。

∼ $ docker service ls
ID                  NAME          MODE                REPLICAS        IMAGE          PORTS
1umb7e2gr68s        mysql         replicated          5/5             mysql:latest        
u6i4e8eg720d        nginx         replicated          8/10            nginx:latest        

过一会儿,所有服务任务都应该被列为正在运行,如nginx服务的10/10所示。

∼ $ docker service ls
ID                  NAME          MODE                REPLICAS        IMAGE          PORTS
1umb7e2gr68s        mysql         replicated          5/5             mysql:latest        
u6i4e8eg720d        nginx         replicated          10/10           nginx:latest        

可以使用单个docker service ps命令列出两个服务的服务任务。

∼ $ docker service ps nginx mysql
ID                  NAME                IMAGE               NODE                         DESIRED STATE       CURRENT STATE                ERROR               PORTS
f9g1tw88nppk        mysql.1             mysql:latest        ip-172-31-26-234.ec2.internal   Running             Running about a minute ago                      
zcl1qfdiqrvu        nginx.1             nginx:latest        ip-172-31-10-132.ec2.internal   Running             Running about a minute ago                      
vu4xo99xr0y4        nginx.2             nginx:latest        ip-172-31-13-155.ec2.internal   Running             Running 40 seconds ago                           
xvxgfoacxjos        mysql.2             mysql:latest        ip-172-31-37-135.ec2.internal   Running             Running 41 seconds ago                           
yw0opq5y0x20        nginx.3             nginx:latest        ip-172-31-13-155.ec2.internal   Running             Running 41 seconds ago                           
vb92hkua6eyo        mysql.3             mysql:latest        ip-172-31-13-155.ec2.internal   Running             Running 40 seconds ago                           
1cnqwtb24zvy        nginx.4             nginx:latest        ip-172-31-13-155.ec2.internal   Running             Running 41 seconds ago                           
hclu53xkosva        mysql.4             mysql:latest        ip-172-31-26-234.ec2.internal   Running             Running 40 seconds ago                           
2xjcw4i9xw89        nginx.5             nginx:latest        ip-172-31-10-132.ec2.internal   Running             Running 41 seconds ago                           
ocvb2qctuids        mysql.5             mysql:latest        ip-172-31-10-132.ec2.internal   Running             Running 41 seconds ago                           
l8mlu3jpp9cx        nginx.6             nginx:latest        ip-172-31-10-132.ec2.internal   Running             Running 41 seconds ago                           
p84m8yh5if5t        nginx.7             nginx:latest        ip-172-31-37-135.ec2.internal   Running             Running 41 seconds ago                           
7yp8m7ytt7z4        nginx.8             nginx:latest        ip-172-31-26-234.ec2.internal   Running             Running 24 seconds ago                           
zegs90r015nn        nginx.9             nginx:latest        ip-172-31-37-135.ec2.internal   Running             Running 41 seconds ago                           
qfkpvy28g1g6        nginx.10            nginx:latest        ip-172-31-26-234.ec2.internal   Running             Running 24 seconds ago                           

离开群体的节点上的服务任务替换

Docker 群模式中的期望状态协调确保了如果资源可用,期望数量的副本正在运行。如果一个节点离开群,在该节点上运行的副本被调度到另一个节点上。从运行在三节点集群中每个节点上的mysql服务副本开始,您可以让一个工作节点离开集群。

∼ docker swarm 1eave
Node left the swarm.

运行在shutdown节点上的服务任务的替换服务任务被调度到另一个节点上。

∼ s docker service ps mysql

NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR

6zu7a59ejdxip3y9oeu548hv5 mysql.l mysql ip-10-0-0-46.ec2.internal Running Running 3 minutes ago
441cuufa7sa9möeatqbiq7vi3 mysql.2 mysql ip-10-0-0-28.ec2.internal Running Running about a minute ago
blcdm8Bh6v86gl..pwp6zx3janv mysql.3 mysql ip-10-0-0-28.ec2.internal Running Running 4 seconds ago
Or3oki4acf3d6ils5iazmg425 \_ mysql.3 mysql ip-10-0-0-106.ec2.internal Shutdown Running about a minute ago

使其他工人节点也离开蜂群。另一个工作节点上的服务副本也被关闭,并被调度到群中唯一剩余的节点上。

∼ s docker service ps mysql

NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR

6zu7a59ejdxip3y9oeu548hv5 mysql.1 mysql ip-10-0-0-46.ec2\. internal Running Running 5 minutes ago

dbdaxvl6lohlxrsxh5aobjxi8 mysq.2 mysql ip-10-0-0-46.ec2.internal Running Running 7 seconds ago

44tcuufa7sa9m6eatqbiq7vi3 \_ mysql.2 mysql ip-10-0-0-28.ec2.internal Shutdown Running 2 minutes ago

216iu28xh5hztm3bgtvy7ttk8 mysql.3 mysql ip-10-0-0-46.ec2.internal Running Running 7 seconds ago

blcdm88h6v86gLpwp6zx3janv \_ mysql.3 mysql ip-10-0-0-28.ec2.internal Shutdown Running about a minute ago

Or3oki4acf3d6ils5iazmg425 \_ mysql.3 mysql ip-10-0-0-106.ec2.internal Shutdown Running 2 minutes ago

如果仅列出所需状态为正在运行的复制副本,则所有复制副本都会在管理器节点上显示为正在运行。

∼s docker service ps -f desired-state=running mysql

ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR

6zu7a59ejdxip3y9oeu548hv5 mysql.1 mysql ip-10-0-0-46.ec2.internal Running Running 7 minutes ago

dbdaxvl6lohlxrsxh5aobjxi8 mysql.2 mysql ip-10-0-0-46.ec2.internal Running Running 2 minutes ago

216iu28xh5hztm3bgtvy7ttk8 mysql.3 mysql ip-10-0-0-46.ec2.internal Running Running 2 minutes ago

摘要

本章讨论了群模式下的服务扩展。只能扩展复制的服务,而不能扩展全局服务。一个服务可以扩展到资源可以支持的尽可能多的副本,也可以缩减到没有副本。使用同一命令可以扩展多个服务。期望状态协调确保期望数量的服务副本正在运行。下一章将介绍 Docker 服务挂载。

六、使用挂载

Swarm 中的服务任务容器可以访问从其 Docker 映像继承的文件系统。数据通过其 Docker 映像集成到 Docker 容器中。有时,Docker 容器可能需要在持久文件系统上存储或访问数据。虽然容器有一个文件系统,但是一旦容器退出,它就会被删除。为了在容器重启时存储数据,数据必须保存在容器之外的某个地方。

问题

仅存储在容器中的数据可能会导致以下问题:

  • 数据不是持久的。当 Docker 容器停止时,数据将被删除。
  • 数据不能与其他 Docker 容器或主机文件系统共享。

解决方案

基于单一责任原则(SRP)的模块化设计建议将数据从 Docker 容器中分离出来。Docker Swarm 模式提供了共享数据的挂载,并使数据在容器启动和关闭时保持持久。Docker Swarm 模式为服务提供了两种类型的挂载:

  • 卷装载
  • 绑定安装

默认值是卷装载。使用docker service create命令的--mount选项创建服务的挂载。

卷装载

卷装载是主机上装载到服务任务容器中的命名卷。即使在停止和删除容器后,主机上的命名卷仍然存在。可以在创建使用该卷的服务之前创建命名卷,或者可以在服务部署时创建该卷。在部署时创建的命名卷是在启动服务任务容器之前创建的。如果在服务部署时创建,并且未指定卷名,则命名卷会自动生成一个名称。图 6-1 显示了一个卷挂载的例子,其中一个在创建服务之前就存在的命名卷mysql-scripts被挂载到目录路径/etc/mysql/scripts下的服务任务容器中。

A454123_1_En_6_Fig1_HTML.gif

图 6-1。

Volume mount

服务中的每个容器都可以访问运行该容器的主机上的相同命名卷,但是该主机命名卷可以存储相同或不同的数据。

使用卷装载时,内容不会跨群集复制。例如,如果您将某些内容放入正在使用的mysql-scripts目录,这些新文件将只能被运行在同一节点上的其他任务访问。在其他节点上运行的副本将无法访问这些文件。

绑定安装

绑定装载是要在其上计划服务任务的主机上的文件系统路径。主机文件系统路径被装载到服务任务容器的指定目录路径中。主机文件系统路径必须存在于群中的每个主机上,在创建服务之前可以在其上调度任务。如果使用节点约束将某些节点排除在服务部署之外,则绑定装载主机文件系统不必存在于这些节点上。使用绑定挂载时,请记住使用绑定挂载的服务本身是不可移植的。如果要在生产中部署服务,主机目录路径必须存在于生产集群中的每个主机上。

主机文件系统路径不必与任务容器中的目标目录路径相同。例如,在图 6-2 中,主机路径/db/mysql/data作为绑定挂载被挂载到目录路径/etc/mysql/data的服务容器中。默认情况下,绑定装载是读写的,但是在服务部署时可以设置为只读。服务中的每个容器都可以访问运行容器的主机上的相同目录路径,但是主机目录路径可以存储不同或相同的数据。

A454123_1_En_6_Fig2_HTML.gif

图 6-2。

Bind mount

群模式装载在主机上提供可共享的命名卷和文件系统路径,这些路径在服务任务启动和关闭期间保持不变。Docker 映像的文件系统仍然位于文件系统层次结构的根位置,并且只能在根文件系统内的目录路径上进行挂载。

本章涵盖以下主题:

  • 设置环境
  • 安装类型
  • 创建命名卷
  • 使用卷装载来获取有关卷的详细信息
  • 删除卷
  • 创建和使用绑定装载

设置环境

为基于 AWS 的群创建一个 Docker,由一个管理节点和两个工作节点组成,如第三章所述。AWS Swarm 的 Docker 将用于一种类型的挂载,即卷挂载。对于绑定挂载,在 CoreOS 实例上创建一个由一个管理器和两个工作者节点组成的三节点集群。在第二章中讨论了在 CoreOS 实例上创建蜂群。使用基于 CoreOS 的 Swarm 是因为 Docker for AWS Swarm 不支持开箱即用的绑定挂载。从 EC2 控制台获取 AWS Swarm Docker 的 manager 实例的公共 IP 地址,如图 6-3 所示。

A454123_1_En_6_Fig3_HTML.jpg

图 6-3。

EC2 instances for Docker for AWS Swarm nodes

SSH 登录到管理器实例。

[root@localhost ∼]# ssh -i "docker.pem" docker@52.91.115.180
Welcome to Docker!

列出群体中的节点。列出了一个管理节点和两个工作节点。

∼ $ docker node ls
ID                          HOSTNAME                      STATUS AVAILABILITY MANAGER STATUS
8ynq7exfo5v74ymoe7hrsghxh   ip-172-31-33-230.ec2.internal Ready  Active             
o0h7o09a61ico7n1t8ooe281g * ip-172-31-16-11.ec2.internal  Ready  Active       Leader
yzlv7c3qwcwozhxz439dbknj4   ip-172-31-25-163.ec2.internal Ready  Active              

创建命名卷

在服务中用作卷类型装载的命名卷可以在创建服务之前创建,也可以在部署时创建。使用以下命令语法创建新的命名卷。

docker volume create [OPTIONS] [VOLUME]

支持表 6-1 中讨论的选项。

表 6-1。

Options for the docker volume create Command for a Named Volume

| [计]选项 | 描述 | 类型 | 缺省值 | | --- | --- | --- | --- | | `--driver, -d` | 指定卷驱动程序名称 | `string` | `local` | | `--label` | 设置卷的元数据 | `value` | `[]` | | `--name` | 指定卷名 | `string` |   | | `--opt, -o` | 设置驱动程序特定选项 | `value` | `map[]` |

使用docker volume create命令创建一个名为hello的命名卷。

∼ $ docker volume create --name  hello
hello

随后,使用docker volume ls命令列出卷。除了可能存在的其他命名卷之外,还列出了hello卷。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello

您可以使用以下命令找到有关该卷的详细信息。

docker volume inspect hello

除了卷名和驱动程序之外,还会列出卷的挂载点。

∼ $ docker volume inspect hello
[    {        "Driver": "local",        "Labels": {},        "Mountpoint": "/var/lib/docker/volumes/hello/_data",        "Name": "hello",        "Options": {},        "Scope": "local"    }]

本地驱动程序卷的范围是local。另一个支持的范围是global。在单个 Docker 主机上创建一个local卷,在集群中的每个 Docker 主机上创建一个global卷。

使用卷装载

使用带有--mount选项的docker service create命令中的hello音量。表 6-2 中讨论的选项可用于绑定挂载和卷挂载。

表 6-2。

Options for Volume and Bind Mounts

| [计]选项 | 需要 | 描述 | 默认 | | `type` | 不 | 指定装载的类型。可以指定三个值之一:`volume-Mounts`是容器中的命名卷。`bind-Bind-mounts`是将一个目录或文件从主机放入一个容器中。`tmpfs-Mounts`是一只`tmpfs`变成的容器。 | `volume` | | `src`或`source` | 仅适用于`type=bind`。`type=volume`的否 | 源目录或卷。该选项对于不同类型的挂载有不同的含义。`type=volume: src`指定卷的名称。如果指定的卷不存在,则创建该卷。如果省略了`src`,则使用自动生成的名称创建命名卷,该名称在主机上是唯一的,但在群集范围内可能不是唯一的。当使用卷的容器被删除时,自动生成的命名卷也被删除。`docker service update`命令关闭任务容器并启动新的任务容器,扩展服务也是如此。`volume source`不能是绝对路径。`type=bind: src`指定要绑定挂载的目录或文件的绝对路径。目录路径必须是绝对路径,而不是相对路径。类型为`bind`的挂载需要`src`选项,如果没有指定,就会产生错误。不支持`type=tmpfs:`。 |   | | `dst`或`destination`或`target` | 是 | 指定容器内的挂载路径。如果容器的文件系统中不存在该路径,Docker 引擎会在挂载绑定或卷挂载之前创建挂载路径。卷目标必须是相对路径。 |   | | `readonly`或`ro` | 不 | 一个布尔值(真/假)或(1/0)来指示 Docker 引擎应该装入卷并绑定读写还是只读。如果未指定选项,引擎将装载绑定或卷读写。如果将该选项指定为 true 值、1 值或无值,则引擎会以只读方式装载卷或绑定。如果将该选项指定为值 false 或 0,则引擎会装载卷或绑定读写。 |   |

一些装载选项仅支持卷装载,并在表 6-3 中讨论。

表 6-3。

Options for Volume Mounts

| [计]选项 | 需要 | 描述 | 缺省值 | | --- | --- | --- | --- | | `volume-driver` | 不 | 指定用于卷的卷驱动程序插件的名称。如果在`src`中没有指定命名卷,则`volume-driver`用于创建一个命名卷。 | `local` | | `volume-` `label` | 不 | 指定要应用于卷的一个或多个逗号分隔的元数据标签。例子:`volume-label=label-1=hello-world,label-2=hello`。 |   | | `volume-nocopy` | 不 | 适用于在文件和目录已经存在的装载路径的容器中装载的空卷。指定是否将挂载路径(`dst`)下容器的文件系统文件和目录复制到卷中。主机能够访问从容器复制到指定卷的文件和目录。true 或 1 值禁止将文件从容器的文件系统复制到主机卷。false 或 0 值表示允许复制。 | 真或 1 | | `volume-` `opt` | 不 | 指定在创建命名卷(如果不存在)时提供给`volume-driver`的选项。`volume-opt`选项被指定为逗号分隔的键/值对列表。例如:`volume-opt-1=option-1=value1,option-2=value2`。要装载卷类型装载的每个主机上都必须有一个命名卷。在 Swarm manager 上创建命名卷并不会在 worker 节点上创建命名卷。`volume-driver`和`volume-opt`选项用于在工作节点上创建命名卷。 |   |

表 6-4 中讨论的选项仅支持tmpfs类型的安装。

表 6-4。

Options for the tmpfs Mount

| [计]选项 | 需要 | 描述 | 缺省值 | | --- | --- | --- | --- | | `tmpfs-size` | 不 | 以字节为单位的`tmpfs`挂载的大小 | Linux 的无限价值 | | `tmpfs-` `mode` | 不 | 以八进制指定`tmpfs`的文件模式 | `1777`在 Linux 中 |

接下来,我们将在用 Docker 映像tutum/hello-world创建的服务中使用命名卷hello。在下面的docker service create命令中,--mount选项将src指定为hello,并包含一些卷的volume-label标签。

∼ $ docker service create \
   --name hello-world \
   --mount src=hello,dst=/hello,volume-label="msg=hello",volume-label="msg2=world" \
   --publish 8080:80 \
   --replicas 2 \
   tutum/hello-world

创建服务并输出服务 ID。

∼ $ docker service create \

>   --name hello-world \

>   --mount src=hello,dst=/hello,volume-label="msg=hello",volume-label="msg2=world" \

>   --publish 8080:80 \

>   --replicas 2 \

>   tutum/hello-world
8ily37o72wyxkyw2jt60kdqoz

创建了两个服务副本。

∼ $ docker service ls
ID            NAME          MODE        REPLICAS  IMAGE                      PORTS
8ily37o72wyx  hello-world   replicated  2/2       tutum/hello-world:latest   *:8080->80/tcp
∼ $ docker service ps hello-world
ID            NAME                IMAGE                        NODE             DESIRED STATE       CURRENT STATE            ERROR              PORTS
uw6coztxwqhf  hello-world.1       tutum/hello-world:latest     ip-172-31-25-163.ec2.internalRunning             Running 20 seconds ago
cfkwefwadkki  hello-world.2       tutum/hello-world:latest     ip-172-31-16-11.ec2.internalRunning             Running 21 seconds ago                       

命名的卷安装在服务的每个任务容器中。

服务定义列出了装载,包括装载标签。

∼ $ docker service inspect hello-world
[     ...        "Spec": {                "ContainerSpec": {                    "Image": "tutum/hello-world:latest@sha256:0d57def8055178aafb4c7669cbc25ec17f0acdab97cc587f30150802da8f8d85",                    "Mounts": [                        {                            "Type": "volume",                            "Source": "hello",                            "Target": "/hello",                            "VolumeOptions": {                                "Labels": {                                    "msg": "hello",                                    "msg2": "world"                                },...]

在前面的示例中,在卷装入中使用卷之前,创建了一个命名卷。又如,在部署时创建一个命名卷。在下面的docker service create命令中,--mount选项被设置为type=volume,源被设置为nginx-root。创建服务之前,命名卷nginx-root不存在。

∼ $ docker service create \

>   --name nginx-service \

>   --replicas 3 \

>   --mount type=volume,source="nginx-root",destination="/var/lib/nginx",volume-
label="type=nginx root dir" \

>   nginx:alpine
rtz1ldok405mr03uhdk1htlnk

运行该命令时,会创建一个服务。服务描述包括mounts中的卷挂载。

∼ $ docker service inspect nginx-service
[...        "Spec": {            "Name": "nginx-service",...                    "Mounts": [                        {                            "Type": "volume",                            "Source": "nginx-root",                            "Target": "/var/lib/nginx",                            "VolumeOptions": {                                "Labels": {                                    "type": "nginx root dir"                                },...]

命名卷nginx-root不是在创建服务之前创建的,因此是在为服务任务启动容器之前创建的。命名卷nginx-root仅在计划任务的节点上创建。三个节点中的每一个都计划了一个服务任务。

∼ $ docker service ps nginx-service
ID                  NAME                IMAGE               NODE                         DESIRED STATE       CURRENT STATE            ERROR               PORTS
pfqinizqmgur        nginx-service.1     nginx:alpine        ip-172-31-33-230.ec2.internalRunning             Running 19 seconds ago                       
mn8h3p40chgs        nginx-service.2     nginx:alpine        ip-172-31-25-163.ec2.internalRunning             Running 19 seconds ago                       
k8n5zzlnn46s        nginx-service.3     nginx:alpine        ip-172-31-16-11.ec2.internalRunning             Running 18 seconds ago                       

当在管理器节点上调度任务时,在管理器节点上创建一个名为nginx-root的命名卷,如docker volume ls命令的输出中所列。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello
local               nginx-root

服务任务和任务容器在两个工作节点的每一个上启动。在每个工作节点上创建一个nginx-root命名卷。列出工作节点上的卷会列出nginx-root卷。

[root@localhost ∼]# ssh -i "docker.pem" docker@34.229.86.64
Welcome to Docker!
∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello
local               nginx-root

[root@localhost ∼]# ssh -i "docker.pem" docker@52.91.200.241
Welcome to Docker!
∼ $ docker volume ls
DRIVER              VOLUME NAME
local               hello
local               nginx-root

在前面的示例中,在src中指定了一个命名卷。在下面的服务定义中,可以省略指定的卷。

∼ $ docker service create \

>   --name nginx-service-2 \

>   --replicas 3 \

>   --mount type=volume,destination=/var/lib/nginx   \

>   nginx:alpine
q8ordkmkwqrwiwhmaemvcypc3

服务是用一个副本创建的,并在每个群节点上进行调度。

∼ $ docker service ps nginx-service-2
ID                  NAME                IMAGE               NODE                           DESIRED STATE       CURRENT STATE            ERROR               PORTS
kz8d8k6bxp7u        nginx-service-2.1   nginx:alpine        ip-172-31-25-163.ec2.internalRunning             Running 27 seconds ago                       
wd65qsmqixpg        nginx-service-2.2   nginx:alpine        ip-172-31-16-11.ec2.internalRunning             Running 27 seconds ago                       
mbnmzldtaaed        nginx-service-2.3   nginx:alpine        ip-172-31-33-230.ec2.internalRunning             Running 26 seconds ago                       

服务定义没有列出命名卷。

∼ $ docker service inspect nginx-service-2
[        "Spec": {            "Name": "nginx-service-2",                "ContainerSpec": {                    "Mounts": [                        {                            "Type": "volume",                            "Target": "/var/lib/nginx"                        }                    ],
...
]

如果没有明确指定卷名,则会创建具有自动生成名称的命名卷。在运行服务任务的每个节点上,都会创建一个具有自动生成名称的自动生成的命名卷。manager 节点上列出的一个命名卷是自动生成的命名卷,具有自动生成的名称。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               305f1fa3673e811b3b320fad0e2dd5786567bcec49b3e66480eab2309101e233
local               hello
local               nginx-root

作为在服务中使用命名卷作为挂载的另一个例子,为 MySQL 数据库服务创建一个名为mysql-scripts的命名卷。

∼ $ docker volume create --name mysql-scripts
mysql-scripts

命名的卷已创建并列出。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               305f1fa3673e811b3b320fad0e2dd5786567bcec49b3e66480eab2309101e233
local               hello
local               mysql-scripts
local               nginx-root

卷描述将范围列为local,并列出挂载点。

∼ $ docker volume inspect mysql-scripts
[    {        "Driver": "local",        "Labels": {},        "Mountpoint": "/var/lib/docker/volumes/mysql-scripts/_data",        "Name": "mysql-scripts",        "Options": {},        "Scope": "local"    }]

接下来,创建一个在卷装载中使用命名卷的服务。

∼ $ docker service create \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --mount type=volume,src="mysql-scripts",dst="/etc/mysql/scripts",
      el="msg=mysql",volume-label="msg2=scripts" \
> --publish 3306:3306\
>   --replicas 2 \
>   --name mysql \
>  mysql
cghaz4zoxurpyqil5iknqf4c1

服务被创建并列出。

∼ $ docker service ls
ID             NAME         MODE        REPLICAS  IMAGE                     PORTS
8ily37o72wyx   hello-world  replicated  2/2       tutum/hello-world:latest  *:8080->80/tcp
cghaz4zoxurp   ysql         replicated  1/2       mysql:latest              *:3306->3306/tcp

列出服务任务表明任务被安排在管理器节点和一个工作者节点上。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                     DESIRED STATE       CURRENT STATE                    ERROR               PORTS
y59yhzwch2fj        mysql.1             mysql:latest        ip-172-31-33-230.ec2.internalRunning             Preparing 12 seconds ago                             
zg7wrludkr84        mysql.2             mysql:latest        ip-172-31-16-11.ec2.internalRunning             Running less than a second ago                       

命名卷的目标目录在 Docker 容器中创建。管理节点上的 Docker 容器可以用docker ps列出,容器上的 bash shell 可以用docker exec -it <containerid> bash命令启动。

$ docker ps
CONTAINER ID        IMAGE                                       COMMAND                  CREATED             STATUS              PORTS                         NAMES
a855826cdc75        mysql:latest                                "docker-entrypoint..."   22 seconds ago      Up 21 seconds       3306/tcp                      mysql.2.zg7wrludkr84zf8vhdkf8wnlh
∼ $ docker exec -it a855826cdc75 bash
root@a855826cd75:/#

将目录更改为容器中的/etc/mysql/scripts。最初,目录是空的。

root@a855826cdc75:/# cd /etc/mysql/scripts
root@a855826cdc75:/etc/mysql/scripts# ls -l
total 0
root@a855826cdc75:/etc/mysql/scripts# exit
exit

在工作者节点之一上创建服务的任务容器,并且可以在工作者节点上列出该任务容器。

∼ $ docker ps
CONTAINER ID        IMAGE                            COMMAND        CREATED             STATUS          PORTS                NAMES
eb8d59cc2dff        mysql:latest                     "docker-entrypoint..."     8 minutes ago       Up 8 minutes    3306/tcp             mysql.1.xjmx7qviihyq2so7n0oxi1muq

在 worker 节点上为 Docker 容器启动一个 bash shell。在 Docker 容器中创建了挂载指定卷的/etc/mysql/scripts目录。

$ docker exec -it eb8d59cc2dff bash
root@eb8d59cc2dff:/# cd /etc/mysql/scripts
root@eb8d59cc2dff:/etc/mysql/scripts# exit
exit

如果使用自动生成的命名卷的服务被扩展为在先前未运行任务的节点上运行任务,则命名卷也会在这些节点上自动生成。作为在服务中使用自动生成的命名卷作为挂载时发现扩展服务的效果的示例,创建一个带有卷挂载的 MySQL 数据库服务。在创建服务之前,卷mysql-scripts不存在;移除mysql-scripts卷(如果存在)。

∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 1 \

>   --mount type=volume,src="mysql-scripts",dst="/etc/mysql/scripts"\

>   --name mysql \

>  mysql
088ddf5pt4yb3yvr5s7elyhpn

服务任务被安排在一个节点上。

$ docker service ps mysql
ID                  NAME                IMAGE               NODE                   DESIRED STATE       CURRENT STATE              ERROR               PORTS
xlix91njbaq0        mysql.1             mysql:latest        ip-172-31-13-122.ec2.internalRunning             Preparing 12 seconds ago               

列出节点;安排服务任务的节点是管理器节点。

∼ $ docker node ls
ID                           HOSTNAME                      STATUS  AVAILABILITY  MANAGER STATUS
o5hyue3hzuds8vtyughswbosl    ip-172-31-11-41.ec2.internal   Ready  Active              
p6uuzp8pmoahlcwexr3wdulxv    ip-172-31-23-247.ec2.internal  Ready  Active              
qnk35m0141lx8jljp87ggnsnq *  ip-172-31-13-122.ec2.internal  Ready  Active        Leader

在调度任务的 manager 节点上创建一个命名卷mysql-scripts和一个具有自动生成名称的辅助命名卷。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               a2bc631f1b1da354d30aaea37935c65f9d99c5f084d92341c6506f1e2aab1d55
local               mysql-scripts

工作节点没有列出mysql-scripts命名卷,因为工作节点上没有调度任务。

∼ $ docker volume ls
DRIVER              VOLUME NAME

将服务扩展到三个副本。在三个节点中的每一个节点上都安排了一个复制副本。

∼ $ docker service scale mysql=3
mysql scaled to 3

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                  DESIRED STATE       CURRENT STATE                    ERROR               PORTS
xlix91njbaq0        mysql.1             mysql:latest        ip-172-31-13-122.ec2.internal Running             Running about a minute ago                           
ifk7xuvfp9p2        mysql.2             mysql:latest        ip-172-31-23-247.ec2.internal Running             Running less than a second ago                       
3c53fxgcjqyt        mysql.3             mysql:latest        ip-172-31-11-41.ec2.internal Running             Running less than a second ago                       

由于计划了一个副本,因此在工作节点上创建了一个命名卷mysql-scripts和一个具有自动生成名称的辅助命名卷。

[root@localhost ∼]# ssh -i "docker.pem" docker@54.165.69.9
Welcome to Docker!

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               431a792646d0b04b5ace49a32e6c0631ec5e92f3dda57008b1987e4fe2a1b561
local               mysql-scripts
[root@localhost ∼]# ssh -i "docker.pem" docker@34.232.95.243
Welcome to Docker!

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               afb2401a9a916a365304b8aa0cc96b1be0c161462d375745c9829f2b6f180873
local               mysql-scripts

自动生成的命名卷是永久性的,不会在服务复制副本关闭时被删除。具有自动生成名称的命名卷不是永久卷。例如,将服务扩展回一个副本。两个复制副本关闭,包括管理器节点上的复制副本。

∼ $ docker service scale mysql=1
mysql scaled to 1
∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                      DESIRED STATE       CURRENT STATE           ERROR               PORTS
3c53fxgcjqyt        mysql.3             mysql:latest        ip-172-31-11-41.ec2.internal Running             Running 2 minutes ago                   

但是管理器节点上的命名卷mysql-scripts不会被删除,即使没有使用该卷的 Docker 容器正在运行。

∼ $ docker volume ls
DRIVER              VOLUME NAME
local               mysql-scripts

类似地,关闭服务副本的工作节点上的命名卷也不会被删除,即使没有使用该命名卷的 Docker 容器正在运行。当没有容器在使用时,具有自动生成名称的命名卷会被删除,但mysql-scripts命名卷不会被删除。

移除卷mysql-scripts仍未移除。

∼ $ docker service rm mysql
mysql
∼ $ docker volume ls
DRIVER              VOLUME NAME
local               mysql-scripts

删除卷

可以使用以下命令删除命名卷。

docker volume rm  <VOL>

例如,删除命名卷mysql-scripts

∼ $ docker volume rm mysql-scripts
mysql-scripts

如果您尝试删除的卷在 Docker 容器中使用,则会生成一个错误,并且该卷不会被删除。如果正在容器中使用,即使是具有自动生成名称的命名卷也不能删除。

创建和使用绑定装载

在本节中,我们将创建一个 bind 类型的装载。如果需要从 Docker 容器中访问主机上已经存在的目录中的数据,则适合使用绑定装载。当创建具有绑定类型装载的服务时,必须使用--mount选项指定type=bind。主机源目录和卷目标必须都是绝对路径。创建服务之前,主机源目录必须存在。服务的每个 Docker 容器中的目标目录是自动创建的。在管理器节点上创建一个目录,然后向该目录添加一个名为createtable.sql的文件。

core@ip-10-0-0-143$ sudo mkdir -p /etc/mysql/scripts
core@ip-10-0-0-143$ cd /etc/mysql/scripts
core@ip-10-0-0-143 /etc/mysql/scripts $ sudo vi createtable.sql

在示例 SQL 文件中保存一个 SQL 脚本,如图 6-4 所示。

A454123_1_En_6_Fig4_HTML.jpg

图 6-4。

Adding a SQL script to the host directory

类似地,创建一个目录并向 worker 节点添加一个 SQL 脚本。

使用使用主机目录的绑定装载创建服务。目标目录被指定为/scripts

core@ip-10-0-0-143 ∼ $ docker service create \

>    --env MYSQL_ROOT_PASSWORD='mysql' \

>    --replicas 3 \

>    --mount type=bind,src="/etc/mysql/scripts",dst="/scripts" \

>    --name mysql \

>       mysql

0kvk2hk2qigqyeem8x1r8qkvk

从调度任务的节点启动服务容器的 bash shell。列出目标目录/scripts

core@ip-10-0-0-143$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED           STATUS              PORTS               NAMES
e71275e6c65c        mysql:latest        "docker-entrypoint.sh"   5 seconds ago       Up 4 seconds        3306/tcp            mysql.1.btqfrx7uffym2xvc441pubaza

core@ip-10-0-0-143$ docker exec -it e71275e6c65c bash
root@e71275e6c65c:/# ls -l                                   
drwxr-xr-x.  2 root root 4096 Jul 24 20:44 scripts

将目录(cd)更改为目标挂载路径/scripts。在绑定挂载的目标挂载路径中列出了createtable.sql脚本。

root@e71275e6c65c:/# cd /scripts
root@e71275e6c65c:/scripts# ls -l
-rw-r--r--. 1 root root 1478 Jul 24 20:44 createtable.sql

每个服务任务 Docker 容器在主机上都有自己的文件副本。因为默认情况下,挂载是read-write,所以挂载路径中的文件可能会被修改或删除。例如,从容器中删除createtable.sql脚本。

core@ip-10-0-0-137$ docker exec -it 995b9455aff2 bash
root@995b9455aff2:/# cd /scripts                                               
root@995b9455aff2:/scripts# ls -l
total 8
-rw-r--r--. 1 root root 1478 Jul 24 20:45 createtable.sql
root@995b9455aff2:/scripts# rm createtable.sql
root@995b9455aff2:/scripts# ls -l
total 0
root@995b9455aff2:/scripts#

如前所述,通过在--mount arg 中包含一个额外的选项,可以将挂载设置为只读。为了演示a readonly挂载,首先删除已经运行的mysql服务。创建一个服务并使用与之前相同的命令挂载一个readonly绑定,除了包含一个额外的readonly选项。

core@ip-10-0-0-143 ∼ $ docker service create \

>    --env MYSQL_ROOT_PASSWORD='mysql' \

>    --replicas 3 \

>    --mount type=bind,src="/etc/mysql/scripts",dst="/scripts",readonly \

>    --name mysql \

>       mysql
c27se8vfygk2z57rtswentrix

安装了类型为readonlymount活页夹。

访问调度任务的节点上的容器,并列出主机目录中的示例脚本。

core@ip-10-0-0-143$ docker exec -it 3bf9cf777d25 bash
root@3bf9cf777d25:/# cd /scripts                                               
root@3bf9cf777d25:/scripts# ls -l
-rw-r--r--. 1 root root 1478 Jul 24 20:44 createtable.sql

删除或尝试删除示例脚本。会产生一个错误。

root@3bf9cf777d25:/scripts# rm createtable.sql
rm: cannot remove 'createtable.sql': Read-only file system

摘要

本章介绍了蜂群模式下的坐骑。支持两种类型的装载—绑定装载和卷装载。绑定装载将预先存在的目录或文件从主机装载到服务的每个容器中。卷挂载将命名卷挂载到服务中的每个容器中,该命名卷在创建服务之前可能存在,也可能不存在。下一章讨论配置资源。

七、配置资源

Docker 容器在底层操作系统内核上独立运行,运行时需要资源。Docker Swarm 模式支持两种类型的资源——CPU 和内存——如图 7-1 所示。

A454123_1_En_7_Fig1_HTML.gif

图 7-1。

Types of resources supported by Docker Swarm mode

问题

默认情况下,Docker Swarm 模式对一个服务任务可以消耗多少资源(CPU 周期或内存)没有任何限制。Swarm 模式也不能保证最少的资源。如果在 Docker Swarm 模式下没有指定资源配置,会导致两个问题。

一些服务任务可能消耗不成比例的资源量,而其他服务任务由于缺乏资源而不能被调度。例如,考虑一个具有 3GB 资源容量和 3 个 CPU 的节点。在没有任何资源保证和限制的情况下,一个服务任务容器可以消耗大部分资源(2.8GB 和 2.8 CPUs),而另外两个服务任务容器每个只剩下 0.1GB 和 0.1 CPU 的资源可以使用,并且没有得到调度,如图 7-2 所示。没有足够资源进行调度的 Docker 服务任务被置于Pending状态。

A454123_1_En_7_Fig2_HTML.gif

图 7-2。

Unequal allocation of resources

可能导致的第二个问题是,节点的资源容量可能被完全用尽,而没有任何供应来调度任何更多的服务任务。例如,一个资源容量为 9GB 和 9 个 CPU 的节点运行着三个服务任务容器,每个容器使用 3GB 和 3 个 CPU,如图 7-3 所示。如果为同一个或另一个服务创建了新的服务任务,它在节点上没有任何可用的资源。

A454123_1_En_7_Fig3_HTML.gif

图 7-3。

Fully resource-utilized node

解决方案

Docker Swarm 模式具有设置资源保证(或储备)和资源限制的规定,如图 7-4 所示。资源储备是为服务任务保证或保留的最小资源量。资源限制是服务任务可以使用的最大资源量,而不管有多少资源可用。

A454123_1_En_7_Fig4_HTML.gif

图 7-4。

Managing Swarm resources with resource reserves and limits

有了资源储备,在前面讨论的问题中,每个服务任务容器可以保证 1 个 CPU 和 1GB,如图 7-5 所示。

A454123_1_En_7_Fig5_HTML.gif

图 7-5。

Resource allocation with resource reserves set

并且,如果对服务任务容器实施资源限制,则多余的资源将可用于启动新的服务任务容器。在前面讨论的示例中,每个服务任务 2GB 和 2 个 CPU 的限制将使 3GB 和 3 个 CPU 的额外资源可用于新的服务任务容器,如图 7-6 所示。

A454123_1_En_7_Fig6_HTML.gif

图 7-6。

Resource allocation with resource limits set

本章涵盖以下主题:

  • 设置环境
  • 创建没有资源规范的服务
  • 保留资源
  • 设置资源限制
  • 使用资源规范创建服务
  • 扩展和资源
  • 保留资源必须小于资源限制
  • 设置资源限制和储备的滚动更新
  • 资源使用和节点容量

设置环境

在 Docker 上为 AWS 创建一个三节点 Swarm,其中有一个管理节点和两个工作节点。在 Docker 上为 AWS 创建一个 Swarm 将在第三章中讨论。我们在本章中也使用了在第六章中创建的三节点蜂群。获取 Swarm manager 实例的公共 IP 地址,如图 7-7 所示。

A454123_1_En_7_Fig7_HTML.jpg

图 7-7。

EC2 instances for Swarm nodes

以用户“docker”的身份通过 SSH 登录 manager 实例。

[root@localhost ∼]# ssh -i "docker.pem" docker@52.91.115.180
Welcome to Docker!

列出群节点;列出了一个管理节点和两个工作节点。

∼ $ docker node ls
ID                          HOSTNAME                       STATUS  AVAILABILITY MANAGER STATUS
8ynq7exfo5v74ymoe7hrsghxh   ip-172-31-33-230.ec2.internal  Ready   Active       
o0h7o09a61ico7n1t8ooe281g * ip-172-31-16-11.ec2.internal   Ready   Active       Leader
yzlv7c3qwcwozhxz439dbknj4   ip-172-31-25-163.ec2.internal  Ready   Active              

创建没有资源规范的服务

我们首先创建一个没有任何资源规范的服务。创建一个 MySQL 数据库服务,不设置任何资源储备或限制。

docker service create \
  --env MYSQL_ROOT_PASSWORD='mysql'\
  --replicas 1 \
  --name mysql \
 mysql

将创建一个服务副本。该命令的输出是服务 ID(以斜体显示)。

∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 1 \

>   --name mysql \

>  mysql

2kcq6cf72t4wu94o00k3sax41

列出服务;列出了mysql服务。

∼ $ docker service ls
ID                  NAME             MODE               REPLICAS      IMAGE           PORTS
2kcq6cf72t4w        mysql            replicated         1/1           mysql:latest        

列出服务任务。唯一的服务任务正在工作节点上运行。

∼ $ docker service ps mysql
ID                  NAME                   IMAGE               NODE          DESIRED STATE       CURRENT STATE          ERROR               PORTS
sccqv4k9r22h        mysql.1                mysql:latest        ip-172-31-33-230.ec2.internal Running             Running 10 seconds ago                       

在检查服务时,容器规范不包括任何资源、限制或保留。单个服务任务可能会使用调度它的节点上的所有可用资源。

∼ $ docker service inspect mysql

[                "Resources": {                    "Limits": {},                    "Reservations": {}                },]

保留资源

Swarm 模式在docker service createdocker service update命令中提供了两个资源预留选项,如表 7-1 所示。

表 7-1。

Options for Resource Reserves

| [计]选项 | 描述 | 缺省值 | | --- | --- | --- | | `--reserve-cpu` | 储备 CPU。值`0.000`意味着没有设置储备。 | `0.000` | | `--reserve-memory` | 保留记忆。值`0`意味着没有设置储备。 | `0` |

设置资源限制

群模式在docker service createdocker service update命令中提供了两个资源限制选项,如表 7-2 中所述。

表 7-2。

Options for Resource Limits

| [计]选项 | 描述 | 缺省值 | | --- | --- | --- | | `--limit-cpu` | 限制 CPU | `0.000` | | `--limit-memory` | 限制内存 | `0` |

使用资源规范创建服务

接下来,使用资源规范创建一个服务。设置 0.25 个 CPU 和 128MB 的资源预留,以及 1 个 CPU 和 256MB 的资源限制。在创建定义了资源的新服务之前,删除先前创建的mysql服务。该命令的输出是服务 ID(以斜体显示)。

∼ $ docker service rm mysql
mysql
∼ $ docker service create \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --replicas 1 \
>   --name mysql \
>   --reserve-cpu .25 --limit-cpu 1 --reserve-memory  128mb --limit-memory 256mb \
>  mysql

abwq9budo7joyd00u32z2b047

在检查服务时,会列出资源限制和保留,这与创建服务时没有资源定义的空资源设置形成对比。

∼ $ docker service inspect mysql
[                "Resources": {                    "Limits": {                        "NanoCPUs": 1000000000,                        "MemoryBytes": 268435456                    },                    "Reservations": {                        "NanoCPUs": 250000000,                        "MemoryBytes": 134217728                    }                },]

扩展和资源

在纵向扩展服务之前,根据 CPU 和内存资源确定节点容量可能是合适的。因为群中的所有三个节点都是相同的,所以一个节点上的节点容量与其他节点上的相同。节点容量是 1 个 CPU 和 1GB,如docker node inspect命令的输出中所列。

∼ $ docker node inspect ip-172-31-16-11.ec2.internal
[
            "Resources": {
                "NanoCPUs": 1000000000,
                "MemoryBytes": 1039040512
            },
]

上一节中创建的每个服务任务的 CPU 限制也是 1 个 CPU。扩展时,节点上所有服务任务的资源限制总数可能会超过节点的容量。但是,资源预留总量不得超过节点容量。

例如,扩展到五个副本。

∼ $ docker service scale mysql=5
mysql scaled to 5

扩展到五个时,管理节点上有两个副本,一个工作节点上有两个副本,另一个工作节点上有一个副本。超过了工作节点上的资源限制的总和,但是资源保留的总和在节点的容量之内。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                      DESIRED STATE       CURRENT STATE              ERROR          PORTS
npc5r7xf98fg        mysql.1             mysql:latest        ip-172-31-16-11.ec2.internal    Running             Running 2 minutes ago                        
xokdhowntp0w        mysql.2             mysql:latest        ip-172-31-25-163.ec2.internal   Running             Running 13 seconds ago                       
b6h4bsf7xzdc        mysql.3             mysql:latest        ip-172-31-16-11.ec2.internal    Running             Running 12 seconds ago                       
j1d7ti7nb80u        mysql.4             mysql:latest        ip-172-31-33-230.ec2.internal   Running             Running 13 seconds ago                       
w6to9pxcdbm5        mysql.5             mysql:latest        ip-172-31-25-163.ec2.internal   Running             Running 13 seconds ago                       

保留资源不得超过资源限制

在计划服务任务时,不考虑资源限制,只考虑资源储备。如果运行任务所需的资源在节点容量范围内,则不设置预留(无论是否设置限制以及限制是否超过节点容量)会调度服务任务。资源储备不得超过资源限制,否则服务任务可能无法调度,或者可能会在一段时间后失败。例如,删除mysql服务,并在资源储备超过资源限制的情况下创建一个新服务。该命令的输出是服务 ID(以斜体显示)。

∼ $ docker service rm mysql
mysql
∼ $ docker service create \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --replicas 1 \
>   --name mysql \
>   --reserve-cpu .75 --limit-cpu .5 --reserve-memory  256mb --limit-memory 128mb \
>  mysql

srot5vr8x7v7iml2awc3fxb1u

服务被创建,甚至被调度。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                   DESIRED STATE       CURRENT STATE           ERROR             PORTS
pmcjrj6p3wfp        mysql.1             mysql:latest        ip-172-31-16-11.ec2.internal   Running             Running 20 seconds ago                       

服务配置的资源储备超过了资源限制。

∼ $ docker service inspect mysql
[                },                "Resources": {                    "Limits": {                        "NanoCPUs": 500000000,                        "MemoryBytes": 134217728                    },                    "Reservations": {                        "NanoCPUs": 750000000,                        "MemoryBytes": 268435456                    }                },]

资源储备在节点容量之内,但是因为资源限制小于资源储备,所以新启动的服务任务失败并被关闭。服务任务不断重启和关闭。

∼ $ docker service ps mysql
ID                  NAME             IMAGE               NODE                    DESIRED STATE       CURRENT STATE                ERROR                       PORTS
vjcnjkwfdfkb        mysql.1          mysql:latest        ip-172-31-16-11.ec2.internal   Running             Running 16 seconds ago                                  
pxdku8pxviyn         \_ mysql.1      mysql:latest        ip-172-31-16-11.ec2.internal   Shutdown            Failed 21 seconds ago       "task: non-zero exit (1)"
pmcjrj6p3wfp         \_ mysql.1      mysql:latest        ip-172-31-16-11.ec2.internal   Shutdown            Failed about a minute ago   "task: non-zero exit (1)"   

服务任务资源限制可以与资源储备相同。删除mysql服务,并使用与资源保留相同的资源限制重新创建它。该命令的输出是服务 ID(以斜体显示)。

∼ $ docker service rm mysql

mysql
∼ $ docker service create \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --replicas 1 \
>   --name mysql \
>   --reserve-cpu .5 --limit-cpu .5 --reserve-memory  256mb --limit-memory 256mb \
>  mysql

81bu63v97p9rm81xfyxv9k11e

创建服务并调度单个任务。当资源储备超过资源限制时,服务任务不会失败。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                     DESIRED STATE       CURRENT STATE      ERROR        PORTS
4i1fpha53abs        mysql.1             mysql:latest        ip-172-31-16-11.ec2.internal   Running             Running 33 seconds ago           

并启动 Docker 容器。

∼ $ docker ps
CONTAINER ID     IMAGE           COMMAND                 CREATED           STATUS      PORTS         NAMES
14d5553f0393     mysql:latest    "docker-entrypoint..."   34 seconds ago   Up 33 seconds       3306/tcp      mysql.1.4i1fpha53absl4qky9dgafo8t

滚动更新以修改资源限额和储量

本节演示了设置新的 CPU 和内存限制和预留的滚动更新。在上一节中创建的服务用于本节中的更新。使用docker service update命令,更新 CPU 和内存预留和限制。该命令的输出是服务名mysql(以斜体显示)。

∼ $ docker service update --reserve-cpu 1 --limit-cpu 2 --reserve-memory  256mb
--limit-memory 512mb mysql

mysql

资源被更新。更新服务的资源规范会关闭服务副本,并使用新的资源规范启动新的副本。

∼ $ docker service ls
ID              NAME                MODE              REPLICAS        IMAGE         PORTS
81bu63v97p9r    mysql               replicated        1/1             mysql:latest        
∼ $ docker service ps mysql
ID                  NAME                IMAGE             NODE            DESIRED STATE       CURRENT STATE             ERROR       PORTS
xkis4mirgbtv        mysql.1             mysql:latest      ip-172-31-33-230.ec2.internal   Running             Running 14 seconds ago                        
4i1fpha53abs         \_ mysql.1         mysql:latest      ip-172-31-16-11.ec2.internal    Shutdown            Shutdown 15 seconds ago                       

服务资源配置已更新。

∼ $ docker service inspect mysql
[                },                "Resources": {                    "Limits": {                        "NanoCPUs": 2000000000,                        "MemoryBytes": 536870912                    },                    "Reservations": {                        "NanoCPUs": 1000000000,                        "MemoryBytes": 268435456                    }                },]

资源使用和节点容量

资源使用不能超过节点容量。在三节点 Swarm 上(一个管理器和两个工作者节点),回想一下节点容量是 1GB 和 1 个 CPU。

删除已经运行的mysql服务,并创建一个mysql服务,它有三个请求 4GB 内存的副本。服务已创建。该命令的输出是服务 ID(以斜体显示)。

∼ $ docker service rm mysql
mysql
∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 3 \

>   --name mysql \

>   --reserve-memory=4GB\

>  mysql

cgrihwij2znn4jkfe6hswxgr7

0/3Replicas列值所示,没有服务副本被调度,因为请求的容量大于单个节点的节点容量。

∼ $ docker service ls
ID               NAME                MODE               REPLICAS      IMAGE           PORTS
cgrihwij2znn     mysql               replicated         0/3           mysql:latest        

副本的Current State列为Pending

∼ $ docker service ps mysql
ID               NAME                    IMAGE               NODE                DESIRED STATE    CURRENT STATE           ERROR               PORTS
vm7z20krx3j6     mysql.1                 mysql:latest                            Running          Pending 19 seconds ago                       
exmsheo144ef     mysql.2                 mysql:latest                            Running          Pending 19 seconds ago                       
kiset9poqz2s     mysql.3                 mysql:latest                            Running          Pending 19 seconds ago                       

如果之前运行所有副本的服务被纵向扩展,一些或所有副本可能会被取消调度。如果运行新复制副本所需的资源超过了可用的节点容量,就会发生这种情况。例如,删除mysql服务并创建一个新的mysql服务,其资源设置在一个节点的供应中。该命令的输出是服务 ID(以斜体显示)。

∼ $ docker service rm mysql

mysql
∼ $
∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 1 \

>   --name mysql \

>   --reserve-cpu .5  --reserve-memory  512mb  \

>  mysql

ysef8n02mhuwa7sxerc9jwjqx

服务被创建,单个副本正在运行,如1/1Replicas列值所示。

∼ $ docker service ls
ID               NAME              MODE              REPLICAS     IMAGE               PORTS
ysef8n02mhuw     mysql             replicated        1/1          mysql:latest        

逐步扩展服务,以确定是否所有服务副本都已安排。首先,扩展到三个副本。

∼ $ docker service scale mysql=3
mysql scaled to 3

服务描述将3/3 Replicas列为正在运行。

∼ $ docker service ls
ID              NAME         MODE                REPLICAS         IMAGE               PORTS
ysef8n02mhuw    mysql        replicated          3/3              mysql:latest        

使用分散调度策略来调度服务副本,群中的每个节点上有一个副本,这将在第八章中详细讨论。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                    DESIRED STATE       CURRENT STATE            ERROR        PORTS
8kkkdns0l690        mysql.1             mysql:latest        ip-172-31-16-11.ec2.internal    Running             Running 51 seconds ago                       
k209uge36bih        mysql.2             mysql:latest        ip-172-31-25-163.ec2.internal   Running             Running 16 seconds ago                       
oiublpclz9eu        mysql.3             mysql:latest        ip-172-31-33-230.ec2.internal   Running             Running 16 seconds ago                       

将 mysql 服务进一步扩展到副本。

∼ $ docker service scale mysql=10

mysql scaled to 10

只有 3/10 的副本被列为正在运行。

∼ $ docker service ls
ID                  NAME                MODE            REPLICAS      IMAGE          PORTS
ysef8n02mhuw        mysql               replicated      3/10          mysql:latest        

有些副本是Allocated的,但由于资源不足,没有计划在任何节点上运行。没有运行的服务副本被列出,其中Current State被设置为Pending

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                      DESIRED STATE       CURRENT STATE                ERROR               PORTS
8kkkdns0l690        mysql.1             mysql:latest        ip-172-31-16-11.ec2.internal    Running             Running about a minute ago                       
k209uge36bih        mysql.2             mysql:latest        ip-172-31-25-163.ec2.internal   Running             Running 35 seconds ago                           
oiublpclz9eu        mysql.3             mysql:latest        ip-172-31-33-230.ec2.internal   Running             Running 35 seconds ago                           
u807b7h0qvqc        mysql.4             mysql:latest                                        Running             Pending 7 seconds ago                            
jh2ep10sonxy        mysql.5             mysql:latest                                        Running             Pending 7 seconds ago                            
8d19osxa4fwf        mysql.6             mysql:latest                                        Running             Pending 7 seconds ago                            
k8hba8j5o9vi        mysql.7             mysql:latest                                        Running             Pending 7 seconds ago                            
ettk65bpin3b        mysql.8             mysql:latest                                        Running             Pending 7 seconds ago                            
i3otbqfsfvr7        mysql.9             mysql:latest                                        Running             Pending 7 seconds ago                            
sxdi970o6d3b        mysql.10            mysql:latest                                        Running             Pending 7 seconds ago                            

添加一个或多个新的工作节点可能会使服务协调其所需的状态,并导致所有副本运行。为了进行下一步演示,我们扩展了 CloudFormation 栈,以增加工作节点的数量。

向上扩展栈

要纵向扩展 CloudFormation 栈,请在 CloudFormation ➤栈表中选择 Docker 栈,然后选择操作➤更新栈,如图 7-8 所示。

A454123_1_En_7_Fig8_HTML.jpg

图 7-8。

Choosing Actions ➤ Update Stack

“更新 Docker 栈向导”启动。它类似于创建栈向导。在选择模板中,单击下一步,不修改任何设置。具体来说,增加集群工作节点的数量?至 10,如图 7-9 所示。点击下一步。

A454123_1_En_7_Fig9_HTML.jpg

图 7-9。

Increasing the number of worker nodes to 10

在预览你的修改时,点击更新,如图 7-10 所示。

A454123_1_En_7_Fig10_HTML.jpg

图 7-10。

Click Update to preview your changes

更新完成后,栈状态变为UPDATE_COMPLETE,如图 7-11 所示。

A454123_1_En_7_Fig11_HTML.jpg

图 7-11。

Stack update is complete

蜂群获得 8 个新的工作者节点,总共 10 个工作者节点。定期(间隔几秒钟后)列出服务描述,随着新工作节点的创建,新的副本开始将当前状态与所需状态相协调。Replicas列中的副本数量在几秒钟内逐渐增加。如服务列表中的10/10所示,mysql服务的所有副本开始运行。

∼ $ docker service ls
ID                  NAME                MODE          REPLICAS       IMAGE          PORTS
ysef8n02mhuw        mysql               replicated    3/10           mysql:latest        
∼ $ docker service ls
ID                  NAME                MODE          REPLICAS       IMAGE          PORTS
ysef8n02mhuw        mysql               replicated    6/10           mysql:latest        
∼ $ docker service ls
ID                  NAME                MODE          REPLICAS       IMAGE          PORTS
ysef8n02mhuw        mysql               replicated    9/10           mysql:latest        
∼ $ docker service ls
ID                  NAME                MODE          REPLICAS       IMAGE          PORTS
ysef8n02mhuw        mysql               replicated    10/10          mysql:latest        

列出服务副本会将所有副本列为Running。先前的Pending副本被安排在新节点上。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                            DESIRED STATE       CURRENT STATE               ERROR               PORTS
8kkkdns0l690        mysql.1             mysql:latest        ip-172-31-16-11.ec2.internal    Running             Running 7 minutes ago                            
k209uge36bih        mysql.2             mysql:latest        ip-172-31-25-163.ec2.internal   Running             Running 6 minutes ago                            
oiublpclz9eu        mysql.3             mysql:latest        ip-172-31-33-230.ec2.internal   Running             Running 6 minutes ago                            
u807b7h0qvqc        mysql.4             mysql:latest        ip-172-31-11-105.ec2.internal   Running             Running 45 seconds ago                           
jh2ep10sonxy        mysql.5             mysql:latest        ip-172-31-13-141.ec2.internal   Running             Running about a minute ago                       
8d19osxa4fwf        mysql.6             mysql:latest        ip-172-31-24-10.ec2.internal    Running             Running about a minute ago                       
k8hba8j5o9vi        mysql.7             mysql:latest        ip-172-31-0-114.ec2.internal    Running             Running 55 seconds ago                           
ettk65bpin3b        mysql.8             mysql:latest        ip-172-31-5-127.ec2.internal    Running             Running about a minute ago                       
i3otbqfsfvr7        mysql.9             mysql:latest        ip-172-31-35-209.ec2.internal   Running             Running 24 seconds ago                           
sxdi970o6d3b        mysql.10            mysql:latest        ip-172-31-21-57.ec2.internal    Running             Running 49 seconds ago                           

如果再次更新栈以减少工作节点的数量,一些副本将关闭并取消调度。在减少工作节点的数量后,Replicas列只列出了正在运行的5/10个副本。

∼ $ docker service ls
ID                  NAME                MODE           REPLICAS       IMAGE           PORTS
ysef8n02mhuw        mysql               replicated     5/10           mysql:latest        

一些服务任务被列为Shutdown,因为一些工作者节点已经从群中移除。

∼ $ docker service ps mysql
ID                  NAME                IMAGE               NODE                           DESIRED STATE       CURRENT STATE             ERROR              PORTS
8kkkdns0l690        mysql.1             mysql:latest        ip-172-31-16-11.ec2.internal    Running             Running 10 minutes ago                           
ulknt3e5zxy1        mysql.2             mysql:latest                                        Ready               Pending 3 seconds ago                            
k209uge36bih         \_ mysql.2         mysql:latest        ip-172-31-25-163.ec2.internal   Shutdown            Running 14 seconds ago                           
oiublpclz9eu        mysql.3             mysql:latest        ip-172-31-33-230.ec2.internal   Running             Running 9 minutes ago                            
mh2fpioi441k        mysql.4             mysql:latest                          Running             Pending 3 seconds ago                
u807b7h0qvqc        \_ mysql.4          mysql:latest        v53huw84hskqsb3e8o0a2pmun       Shutdown            Running about a minute ago            
jzghd72nk0zc        mysql.5             mysql:latest                                        Ready               Pending 3 seconds ago                            
jh2ep10sonxy        \_ mysql.5         mysql:latest         ip-172-31-13-141.ec2.internal   Shutdown            Running 14 seconds ago                           
8d19osxa4fwf        mysql.6             mysql:latest        ip-172-31-24-10.ec2.internal    Running             Running 4 minutes ago                            
dlcgstxxkd9t        mysql.7             mysql:latest                                        Running             Pending 3 seconds ago                            
ziqslz7u9d9l        \_ mysql.7         mysql:latest         ip-172-31-43-179.ec2.internal   Shutdown            Assigned 57 seconds ago                          
k8hba8j5o9vi        \_ mysql.7         mysql:latest         op1dzvmt5eyc74l6pcl5ut64p       Shutdown            Running about a minute ago                       
ettk65bpin3b        mysql.8             mysql:latest        ip-172-31-5-127.ec2.internal    Running             Running 4 minutes ago                            
i3otbqfsfvr7        mysql.9             mysql:latest        ip-172-31-35-209.ec2.internal   Running             Running 3 minutes ago                            
sxdi970o6d3b        mysql.10            mysql:latest        ip-172-31-21-57.ec2.internal    Running             Running 12 seconds ago                           

摘要

本章讨论了基于资源储备和资源限制的 Docker Swarm 模式的资源模型。预留资源不能超过资源限制,分配给服务任务的资源受节点容量的限制。下一章讨论 Docker 群模式下的调度。

八、调度

在第二章,介绍了 Docker Swarm。在第四章中,介绍了 Docker 群服务。一个服务由零个或多个服务任务(副本)组成,它在集群中的节点上调度这些任务。服务的期望状态包括必须运行的任务数量。调度被定义为将需要运行的服务任务放置在集群中的一个节点上以保持服务的期望状态的过程,如图 8-1 所示。只能在工作节点上计划服务任务。默认情况下,管理器节点也是工作者节点。

A454123_1_En_8_Fig1_HTML.gif

图 8-1。

Scheduling

问题

如果没有调度策略,服务任务可能会被调度到群中的一个节点子集上。例如,一个服务中的所有三个任务都可以在一个群中的同一个节点上被调度,如图 8-2 所示。

A454123_1_En_8_Fig2_HTML.gif

图 8-2。

Avoid scheduling all tasks on one node

不使用调度策略可能会导致以下问题:

  • 群中资源利用不足—如果所有任务都在单个节点或节点子集上调度,则其他节点的资源容量没有得到利用。
  • 资源利用不均衡—如果所有任务都安排在单个节点或节点子集上,则安排任务的节点上的资源会被过度利用,任务甚至会用尽所有资源容量,而没有扩展副本的余地。
  • 缺乏局部性—客户端基于节点位置访问服务的任务。如果所有服务任务都被安排在单个节点上,则在其他节点上访问服务的外部客户端不能本地访问服务,从而在访问相对远程的任务时导致网络开销。
  • 单点故障—如果所有服务都在一个节点上运行,而该节点出现问题,就会导致停机。增加节点间的冗余可以避免这个问题。

解决方案

为了克服前面讨论的问题,Docker 群中的服务任务调度是基于一个内置的调度策略。Docker Swarm 模式使用分散调度策略对节点进行排序,以放置服务任务(副本)。为每个任务的调度计算节点排序,并且在具有最高计算排序的节点上调度任务。分布调度策略根据节点的可用 CPU、RAM 和已经在节点上运行的容器数量来计算节点等级。传播策略针对容器数量最少的节点进行优化。负载共享是分布策略的目标,它导致任务(容器)稀疏而均匀地分布在集群中的几台机器上。传播策略的预期结果是,如果单个节点或节点的一个小子集宕机或变得可用,则只有少数任务丢失,而群中的大多数任务继续可用。

Note

因为容器在所有状态下都会消耗资源,包括退出时,所以扩展策略不会考虑容器的状态。建议用户删除已停止的容器,因为如果某个节点有几个已停止的容器,那么该节点将变得不适合调度新任务。

扩展调度策略不考虑为哪个服务调度任务。只有可用的和请求的资源被用于调度新的任务。图 8-3 显示了使用扩展调度策略的调度。

A454123_1_En_8_Fig3_HTML.gif

图 8-3。

Using the spread scheduling policy

举个假设的例子:

  1. 从三个节点开始,每个节点有 3GB 的容量和 3 个 CPU,并且没有容器运行。
  2. 创建一个带有一个副本的mysql服务,它需要 1GB 和 1 个 CPU 的资源。第一个副本被随机安排在群中三个节点中的一个上,因为所有节点都具有相同的排名。如果所有的节点都有相同的等级,一个新的任务会被随机安排在其中一个节点上。
  3. mysql服务扩展为三个任务。由于其中一个节点已经加载,这两个新任务被安排在另外两个节点上,将一个任务分配给每个节点。
  4. mysql服务扩展到五个任务。必须启动两个新任务,并且所有节点都具有相同的等级,因为它们具有相同的可用资源容量和相同数量的正在运行的容器。这两个新任务随机安排在两个节点上。因此,两个节点各有两个任务,一个节点有一个任务。
  5. nginx服务器创建另一个服务,需要两个任务,每个任务需要 0.5GB 和 0.5 CPU。这两个任务都被安排在只有mysql服务任务的节点上,因为它负载最小。因此,两个节点有两个mysql服务任务和 1GB 和 1 个 CPU 的可用容量,一个节点有两个nginx服务任务和一个mysql服务任务以及 1GB 和 1 个 CPU 的可用资源容量。
  6. nginx服务扩展到三个。即使所有节点都有相同的可用 CPU 和 RAM,新任务也不会随机安排在三个节点中的一个上,而是安排在容器数量最少的节点上。结果,新的nginx任务被随机安排在其中一个节点上,每个节点有两个mysql任务。如果节点具有相同的可用 CPU 和 RAM,则选择具有较少容器(运行或停止)的节点来调度新任务。

本章涵盖以下主题:

  • 设置环境
  • 创建和计划服务—扩展计划
  • 期望的国家和解
  • 受节点资源容量限制的任务调度
  • 添加服务调度约束
  • 在特定节点上调度
  • 添加多个日程排定限制
  • 为调度添加节点标签
  • 添加、更新和删除服务调度约束
  • 扩展调度和全球服务

设置环境

使用 Docker for AWS 创建一个由一个管理节点和两个工作节点组成的 CloudFormation 栈。AWS 的 Docker 在第三章中介绍。栈如图 8-4 所示。

A454123_1_En_8_Fig4_HTML.jpg

图 8-4。

CloudFormation stack

栈中的三个 EC2 实例如图 8-5 所示。

A454123_1_En_8_Fig5_HTML.jpg

图 8-5。

EC2 instances for the Docker swarm

使用公共 IP 地址 SSH 登录到 Swarm manager,该地址可以从 EC2 控制台获得,如图 8-5 所示。

[root@localhost ∼]# ssh -i "docker.pem" docker@54.84.133.157
Welcome to Docker!

列出群体中的节点;应该列出三个节点。

∼ $ docker node ls
ID                           HOSTNAME                       STATUS  AVAILABILITY  MANAGER STATUS
0waa5g3b6j641xtwsygvjvwc1    ip-172-31-0-147.ec2.internal   Ready   Active              
e7vigin0luuo1kynjnl33v9pa    ip-172-31-29-67.ec2.internal   Ready   Active              
ptm7e0p346zwypos7wnpcm72d *  ip-172-31-25-121.ec2.internal  Ready   Active        Leader

创建和计划服务:扩展计划

首先,我们以 MySQL 数据库服务为例来讨论默认的扩展调度。从 Swarm manager 节点,运行以下命令为 MySQL 创建一个五副本服务。输出是服务 ID(以斜体显示)。

∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 5 \

>   --name mysql \

>  mysql

1onpemnoz4x1lh3sv5umab8uo

随后,使用docker service ls列出服务。最初,REPLICAS列可能是0/5,表示没有副本被调度和运行。

∼ $ docker service ls
ID             NAME    MODE         REPLICAS   IMAGE          PORTS
1onpemnoz4x1   mysql   replicated   0/5        mysql:latest   

过一会儿再次运行该命令;所有副本应该都在运行,如REPLICAS列中的5/5所示。使用docker service ps mysql命令列出服务副本。任务应该正在运行或准备运行。

∼ $ docker service ps mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE             ERROR    PORTS
fwjbu3gt2zn0    mysql.1    mysql:latest    ip-172-31-0-147.ec2.internal    Running          Preparing 8 seconds ago                       
w0521ik1awjf    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Preparing 8 seconds ago                       
z9wn2nrzfzt8    mysql.3    mysql:latest    ip-172-31-0-147.ec2.internal    Running          Preparing 8 seconds ago                       
tm8jbque3xbb    mysql.4    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Preparing 8 seconds ago                       
7drxfy3vbmp5    mysql.5    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Preparing 8 seconds ago                       

按照分布调度策略,其中两个副本在一个工作节点上按计划列出,两个在另一个工作节点上,一个在管理器节点上。由于副本的数量为奇数,所以位置不能完全均匀分布,但是单个节点不会有两个以上的副本。

要查看分布调度策略如何在整个群中均匀地分布副本,请将服务扩展到六个副本。docker service scale命令的输出以斜体显示。

∼ $ docker service scale mysql=6

mysql scaled to 6

随后,列出副本。每个节点上都安排了两个复制副本,因为扩展计划策略旨在计划。

∼ $ docker service ps mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
fwjbu3gt2zn0    mysql.1    mysql:latest    ip-172-31-0-147.ec2.internal    Running          Running 13 seconds ago                       
w0521ik1awjf    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 12 seconds ago                       
z9wn2nrzfzt8    mysql.3    mysql:latest    ip-172-31-0-147.ec2.internal    Running          Running 13 seconds ago                       
tm8jbque3xbb    mysql.4    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 8 seconds ago                        
7drxfy3vbmp5    mysql.5    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 12 seconds ago                       
utjo8lwbtzf7    mysql.6    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 5 seconds ago                        

因为服务副本或任务只不过是运行容器的一个槽,所以每个节点为mysql服务运行两个容器。

为了进一步演示扩展调度,将服务缩减为三个任务。命令输出以斜体显示。

∼ $ docker service scale mysql=3

mysql scaled to 3

列出服务任务。每个节点上运行一个任务,这也是一个均匀分布的任务调度。

∼ $ docker service ps mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
w0521ik1awjf    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 40 seconds ago                       
z9wn2nrzfzt8    mysql.3    mysql:latest    ip-172-31-0-147.ec2.internal    Running          Running 41 seconds ago                       
utjo8lwbtzf7    mysql.6    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 33 seconds ago                       

期望的国家和解

当一个服务被创建或者被放大或缩小时,该服务最初在当前状态和期望状态之间存在差异。期望状态的不同值是readyrunningshutdownaccepted。Docker 服务是为期望的状态协调而设计的,这意味着群管理器持续监视集群状态,以协调服务的期望状态和当前状态之间的任何差异。任务的当前状态可以是assignedpreparingreadyrunningshutdownpending。已经分配给节点但当前未运行的任务处于assigned状态。期望状态为running并准备运行的任务处于preparing当前状态。如果群中没有节点可以运行任务,则该任务处于pending状态。

在下面的任务列表中,一些任务具有期望状态和当前状态running。这些任务已经协调了它们期望的状态。一个任务的期望状态被设置为running,但是当前状态是pending。另一个任务的期望状态设置为shutdown,当前状态设置为assigned

∼ $ docker service ps mysql
ID              NAME          IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
opxf4ne7iyy6    mysql.1       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 9 minutes ago                         
x30y3jlea047    mysql.2       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 8 minutes ago                         
w4ivsbvwqqzq    mysql.3       mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 4 minutes ago                         
j9lp08ojofj7    mysql.4       mysql:latest                                        Running          Pending 28 seconds ago                        
ph1zpsjsvp69     \_ mysql.4   mysql:latest    ip-172-31-7-137.ec2.internal    Shutdown         Assigned 33 seconds ago                       
d3oxy6hxfjh3     \_ mysql.4   mysql:latest    ip-172-31-40-70.ec2.internal    Shutdown         Running 43 seconds ago                        
ic331aasjpdm    mysql.5       mysql:latest    ip-172-31-44-104.ec2.internal   Running          Running 8 minutes ago                         

在早期的任务列表中,所有任务都处于当前状态preparing和期望状态running

群模式旨在尽可能地协调所需的状态,这意味着如果节点资源可用,将运行所需数量的副本。为了进行演示,通过选择操作➤更新栈来更新 AWS CloudFormation 栈的 Docker,如图 8-6 所示。

A454123_1_En_8_Fig6_HTML.jpg

图 8-6。

Updating a stack

将工作节点的数量从两个减少到一个,如图 8-7 所示。

A454123_1_En_8_Fig7_HTML.jpg

图 8-7。

Decreasing the number of worker nodes to one

随后,列出来自 Swarm manager 节点的服务副本。

docker service ps mysql

在离开群的群工作者节点上运行的服务副本被列为shutdown。在群中剩余的两个节点上开始新的副本以协调期望的状态。

∼ $ docker service ps mysql
ID              NAME          IMAGE           NODE                            DESIRED STATE    CURRENT STATE                 ERROR    PORTS
p14bbk7ij1mt    mysql.1       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 5 minutes ago                            
w0521ik1awjf    mysql.2       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 7 minutes ago                            
uatsaay7axlc    mysql.3       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running about a minute ago                      
z9wn2nrzfzt8     \_ mysql.3   mysql:latest    0waa5g3b6j641xtwsygvjvwc1       Shutdown         Running 2 minutes ago                            
w1tlw0fom42q    mysql.4       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running about a minute ago                       
qc75buhzzct3     \_ mysql.4   mysql:latest    0waa5g3b6j641xtwsygvjvwc1    Shutdown         Running 2 minutes ago                            
s09ts9s8np3d    mysql.5       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 5 minutes ago                            
utjo8lwbtzf7    mysql.6       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 7 minutes ago                            

仅列出所需状态为running的副本,六个副本在两个节点之间按计划平均列出—三个副本在管理节点上,三个副本在工作节点上。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE            ERROR    PORTS
p14bbk7ij1mt    mysql.1    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 6 minutes ago                       
w0521ik1awjf    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 8 minutes ago                       
uatsaay7axlc    mysql.3    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 2 minutes ago                       
w1tlw0fom42q    mysql.4    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 2 minutes ago                       
s09ts9s8np3d    mysql.5    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 6 minutes ago                       
utjo8lwbtzf7    mysql.6    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 8 minutes ago                       

如果新的节点被添加到群中,传播调度策略不重新调度已经运行的副本来实现群中的均匀传播。为了演示这一点,我们将工作节点的数量增加回两个,如图 8-8 所示。

A454123_1_En_8_Fig8_HTML.jpg

图 8-8。

Re-adding a worker node to Swarm

将一个节点添加到群中不会关闭其他节点上的副本并在新节点上启动副本。列出正在运行的副本并不表示服务副本的替换。在添加新节点之前,服务副本继续在运行它们的节点上运行,其中三个在管理节点上,三个在工作节点上。

∼ $ docker service ps mysql
ID              NAME          IMAGE           NODE                            DESIRED STATE    CURRENT STATE             ERROR    PORTS
p14bbk7ij1mt    mysql.1       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 15 minutes ago                       
w0521ik1awjf    mysql.2       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 17 minutes ago                       
uatsaay7axlc    mysql.3       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 12 minutes ago                       
z9wn2nrzfzt8     \_ mysql.3   mysql:latest    0waa5g3b6j641xtwsygvjvwc1       Shutdown         Running 13 minutes ago                       
w1tlw0fom42q    mysql.4       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 12 minutes ago                       
qc75buhzzct3     \_ mysql.4   mysql:latest    0waa5g3b6j641xtwsygvjvwc1       Shutdown         Running 13 minutes ago                       
s09ts9s8np3d    mysql.5       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 15 minutes ago                       
utjo8lwbtzf7    mysql.6       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 17 minutes ago                       

受节点资源容量限制的任务调度

调度策略受到可用节点资源的限制,这意味着如果没有足够的节点资源(CPU 和内存)可用,就无法运行服务副本。资源使用不能超过节点容量。副本仍被分配给服务以定义所需的状态,但由于资源不足,可能不会运行。为了演示这一点,我们删除服务mysql并使用指定的资源请求和限制再次创建服务。命令输出以斜体显示。

∼ $ docker service rm mysql

mysql

∼ $ docker service create \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --replicas 1 \
>   --name mysql \
>   --reserve-cpu 1 --limit-cpu 2 --reserve-memory  256mb --limit-memory 512mb mysql

0qe2thy0dlviroli6k8thist1

列出服务表明创建了服务的一个副本。

∼ $ docker service ls
ID              NAME     MODE          REPLICAS    IMAGE           PORTS
0qe2thy0dlvi    mysql    replicated    1/1         mysql:latest    

单个副本被调度在管理节点上,如果群中的所有节点具有相同的节点排名,则管理节点被随机选择。

∼ $ docker service ps mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE            ERROR               PORTS
opxf4ne7iyy6    mysql.1    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 8 seconds ago                       

接下来,为了潜在地使服务副本消耗比可用资源更多的资源,将服务扩展到五个副本。

∼ $ docker service scale mysql=5

mysql scaled to 5

列出服务表明3/5 Replicas正在运行。

∼ $ docker service ls
ID              NAME     MODE          REPLICAS    IMAGE           PORTS
0qe2thy0dlvi    mysql    replicated    3/5         mysql:latest    

列出服务副本表明一些副本是pending而不是running

∼ $ docker service ps mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE            ERROR    PORTS
opxf4ne7iyy6    mysql.1    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 4 minutes ago                       
x30y3jlea047    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 3 minutes ago                       
w4ivsbvwqqzq    mysql.3    mysql:latest                                        Running          Pending 3 minutes ago                       
d3oxy6hxfjh3    mysql.4    mysql:latest                                        Running          Pending 3 minutes ago                       
ic331aasjpdm    mysql.5    mysql:latest    ip-172-31-44-104.ec2.internal   Running          Running 3 minutes ago                       

pending状态意味着副本被分配给服务,但是还没有在任何节点上被调度。根据请求的资源和可用的节点资源,只能运行三个副本,每个节点一个。

因为由于缺乏资源而没有调度副本,所以我们添加一个或多个新的工作节点来潜在地调度副本以协调期望的状态。将工作节点的数量增加到 5 个,如图 8-9 所示。

A454123_1_En_8_Fig9_HTML.jpg

图 8-9。

Increasing the number of worker nodes to five

在添加一个新节点后,Swarm 应该列出六个节点。随着资源变得可用于pending任务,任务得到调度并开始运行。

∼ $ docker service ps mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE       CURRENT STATE              ERROR               PORTS
opxf4ne7iyy6    mysql.1    mysql:latest    ip-172-31-25-121.ec2.internal   Running             Running 5 minutes ago                          
x30y3jlea047    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal    Running             Running 4 minutes ago                          
w4ivsbvwqqzq    mysql.3    mysql:latest    ip-172-31-2-177.ec2.internal    Running             Running 21 seconds ago                         
d3oxy6hxfjh3    mysql.4    mysql:latest    ip-172-31-40-70.ec2.internal    Running             Preparing 30 seconds ago                       
ic331aasjpdm    mysql.5    mysql:latest    ip-172-31-44-104.ec2.internal   Running             Running 4 minutes ago                          

如果工作者节点的数量减少,一些任务被重新调度,如shutdown期望状态所示。

∼ $ docker service ps mysql
ID              NAME          IMAGE           NODE                            DESIRED STATE    CURRENT STATE             ERROR    PORTS
opxf4ne7iyy6    mysql.1       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 9 minutes ago                         
x30y3jlea047    mysql.2       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 8 minutes ago                         
w4ivsbvwqqzq    mysql.3       mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 4 minutes ago                         
j9lp08ojofj7    mysql.4       mysql:latest                                        Running          Pending 28 seconds ago                        
ph1zpsjsvp69     \_ mysql.4   mysql:latest    ip-172-31-7-137.ec2.internal    Shutdown         Assigned 33 seconds ago                       
d3oxy6hxfjh3     \_ mysql.4   mysql:latest    ip-172-31-40-70.ec2.internal    Shutdown         Running 43 seconds ago                        
ic331aasjpdm    mysql.5       mysql:latest    ip-172-31-44-104.ec2.internal   Running          Running 8 minutes ago                         

更新服务以降低保留的 CPU 和内存资源使用率只会更新服务的UpdateConfig。这不会降低已经运行的任务的资源使用率,也不会使pendingshutdown任务运行。例如,当一些任务由于缺乏资源而处于pendingshutdown时,降低mysql服务的资源储备和限制。

∼ $ docker service update --reserve-cpu .1 --limit-cpu .5 --reserve-memory  64mb
 --limit-memory 128mb mysql

mysql

UpdateConfig被修改,但仅适用于在该点之后创建的新副本。

∼ $ docker service inspect mysql
[                },                "Resources": {                    "Limits": {                        "NanoCPUs": 500000000,                        "MemoryBytes": 134217728                    },                    "Reservations": {                        "NanoCPUs": 100000000,                        "MemoryBytes": 67108864                    }                },]

mysql服务中只有三个副本在实际运行。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE            ERROR    PORTS
opxf4ne7iyy6    mysql.1    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 10 minutes ago                       
x30y3jlea047    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 10 minutes ago                       
w4ivsbvwqqzq    mysql.3    mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 5 minutes ago                        
rm9uj4qevt5b    mysql.5    mysql:latest                                        Running          Pending 33 seconds ago                       

要强制服务任务使用新的资源设置,请将服务缩减为一个任务,然后再缩减为五个任务。

∼ $ docker service scale mysql=1

mysql scaled to 1

∼ $ docker service scale mysql=5

mysql scaled to 5

所有五个任务现在都在运行。

∼ $ docker service ps mysql
ID              NAME          IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
anai3mptbnkp    mysql.1       mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 17 seconds ago                        
opxf4ne7iyy6     \_ mysql.1   mysql:latest    ip-172-31-25-121.ec2.internal   Shutdown         Shutdown 18 seconds ago                       
lmkn8l50t334    mysql.2       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 10 seconds ago                        
7uz7q86wnzn4    mysql.3       mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 11 seconds ago                        
ubh4m39aw8m9    mysql.4       mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 11 seconds ago                        
56pnrzajogvs    mysql.5       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 10 seconds ago                        

添加服务调度约束

Docker Swarm 支持放置或调度约束来调度新任务。服务放置约束是放置服务任务的附加标准,可以基于节点属性、元数据和引擎元数据。群调度器使用以下序列来调度服务任务。

  1. 节点是否满足所有放置约束?
  2. 一个节点是否满足均匀分布的调度策略要求?
  3. 节点是否有足够的资源来调度任务?

可通过docker service create命令使用--constraint选项添加一个布局约束。对于一个已经运行的服务,可以分别使用--constraint-add--constraint-rm选项和docker service update命令添加和删除约束。表 8-1 中讨论的节点属性可用于指定约束。

表 8-1。

Node Attributes for Constraints

| 节点属性 | 描述 | 例子 | | --- | --- | --- | | `node.id` | 指定节点 ID。使用`docker node ls`命令列出节点 id。 | `node.id==a3r56hj7y` | | `node.hostname` | 指定节点的主机名。使用`docker node ls`命令列出了节点的主机名。 | `node.hostname!=ip-10-0-0-ec2.internal` | | `node.role` | 指定节点角色,它是`worker`或`manager`之一。 | `node.role==manager` | | `node.labels` | 指定用户添加的节点标签。标签是一个键值对。添加节点标签时,`node.labels.`前缀将被省略,并自动添加。添加和使用节点标签将在后续章节中讨论。 | `node.labels.db==mysql` | | `engine.labels` | Docker 引擎标签,如驱动程序、操作系统、版本。 | `engine.labels.os==coreos` |

接下来,我们讨论一些使用调度约束的例子。

在特定节点上调度

在本节中,我们将在集群中的特定节点上调度服务副本。用docker node ls命令列出节点 id。Swarm 有以下三个可用于调度的节点。

∼ $ docker node ls
ID                           HOSTNAME                       STATUS  AVAILABILITY  MANAGER STATUS
81h6uvu8uq0emnovzkg6v7mzg    ip-172-31-2-177.ec2.internal   Ready   Active              
e7vigin0luuo1kynjnl33v9pa    ip-172-31-29-67.ec2.internal   Ready   Active              
ptm7e0p346zwypos7wnpcm72d *  ip-172-31-25-121.ec2.internal  Ready   Active        Leader

我们可以按节点角色安排服务。创建一个mysql服务,其位置约束是服务任务只能在工作节点上调度。首先,删除已经运行的mysql服务

∼ $ docker service rm mysql
mysql
∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 3 \


>   --constraint node.role==worker \


>   --name mysql \

>  mysql

nzgte4zac1x8itx6t98y5gi42

创建了服务,并且仅在两个 worker 节点上调度了三个任务,如正在运行的服务任务中所列。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                           DESIRED STATE    CURRENT STATE              ERROR    PORTS
f5t15mnrft0h    mysql.1    mysql:latest    ip-172-31-29-67.ec2.internal   Running          Running 19 seconds ago                       
oxvq4ljuq6yz    mysql.2    mysql:latest    ip-172-31-2-177.ec2.internal   Running          Running 19 seconds ago                       
k5jo862lvsxf    mysql.3    mysql:latest    ip-172-31-2-177.ec2.internal   Running          Running 19 seconds ago                       

接下来,我们使用节点 ID 来调度服务的任务。复制管理节点的节点 ID,它也是群中的领导者,是唯一的管理节点。在下面的命令中替换节点 ID,为 MySQL 数据库创建一个服务,并只在 manager 节点上调度副本。

docker service create \
  --env MYSQL_ROOT_PASSWORD='mysql'\
  --replicas 3 \
  --constraint  node.id ==<nodeid>
  --name mysql \
 mysql

创建服务有三个任务。命令输出以斜体显示。

∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 3 \

>   --constraint  node.id==ptm7e0p346zwypos7wnpcm72d\

>   --name mysql \

>  mysql

u1qi6zqnch9hn7x6k516axg7h

该服务的所有三个副本仅在管理器节点上进行调度。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
lbttu95qdjvy    mysql.1    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 21 seconds ago                       
89x0z94on0fb    mysql.2    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 21 seconds ago                       
3s6508aimdaj    mysql.3    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 22 seconds ago                       

添加多个日程排定限制

还可以指定多个节点约束,并且必须使用AND来满足每个约束表达式,以便调度程序在节点上调度副本。例如,我们创建一个具有两个角色的服务,一个将节点角色约束为 worker,另一个将节点主机名约束为不是特定的主机名ip-172-31-2-177.ec2.internal

∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 3 \

>   --constraint node.role==worker \

>   --constraint   node.hostname!=ip-172-31-2-177.ec2.internal\

>   --name mysql \

>  mysql

87g0c8kauhz8yb4wv2ryc2vqr

服务被创建。列出服务会将3/3 replicas列为正在运行。

∼ $ docker service ls
ID             NAME    MODE         REPLICAS   IMAGE          PORTS
87g0c8kauhz8   mysql   replicated   3/3        mysql:latest   

列出服务任务表明所有任务都被安排在单个工作节点上。满足两个约束:该节点是一个工作节点,而不是主机名为ip-172-31-2-177.ec2.internal的工作节点。

∼ $ docker service ps mysql
ID              NAME       IMAGE           NODE                           DESIRED STATE    CURRENT STATE              ERROR    PORTS
jlfk79mb6m6a    mysql.1    mysql:latest    ip-172-31-29-67.ec2.internal   Running          Running 13 seconds ago                       
if5y39ky884q    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal   Running          Running 13 seconds ago                       
zctm6mzbl4du    mysql.3    mysql:latest    ip-172-31-29-67.ec2.internal   Running          Running 13 seconds ago                       

如果mysql服务被更新以移除约束,则扩展调度策略基于节点排序来重新调度任务。例如,更新服务以移除添加的两个放置约束。使用docker service update命令的–constraint-rm选项删除一个约束。

∼ $ docker service update \
>   --constraint-rm node.role==worker \
>   --constraint-rm   node.hostname!=ip-172-31-2-177.ec2.internal\
>  mysql

mysql

当服务被更新以移除约束时,所有服务任务被关闭,并且新的服务任务被启动。开始新的服务任务,在群中的三个节点上各一个。

∼ $ docker service ps mysql
ID              NAME          IMAGE           NODE                            DESIRED STATE    CURRENT STATE                   ERROR    PORTS
d22bkgteivot    mysql.1       mysql:latest    ip-172-31-29-67.ec2.internal    Ready            Ready less than a second ago                       
jlfk79mb6m6a     \_ mysql.1   mysql:latest    ip-172-31-29-67.ec2.internal    Shutdown         Running 1 second ago                               
mp757499j3io    mysql.2       mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 1 second ago                               
if5y39ky884q     \_ mysql.2   mysql:latest    ip-172-31-29-67.ec2.internal    Shutdown         Shutdown 2 seconds ago                             
jtdxucteb0fl    mysql.3       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 4 seconds ago                              
zctm6mzbl4du     \_ mysql.3   mysql:latest    ip-172-31-29-67.ec2.internal    Shutdown         Shutdown 5 seconds ago                             

仅列出正在运行的任务。列出了每个节点上运行的一个任务。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
d22bkgteivot    mysql.1    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 46 seconds ago                       
mp757499j3io    mysql.2    mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 49 seconds ago                       
jtdxucteb0fl    mysql.3    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 53 seconds ago                       

类似地,多节点约束可用于仅在管理器节点上运行副本。接下来,我们更新mysql服务以在特定的管理器节点上运行。首先,将一个 worker 节点提升为 manager。

∼ $ docker node promote ip-172-31-2-177.ec2.internal

Node ip-172-31-2-177.ec2.internal promoted to a manager in the swarm.

随后,列出了两个管理器节点,如其中两个节点的Manager Status所示。

∼ $ docker node ls
ID                           HOSTNAME                       STATUS  AVAILABILITY  MANAGER STATUS
81h6uvu8uq0emnovzkg6v7mzg    ip-172-31-2-177.ec2.internal   Ready   Active        Reachable
e7vigin0luuo1kynjnl33v9pa    ip-172-31-29-67.ec2.internal   Ready   Active        
ptm7e0p346zwypos7wnpcm72d *  ip-172-31-25-121.ec2.internal  Ready   Active        Leader

更新mysql服务以添加多个节点约束,从而仅在特定的管理器节点上运行副本。使用docker service update命令的--constraint-add选项添加约束。

∼ $ docker service update \
>   --constraint-add node.role==manager \
>   --constraint-add   node.hostname==ip-172-31-2-177.ec2.internal\
>  mysql

mysql

同样,所有服务任务被关闭,新任务被启动,所有这些都在从 worker 节点升级的指定 manager 节点上进行。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                           DESIRED STATE    CURRENT STATE              ERROR    PORTS
eghm1or6yg5g    mysql.1    mysql:latest    ip-172-31-2-177.ec2.internal   Running          Running 28 seconds ago                       
bhfngac5ssm7    mysql.2    mysql:latest    ip-172-31-2-177.ec2.internal   Running          Running 22 seconds ago                       
ts3fgvq900os    mysql.3    mysql:latest    ip-172-31-2-177.ec2.internal   Running          Running 25 seconds ago                       

为调度添加节点标签

接下来,我们讨论如何使用节点标签来指定服务放置约束。可以使用以下命令语法向节点添加标签,其中变量为<LABELKEY><LABELVALUE><NODE><NODE>是节点 ID 或主机名。

docker node update --label-add  <LABELKEY>=<LABELVALUE>  <NODE>

例如,将标签db=mysql添加到主机名设置为ip-172-31-25-121.ec2.internal的节点,该节点是领导者节点。

∼ $ docker node update --label-add  db=mysql  ip-172-31-25-121.ec2.internal
ip-172-31-25-121.ec2.internal

添加一个节点标签。检查节点时,标签列在Labels字段中。

∼ $ docker node inspect ip-172-31-25-121.ec2.internal
[
        "Spec": {
            "Labels": {
                "db": "mysql"
            },
            "Role": "manager",
            "Availability": "active"
        },
]

接下来,创建一个使用节点标签添加放置约束的服务。标签的- constraint 选项必须包括前缀 node.labels。

∼ $ docker service rm mysql
mysql
∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 3 \


>   --constraint node.labels.db==mysql \


>   --name mysql \

>  mysql

2hhccmj9senseazbet11dekoa

服务已创建。列出任务会列出领导者管理器节点上的所有任务,这是节点标签约束所指定的。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
g5jz9im3fufv    mysql.1    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 18 seconds ago                       
bupr27bs57h1    mysql.2    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 18 seconds ago                       
5bb2yf8aehqn    mysql.3    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 18 seconds ago                       

添加的标签可通过docker node update命令的--label-rm选项移除,其中仅指定了标签键。

docker node update --label-rm  db  ip-172-31-25-121.ec2.internal   

添加、更新和删除服务调度约束

在前面的部分中,我们讨论了在使用docker service create创建服务时添加位置约束。可使用--constraint-add--constraint-rm选项通过docker service update命令添加/删除布局约束。为了讨论一个更新布局约束的例子,我们创建了一个mysql服务,它有三个副本,开始时没有布局约束。

∼ $ docker service rm mysql
mysql
∼ $ docker service create \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --replicas 3 \

>   --name mysql \

>  mysql

az3cq6sxwrrk4mxkksdu21i25

一个mysql服务被创建,在集群中的三个节点上调度三个副本,使用传播策略。

接下来,用docker service update命令更新服务,为服务副本添加一个仅在管理器节点上运行的约束。

∼ $ docker service update \
>  --constraint-add node.role==manager \
>  mysql

mysql

在具有两个管理节点的群中,所有服务任务都被关闭,新任务只在管理节点上启动。

∼ $ docker service ps mysql
ID              NAME          IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR               PORTS
pjwseruvy4rj    mysql.1       mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 4 seconds ago                         
s66g9stz9af5     \_ mysql.1   mysql:latest    ip-172-31-2-177.ec2.internal    Shutdown         Shutdown 4 seconds ago                        
yqco9zd0vq79    mysql.2       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 9 seconds ago                         
8muu6gbghhnd     \_ mysql.2   mysql:latest    ip-172-31-25-121.ec2.internal   Shutdown         Shutdown 10 seconds ago                       
8x7xlavcxdau    mysql.3       mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 7 seconds ago                         
qx95vwi2h547     \_ mysql.3   mysql:latest    ip-172-31-29-67.ec2.internal    Shutdown         Shutdown 7 seconds ago                        

可以在同一个docker service update命令中添加和删除调度约束。例如,删除节点成为管理者的约束,并添加节点成为工作者的约束。

∼ $ docker service update \
>   --constraint-rm node.role==manager \
>   --constraint-add node.role==worker \
>  mysql

mysql

又来了。所有服务任务都将关闭,新任务仅在工作节点上启动。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                           DESIRED STATE    CURRENT STATE              ERROR    PORTS
6ppgmvw9lv75    mysql.1    mysql:latest    ip-172-31-29-67.ec2.internal   Running          Running 9 seconds ago                        
qm0loki65v9s    mysql.2    mysql:latest    ip-172-31-29-67.ec2.internal   Running          Running 17 seconds ago                       
ypl0tc1ft92o    mysql.3    mysql:latest    ip-172-31-29-67.ec2.internal   Running          Running

如果将节点角色指定为工作者的唯一调度约束被移除,则分布调度策略开始在整个群中均匀分布新任务。要进行演示,请删除节点角色成为工作者的约束。

∼ $ docker service update --constraint-rm node.role==worker mysql

mysql

随后,新的任务在群体中的节点间传播。

∼ $ docker service ps -f desired-state=running mysql
ID              NAME       IMAGE           NODE                            DESIRED STATE    CURRENT STATE              ERROR    PORTS
jpx4jjw6l9d5    mysql.1    mysql:latest    ip-172-31-29-67.ec2.internal    Running          Running 5 seconds ago                        
ngajiik1hugb    mysql.2    mysql:latest    ip-172-31-25-121.ec2.internal   Running          Running 12 seconds ago                       
40eaujzlux88    mysql.3    mysql:latest    ip-172-31-2-177.ec2.internal    Running          Running 8 seconds ago                        

扩展调度和全球服务

全局服务在集群中的每个节点上运行一个任务。全局服务不能被扩展以创建更多/更少的任务。因此,分布调度策略概念不适用于全局服务。然而,节点约束可以应用于全局服务。例如,我们为mysql数据库创建了一个全局服务。应用一个放置约束,即服务应该只在工作节点上可用。

∼ $ docker service create \

>   --mode global \

>   --env MYSQL_ROOT_PASSWORD='mysql'\

>   --constraint node.role==worker \

>   --name mysql \

>  mysql

jtzcwatp001q9r26n1uubd8me

创建了全局服务。将具有期望状态的任务的服务任务列为running仅列出工作节点上的任务。

∼ $ docker service ps -f desired-state=running mysql
ID            NAME                             IMAGE         NODE                           DESIRED STATE  CURRENT STATE            ERROR   PORTS
o5nskzpv27j9  mysql.e7vigin0luuo1kynjnl33v9pa  mysql:latest  ip-172-31-29-67.ec2.internal   Running        Running 17 seconds ago                       

如果创建时没有仅在工作节点上调度的约束,全局服务将在每个节点上调度一个任务,如下例所示。

∼ $ docker service rm mysql
mysql
∼ $ docker service create \
>   --mode global \
>   --env MYSQL_ROOT_PASSWORD='mysql'\
>   --name mysql \
>  mysql

mv9yzyyntdhzz41zssbutcsvw

∼ $ docker service ps -f desired-state=running mysql
ID            NAME                             IMAGE         NODE                          DESIRED STATE  CURRENT STATE           ERROR  PORTS
mc87btddhmpl  mysql.e7vigin0luuo1kynjnl33v9pa  mysql:latest  ip-172-31-29-67.ec2.internal  Running        Running 19 seconds ago                       
o0wfdq9sd8yt  mysql.ptm7e0p346zwypos7wnpcm72d  mysql:latest  ip-172-31-25-121.ec2.internal Running        Running 19 seconds ago                       
wt2q5k2dhqjt  mysql.81h6uvu8uq0emnovzkg6v7mzg  mysql:latest  ip-172-31-2-177.ec2.internal   Running        Running 19 seconds ago                       

摘要

本章讨论了 Docker Swarm 模式中使用的分布调度策略,通过这种策略,服务副本基于节点排序均匀地分布在集群中的节点上;较高的节点等级获得服务副本放置优先级。我们还讨论了有限节点资源容量的影响,以及如何通过向群集添加新节点来缓解这种影响。我们讨论了调度新副本的放置约束。分布调度策略与全局服务无关,因为默认情况下,全局服务在每个节点上创建一个服务任务。然而,调度约束可以与全局服务一起使用。在下一章,我们将讨论 Docker 服务的滚动更新。