Swarm filters
Configure the available filters
过滤器分为两类,即节点过滤器和容器配置过滤器。 节点过滤器对Docker主机的特性或Docker守护程序的配置进行操作。 容器配置过滤器根据容器的特性或主机上image的可用性进行操作。
每个过滤器都有一个标识它的名称。 节点过滤器是:
constraint
health
containerslots
The container configuration filters are:
affinity
dependency
port
当您使用swarm manage命令启动Swarm管理器时,将启用所有过滤器。 如果要限制Swarm可用的过滤器,请通过传递--filter标志和名称来指定一个过滤器子集:
$ swarm manage --filter=health --filter=dependency
注意:应用过滤器时,容器配置过滤器将匹配所有容器,包括已停止的容器。 要释放容器使用的节点,必须从节点中删除该容器。
Node filters
创建容器或构建iimage时,您可以使用constraint
或health
过滤器来选择要计划的节点子集。 如果Swarm群集中的节点具有带有containerslots
和数字值的标签,Swarm将不会启动比给定号码更多的容器。
Use a constraint filter
节点约束可以指Docker的默认标签或自定义标签。 默认标签来自docker info。 通常它们与Docker主机的属性有关。 目前,默认标签包括:
node
to refer to the node by ID or namestoragedriver
executiondriver
kernelversion
operatingsystem
Custom node labels you apply when you start the docker daemon
, for example:
$ docker daemon --label com.example.environment="production" --label com.example.storage="ssd"
然后,当您在群集上启动容器时,可以使用这些默认标签或自定义标签设置约束。 Swarm调度程序在集群上查找匹配的节点,并在那里启动容器。 这种方法有几个实际应用:
- 基于特定主机属性进行计划,例如,storage = ssd在特定硬件上调度容器。
- 强制容器在给定位置运行,例如region = us-east。
- 通过将集群分成具有不同属性的子集群(例如environment = production)来创建逻辑集群分区。
Example node constraints
To specify custom label for a node, pass a list of --label
options at docker
startup time. For instance, to start node-1
with the storage=ssd
label:
$ docker daemon --label storage=ssd
$ swarm join --advertise=192.168.0.42:2375 token://XXXXXXXXXXXXXXXXXX
You might start a different node-2
with storage=disk
:
$ docker daemon --label storage=disk
$ swarm join --advertise=192.168.0.43:2375 token://XXXXXXXXXXXXXXXXXX
一旦节点连接到群集,Swarm manager将拉出各自的标签。 展望未来,在安排新container时,manager会考虑标签。
继续上一个示例,假设您的群集具有node-1和node-2,您可以在群集上运行MySQL服务器容器。 运行容器时,可以使用约束来确保数据库获得良好的I / O性能。 您可以通过使用闪存驱动器的节点进行过滤:
$ docker tcp://<manager_ip:manager_port> run -d -P -e constraint:storage==ssd --name db mysql f8b693db9cd6 $ docker tcp://<manager_ip:manager_port> ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f8b693db9cd6 mysql:latest "mysqld" Less than a second ago running 192.168.0.42:49178->3306/tcp node-1/db
在此示例中,管理员选择了满足storage = ssd约束的所有节点,并在其上面应用了资源管理。 只有节点1被选中,因为它是唯一的主机运行闪存。
假设你想在一个集群中运行一个Nginx前端。 在这种情况下,您不需要闪存驱动器,因为前端主要将日志写入磁盘。
调度程序选择node-2,因为它是以storage = disk标签启动的。
最后,构建args可以用于将节点约束应用于docker构建。 再次,你会避免闪存驱动器。
$ mkdir sinatra
$ cd sinatra
$ echo "FROM ubuntu:14.04" > Dockerfile $ echo "RUN apt-get update && apt-get install -y ruby ruby-dev" >> Dockerfile $ echo "RUN gem install sinatra" >> Dockerfile $ docker build --build-arg=constraint:storage==disk -t ouruser/sinatra:v2 . Sending build context to Docker daemon 2.048 kB Step 1 : FROM ubuntu:14.04 ---> a5a467fddcb8 Step 2 : RUN apt-get update && apt-get install -y ruby ruby-dev ---> Running in 26c9fbc55aeb ---> 30681ef95fff Removing intermediate container 26c9fbc55aeb Step 3 : RUN gem install sinatra ---> Running in 68671d4a17b0 ---> cd70495a1514 Removing intermediate container 68671d4a17b0 Successfully built cd70495a1514 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE dockerswarm/swarm manager 8c2c56438951 2 days ago 795.7 MB ouruser/sinatra v2 cd70495a1514 35 seconds ago 318.7 MB ubuntu 14.04 a5a467fddcb8 11 days ago 187.9 MB
Use the health filter
节点健康过滤器防止调度程序在不健康的节点上运行容器。 如果节点关闭或无法与集群存储通信,则节点被认为是不健康的。
Use the containerslots filter
You may give your Docker nodes the containerslots label
$ docker daemon --label containerslots=3
如果所有节点都为“满”,Swarm将在此节点运行多达3个容器,则会抛出错误,指示找不到合适的节点。 如果该值不可转换为整数或不存在,则容器数量不会有限制。
Container filters
When creating a container, you can use three types of container filters:
Use an affinity filter
使用亲和过滤器在容器之间创建“景点”。 例如,您可以运行一个容器,并指示Swarm根据这些亲和力将其安排在另一个容器旁边:
- container name or ID
- an image on the host
- a custom label applied to the container
这些亲和性确保容器运行在同一个网络节点上,而无需知道每个节点正在运行。
Example name affinity
您可以根据容器名称或ID来安排新容器运行到另一个容器。 例如,您可以启动一个名为frontend
运行nginx的容器:
$ docker tcp://<manager_ip:manager_port> run -d -p 80:80 --name frontend nginx
87c4376856a8
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1/frontend
然后,使用-e affinity:container == frontend值来计划第二个容器来定位并运行在名为frontend的容器旁
$ docker tcp://<manager_ip:manager_port> run -d --name logger -e affinity:container==frontend logger
87c4376856a8
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1/frontend
963841b138d8 logger:latest "logger" Less than a second ago running node-1/logger
由于名称相关性,记录器容器与前端容器一起结束在节点1上。 您可以提供其ID,而不是frontend
名称,如下所示:
Example image affinity
您可以安排一个容器仅在已经拉出特定图像的节点上运行。 例如,假设您将一个redis映像拖放到两个主机和一个mysql映像到三分之一。
$ docker -H node-1:2375 pull redis
$ docker -H node-2:2375 pull mysql
$ docker -H node-3:2375 pull redis
只有节点1和节点3具有redis映像。 指定-e affinity:image == redis过滤器以安排在这些节点上运行的多个附加容器。
$ docker tcp://<manager_ip:manager_port> run -d --name redis1 -e affinity:image==redis redis
$ docker tcp://<manager_ip:manager_port> run -d --name redis2 -e affinity:image==redis redis
$ docker tcp://<manager_ip:manager_port> run -d --name redis3 -e affinity:image==redis redis $ docker tcp://<manager_ip:manager_port> run -d --name redis4 -e affinity:image==redis redis $ docker tcp://<manager_ip:manager_port> run -d --name redis5 -e affinity:image==redis redis $ docker tcp://<manager_ip:manager_port> run -d --name redis6 -e affinity:image==redis redis $ docker tcp://<manager_ip:manager_port> run -d --name redis7 -e affinity:image==redis redis $ docker tcp://<manager_ip:manager_port> run -d --name redis8 -e affinity:image==redis redis $ docker tcp://<manager_ip:manager_port> ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 87c4376856a8 redis:latest "redis" Less than a second ago running node-1/redis1 1212386856a8 redis:latest "redis" Less than a second ago running node-1/redis2 87c4376639a8 redis:latest "redis" Less than a second ago running node-3/redis3 1234376856a8 redis:latest "redis" Less than a second ago running node-1/redis4 86c2136253a8 redis:latest "redis" Less than a second ago running node-3/redis5 87c3236856a8 redis:latest "redis" Less than a second ago running node-3/redis6 87c4376856a8 redis:latest "redis" Less than a second ago running node-3/redis7 963841b138d8 redis:latest "redis" Less than a second ago running node-1/redis8
正如你可以在这里看到的,容器只被安排在具有redis镜像的节点上。 您可以指定image ID而不是image名称。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
redis latest 06a1f75304ba 2 days ago 111.1 MB
$ docker tcp://<manager_ip:manager_port> run -d --name redis1 -e affinity:image==06a1f75304ba redis
Example label affinity
标签亲和性允许您根据自定义容器标签进行过滤。 例如,您可以运行一个nginx容器并应用com.example.type = frontend自定义标签。
$ docker tcp://<manager_ip:manager_port> run -d -p 80:80 --label com.example.type=frontend nginx
87c4376856a8
$ docker tcp://<manager_ip:manager_port> ps --filter "label=com.example.type=frontend"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1/trusting_yonath
Then, use -e affinity:com.example.type==frontend
to schedule a container next to the container with the com.example.type==frontend
label.
$ docker tcp://<manager_ip:manager_port> run -d -e affinity:com.example.type==frontend logger
87c4376856a8
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
87c4376856a8 nginx:latest "nginx" Less than a second ago running 192.168.0.42:80->80/tcp node-1/trusting_yonath
963841b138d8 logger:latest "logger" Less than a second ago running
The logger
container ends up on node-1
because its affinity with the com.example.type==frontend
label.
Use a dependency filter
容器依赖过滤器在相同的节点上调度相关容器。 目前,依赖关系声明如下:
--volumes-from=dependency
(shared volumes)--link=dependency:alias
(links)--net=container:dependency
(shared network stacks)
Swarm尝试将依赖容器同时放置在同一个节点上。 如果不能完成(因为从属容器不存在,或因为节点没有足够的资源),它将阻止容器创建。
如果可能,多个依赖关系的组合将得到尊重。 例如,如果指定--volumes-from = A --net = container:B,则调度程序将尝试将与A和B相同节点上的容器进行共同定位。如果这些容器在不同的节点上运行,则Swarm 不安排容器。
Use a port filter
启用端口过滤器后,将使用容器的端口配置作为唯一约束。 Docker Swarm选择一个特定端口可用并且被其他容器或进程占用的节点。 可以通过映射主机端口或使用主机网络并使用容器配置暴露端口来指定所需的端口。
Example in bridge mode
默认情况下,容器在Docker的网桥上运行。 要将端口过滤器与桥接网络一起使用,请运行以下容器。
$ docker tcp://<manager_ip:manager_port> run -d -p 80:80 nginx
87c4376856a8
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND PORTS NAMES
87c4376856a8 nginx:latest "nginx" 192.168.0.42:80->80/tcp node-1/prickly_engelbart
Docker Swarm选择端口80可用并且被其他容器或进程占用的节点,在本例中为节点-1。 尝试运行另一个使用主机端口80的容器导致Swarm选择不同的节点,因为端口80已在节点1上占用:
$ docker tcp://<manager_ip:manager_port> run -d -p 80:80 nginx
963841b138d8
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND PORTS NAMES
963841b138d8 nginx:latest "nginx" 192.168.0.43:80->80/tcp node-2/dreamy_turing
87c4376856a8 nginx:latest "nginx" 192.168.0.42:80->80/tcp node-1/prickly_engelbart
再次,重复相同的命令将导致节点3的选择,因为端口80在节点1和节点2上都不可用:
$ docker tcp://<manager_ip:manager_port> run -d -p 80:80 nginx
963841b138d8
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND PORTS NAMES
f8b693db9cd6 nginx:latest "nginx" 192.168.0.44:80->80/tcp node-3/stoic_albattani
963841b138d8 nginx:latest "nginx" 192.168.0.43:80->80/tcp node-2/dreamy_turing
87c4376856a8 nginx:latest "nginx" 192.168.0.42:80->80/tcp node-1/prickly_engelbart
最后,Docker Swarm将拒绝运行另一个需要端口80的容器,因为它在集群中的任何节点上都不可用:
$ docker tcp://<manager_ip:manager_port> run -d -p 80:80 nginx
2014/10/29 00:33:20 Error response from daemon: no resources available to schedule container
当容器创建时,每个容器在其驻留节点上占用端口80,并在容器被删除时释放端口。 退出状态的容器仍然拥有端口。 如果节点1上的prickly_engelbart已停止但未被删除,
则尝试启动需要端口80的节点1上的另一个容器将失败,因为端口80与prickly_engelbart相关联。 要增加nginx的运行实例,可以重新启动prickly_engelbart,也可以在删除prickly_englbart后启动另一个容器。
Node port filter with host networking
运行于--net = host的容器与默认bridge模式不同,因为主机模式不执行任何端口绑定。 相反,主机模式要求您显式公开一个或多个端口号。 您在Dockerfile中使用EXPOSE公开端口或在命令行上使用--expose。
Swarm使用此信息与主机模式一起选择新容器的可用节点。
例如,以下命令在3节点集群上启动nginx。
$ docker tcp://<manager_ip:manager_port> run -d --expose=80 --net=host nginx
640297cb29a7
$ docker tcp://<manager_ip:manager_port> run -d --expose=80 --net=host nginx 7ecf562b1b3f $ docker tcp://<manager_ip:manager_port> run -d --expose=80 --net=host nginx 09a92f582bc2
端口绑定信息通过docker ps命令不可用,因为所有节点都是使用host网络启动的。
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
640297cb29a7 nginx:1 "nginx -g 'daemon of Less than a second ago Up 30 seconds box3/furious_heisenberg
7ecf562b1b3f nginx:1 "nginx -g 'daemon of Less than a second ago Up 28 seconds box2/ecstatic_meitner
09a92f582bc2 nginx:1 "nginx -g 'daemon of 46 seconds ago Up 27 seconds box1/mad_goldstine
尝试实例化第4个容器时,Swarm拒绝操作。
$ docker tcp://<manager_ip:manager_port> run -d --expose=80 --net=host nginx
FATA[0000] Error response from daemon: unable to find a node with port 80/tcp available in the Host mode
但是,仍然允许端口绑定到不同的值,例如81。
$ docker tcp://<manager_ip:manager_port> run -d -p 81:80 nginx:latest
832f42819adc
$ docker tcp://<manager_ip:manager_port> ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
832f42819adc nginx:1 "nginx -g 'daemon of Less than a second ago Up Less than a second 443/tcp, 192.168.136.136:81->80/tcp box3/thirsty_hawking
640297cb29a7 nginx:1 "nginx -g 'daemon of 8 seconds ago Up About a minute box3/furious_heisenberg
7ecf562b1b3f nginx:1 "nginx -g 'daemon of 13 seconds ago Up About a minute box2/ecstatic_meitner
09a92f582bc2 nginx:1 "nginx -g 'daemon of About a minute ago Up About a minute box1/mad_goldstine
How to write filter expressions
要应用节点约束或容器关联过滤器,必须使用过滤器表达式在容器上设置环境变量,例如:
Each expression must be in the form:
<filter-type>:<key><operator><value>
<filter-type>是affinity或constraint关键字。 它标识您要使用的类型过滤器。
<key>是一个字母数字,必须以字母或下划线开头。 <key>对应于以下之一:
- the
container
keyword - the
node
keyword - a default tag (node constraints)
- a custom metadata label (nodes or containers).
<operator>是==或!=。 默认情况下,表达式运算符被强制执行。 如果表达式不完全满足,则管理器不调度容器。 您可以使用〜(波浪号)创建“软”表达式。 调度程序尝试匹配一个软表达式。 如果不满足表达式,则调度程序将丢弃该过滤器并根据调度程序的策略调度该容器。
- A globbing pattern, for example,
abc*
. - A regular expression in the form of
/regexp/
. See re2 syntax for the supported regex syntax.
以下示例说明了一些可能的表达式:
constraint:node==node1
matches nodenode1
.constraint:node!=node1
matches all nodes, exceptnode1
.constraint:region!=us*
matches all nodes outside with aregion
tag prefixed withus
.constraint:node==/node[12]/
matches nodesnode1
andnode2
.constraint:node==/node\d/
matches all nodes withnode
+ 1 digit.constraint:node!=/node-[01]/
matches all nodes, exceptnode-0
andnode-1
.constraint:node!=/foo\[bar\]/
matches all nodes, exceptfoo[bar]
. You can see the use of escape characters here.constraint:node==/(?i)node1/
matches nodenode1
case-insensitive. SoNoDe1
orNODE1
also match.affinity:image==~redis
tries to match for nodes running container with aredis
image.constraint:region==~us*
searches for nodes in the cluster belonging to theus
region.affinity:container!=~redis*
schedules a newredis5
container to a node without a container that satisfiesredis*
.