前文介绍如何在单独Docker环境下使用compose,本文介绍如何在swarm集群中使用compose。
限制
image构建
在swarm中构建image与单机版一样,使用相同的命令。但是构建完成的image只存在于当前主机,如果运行镜像的多个实例,并且这些实例分布在集群中的不同节点上,那么就需要分发构建好的镜像,一个节点不会共享另一个节点上已经构建好的镜像。解决办法为首先在某个节点上构建image,然后再将image上传到镜像仓库,然后在compose的定义文件中从仓库引用此镜像。救命如下:
$ docker build -t myusername/web .
$ docker push myusername/web
$ cat docker-compose.yml
web:
image: myusername/web
$ docker-compose up -d
$ docker-compose scale web=3
多依赖
如果某个应用有多个服务组成,如下例:
version: "2"
services:
foo:
image: foo
volumes_from: ["bar"]
network_mode: "service:baz"
bar:
image: bar
baz:
image: baz
上例中,foo的volume依赖于bar,foo的网络与baz共享,实例这三个服务必需部署在同一个节点上才行,也就是foo明确依赖于bar与baz。在部署时的实际调度中,如果依次先部署foo,那么系统会发现它依赖于bar与baz,然后系统在同一个节点上就会先部署bar与baz,然后再部署foo。但实际上,swarm并不是这样调度的,它是并发的,有可能先部署bar与baz,这两个服务都没有指出依赖谁,因此可能部署到集群中的任何节点上,并且是不同的节点,这个时候再部署foo时就会出问题,因为它依赖的东西分布在不同的节点上。解决的一种方案是手动为部署增加约束,如:
version: "2"
services:
foo:
image: foo
volumes_from: ["bar"]
network_mode: "service:baz"
environment:
- "constraint:node==node-1"
bar:
image: bar
environment:
- "constraint:node==node-1"
baz:
image: baz
environment:
- "constraint:node==node-1"
以上强制要求所有三个服务必需部署在节点node-1上。这种方式实际上不太灵活,因为强制指定了节点名称。一种方法是通过标签,将目标节点打上标签,然后再约束中指定标签名称,这需要一个选择器,k8s是这样做的,compose可能也有这种功能。
主机端口与容器重建 (Host ports and recreating containers)
这一段实在看不明白是什么意思,一会volume一会port,不明白到底是什么原因引起冲突。原文如下:
If a service maps a port from the host, such as 80:8000
, then you may get an error like this when running docker-compose up
on it after the first time:
docker: Error response from daemon: unable to find a node that satisfies
container==6ab2dfe36615ae786ef3fc35d641a260e3ea9663d6e69c5b70ce0ca6cb373c02.
The usual cause of this error is that the container has a volume (defined either in its image or in the Compose file) without an explicit mapping, and so in order to preserve its data, Compose has directed Swarm to schedule the new container on the same node as the old container. This results in a port clash.
它下边提到的两个方法到是看明白了。一个是命名volume,代码如下:
version: "2"
services:
web:
build: .
ports:
- "80:8000"
volumes:
- web-logs:/var/log/web
volumes:
web-logs:
driver: custom-volume-driver
上例中,volume是有名字的,并且是某个存储系统单独提供的,不依赖于宿主机,容器实例部署在那里,它就跟到那里。有一个疑问就是多实例多volume的问题,假如运行5个实例,然后又调整到10个实例,那么这个volume怎么绑定呢?
第二方法是彻底清除上次运行产生的遗留,以免冲突,如下:
$ docker-compose stop web
$ docker-compose rm -f web
$ docker-compose up web
自动调度
在上边例子里已经出现过,compose中服务的配置可能会影响调度,如:
-
network_mode: "service:..."
andnetwork_mode: "container:..."
(andnet: "container:..."
in the version 1 file format). -
volumes_from
-
links
手动调度
# Schedule containers on a specific node
environment:
- "constraint:node==node-1"
# Schedule containers on a node that has the 'storage' label set to 'ssd'
environment:
- "constraint:storage==ssd"
# Schedule containers where the 'redis' image is already pulled
environment:
- "affinity:image==redis"
实例上就是部署时的约束、亲各与反亲和等。