共计 4776 个字符,预计需要花费 12 分钟才能阅读完成。
Swarm 介绍
Swarm 是 Docker 公司在 2014 年 12 月初发布的一套较为简单的工具,用来管理 Docker 集群,它将一群 Docker 宿主机变成一个单一的,虚拟的主机。Swarm 使用标准的 Docker API 接口作为其前端访问入口,换言之,各种形式的 Docker Client(docker client in Go, docker_py, docker 等)均可以直接与 Swarm 通信。Swarm 几乎全部用 Go 语言来完成开发,上周五,4 月 17 号,Swarm0.2 发布,相比 0.1 版本,0.2 版本增加了一个新的策略来调度集群中的容器,使得在可用的节点上传播它们,以及支持更多的 Docker 命令以及集群驱动。
Swarm deamon 只是一个调度器(Scheduler)加路由器(router),Swarm 自己不运行容器,它只是接受 docker 客户端发送过来的请求,调度适合的节点来运行容器,这意味着,即使 Swarm 由于某些原因挂掉了,集群中的节点也会照常运行,当 Swarm 重新恢复运行之后,它会收集重建集群信息。下面是 Swarm 的结构图:
如何使用 Swarm
有 3 台机器:
sclu083:10.13.181.83
sclu084:10.13.181.84
atsg124:10.32.105.124
利用这三台机器创建一个 Docker 集群,其中 sclu083 同时充当 swarm manager 管理集群。
Swarm 安装
最简单的安装 Swarm 的方式就是用 Docker 官方提供的 Swarm 镜像:
$ sudo docker pull swarm
Docker 集群管理需要服务发现 (Discovery service backend) 功能。Swarm 支持以下几种 discovery service backend:Docker Hub 上面内置的服务发现功能,本地的静态文件描述集群(static file describing the cluster),etcd(顺带说一句,etcd 这玩意貌似很火很有前途,有时间研究下),consul,zookeeper 和一些静态的 ip 列表(a static list of ips)。本文会详细介绍前面两种方法 backend 的使用。
在使用 Swarm 进行集群管理之前,需要先把准备加入集群的所有的节点的 docker deamon 的监听端口修改为 0.0.0.0:2375,可以直接使用 sudo docker –H tcp://0.0.0.0:2375 &
命令,也可以在配置文件中修改
$ sudo vim /etc/default/docker
在文件的最后面添加下面这句
D0OCKER_OPTS="-H 0.0.0.0:2375 –H unix:///var/run/docker.sock"
注意:一定是要在所有的节点上进行修改, 修改之后要重启 docker deamon
$ sudo service docker restart
第一种方法:使用 Docker Hub 上面内置的服务发现功能
第一步
在任何一个节点上面执行 swarm create 命令来创建一个集群标志。这条命令执行完毕之后,swarm 会前往 Docker Hub 上内建的发现服务中获取一个全球唯一的 token,用以唯一的标识 swarm 管理的 Docker 集群。
$ sudo docker run --rm swarm create
我们在 sclu084 这台机器上执行上面的命令
返回的 token 是 d947b55aa8fb9198b5d13ad81f61ac4d,这个 token 一定要记住,因为接下来的操作都会用到这一个 token。
第二步
在所有的要加入集群的机器上面执行 swarm join 命令,把机器加入集群。
本次试验就是要在所有的三台机器上执行命令。
$ sudo docker run –-rm swarm join –addr=ip_address:2375 token://d947b55aa8fb9198b5d13ad81f61ac4d
在 IP 地址为 10.13.181.84 机器上面执行
执行这条命令后不会立即返回,我们手动通过 Ctrl+ C 返回。
第三步
启动 swarm manager。
因为我们要让 sclu083 充当 Swarm 管理节点,所以我们要在这台机器上面执行 swarm manage 命令
$ sudo docker run –d –p 2376:2375 swarm manage token:// d947b55aa8fb9198b5d13ad81f61ac4d
重点内容需要注意的是:在这条命令中,第一:要以 daemon 的形式运行 swarm;第二:端口映射:2376 可以更换成任何一个本机没有占用的端口,一定不能是 2375,否则就会出问题。
执行结果如下如所示:
执行完这个命令之后,整个集群已经启动起来了。
现在可以在任何一个节点上查看集群上的所有节点了。
之后可以在任何一台安装了 docker 的机器上面通过命令 (命令中要指明 swarm maneger 机器的 IP 地址和端口) 在这个集群上面运行 Dcoker 容器操作。
现在在 10.13.181.85 这台机器上面查看集群的节点的信息。info 命令可以换成任何一个 Swarm 支持的 docker 命令,这些命令可以查看官方文档
$ sudo docker –H 10.13.181.83:2376 info
由上图的结果,我们可以发现一个问题:明明这个小集群中是有 3 个节点的,但是 info 命令只显示了 2 个节点。还缺少节点 10.32.105.124。为什么会出现这个情况呢?
因为 10.32.105.124 这台机器没有设置上面的 docker daemon 监听 0.0.0.0:2375 这个端口,所以 Swarm 没办法吧这个节点加入集群中来。
在使用 Docker Hub 内置的发现服务时,会出现一个问题,就是使用 swarm create 时会出现
time="2015-04-21T08:56:25Z" level=fatal msg="Get https://discovery-stage.hub.docker.com/v1/clusters/d947b55aa8fb9198b5d13ad81f61ac4d: dial tcp: i/o timeout"
类似于这样的错误,不知道是什么原因,有待解决。(可能是防火墙的问题)
当使用 Docker Hub 内置的服务发现功能出现问题时,可以使用下面的第二种方法。
第二种方法:使用文件
第二种方法相对而言比第一种方法要简单,也更不容易出现 timeout 的问题。
第一步
在 sclu083 这台机器上新建一个文件,把要加入集群的机器的 IP 地址写进去
第二步
在 sclu083 这台机器上面执行 swarm manage 命令:
$ sudo docker run –d –p 2376:2375 –v $(pwd)/cluster:/tmp/cluster swarm manage file:///tmp/cluster
注意:这里一定要使用 - v 命令,因为 cluster 文件是在本机上面,启动的容器默认是访问不到的,所以要通过 - v 命令共享。还有,file:/// 千万不能忘记了。
可以看到,swarm 已经运行起来了。现在可以查看下集群节点信息了,使用命令:
$ sudo docker run –rm –v $(pwd)/cluster:/tmp/cluster swarm list file:///tmp/cluster
(在使用文件作为服务发现的时候,貌似 manage list 命令只能在 swarm manage 节点上使用,在其他节点上好像是用不了)
好了,现在集群也已经运行起来了,可以跟第一种方法一样在其他机器上使用集群了。同样在 sclu085 机器上做测试:
可以看到,成功访问并且节点信息是正确的。接下来可以把上面的 info 命令替换成其他 docker 可执行命令来使用这个晓得 Docker 集群了。
Swarm 调度策略
Swarm 在 schedule 节点运行容器的时候,会根据指定的策略来计算最适合运行容器的节点,目前支持的策略有:spread, binpack, random.
Random 顾名思义,就是随机选择一个 Node 来运行容器,一般用作调试用,spread 和 binpack 策略会根据各个节点的可用的 CPU, RAM 以及正在运行的容器的数量来计算应该运行容器的节点。
在同等条件下,Spread 策略会选择运行容器最少的那台节点来运行新的容器,binpack 策略会选择运行容器最集中的那台机器来运行新的节点(The binpack strategy causes Swarm to optimize for the Container which is most packed.)。
使用 Spread 策略会使得容器会均衡的分布在集群中的各个节点上运行,一旦一个节点挂掉了只会损失少部分的容器。
Binpack 策略最大化的避免容器碎片化,就是说 binpack 策略尽可能的把还未使用的节点留给需要更大空间的容器运行,尽可能的把容器运行在一个节点上面。
过滤器
Constraint Filter
通过 label 来在指定的节点上面运行容器。这些 label 是在启动 docker daemon 时指定的,也可以写在 /etc/default/docker 这个配置文件里面。
$ sudo docker run –H 10.13.181.83:2376 –name Redis_083 –d –e constraint:label==083 redis
Affinity Filter
使用 -e affinity:container==container_name / container_id –-name container_1 可以让容器 container_1 紧挨着容器 container_name / container_id 执行,也就是说两个容器在一个 node 上面执行(You can schedule 2 containers and make the container #2 next to the container #1.)
先在一台机器上启动一个容器
$ sudo docker -H 10.13.181.83:2376 run --name redis_085 -d -e constraint:label==085 redis
接下来启动容器 redis_085_1,让 redis_085_1 紧挨着 redis_085 容器运行,也就是在一个节点上运行
$ sudo docker –H 10.13.181.83:2376 run –d –name redis_085_1 –e affinity:container==redis_085 redis
通过 -e affinity:image=image_name 命令可以指定只有已经下载了 image_name 的机器才运行容器(You can schedule a container only on nodes where the images are already pulled)
下面命令在只有 Redis 镜像的节点上面启动 redis 容器:
$ sudo docker –H 100.13.181.83:2376 run –name redis1 –d –e affinity:image==redis redis
下面这条命令达到的效果是:在有 redis 镜像的节点上面启动一个名���叫做 redis 的容器,如果每个节点上面都没有 redis 容器,就按照默认的策略启动 redis 容器。
$ sudo docker -H 10.13.181.83:2376 run -d --name redis -e affinity:image==~redis redis
Port filter
Port 也会被认为是一个唯一的资源
$ sudo docker -H 10.13.181.83:2376 run -d -p 80:80 nginx
执行完这条命令,任何使用 80 端口的容器都是启动失败。
本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-02/140520.htm