Docker Swarm是官方发布的集群容器管理工具。它的特点是:比较轻量级,无缝支持标准的docker API。深入浅出Swarm一文很清晰地讲解了它的架构和命令。本文从零开始搭建并管理一个swarm集群。
准备工作
我们需要先安装virtualBox和vagrant。通过vagrant来驱动virtualBox搭建一个虚拟测试环境。首先在本地任意路径新建一个空文件夹比如test
,运行以下命令:
virtual box host1 2 3 4
| mkdir test cd test vagrant init minimum/ubuntu-trusty64-docker vi Vagrantfile
|
里面应该有一句config.vm.box = "minimum/ubuntu-trusty64-docker"
,在它的下面添加如下几行代码,相当于给它分配三台虚拟机,一台叫做manager,它的IP是192.168.33.17;另两台叫做node1和node2,它们的IP是192.168.33.18和192.168.33.19。
Vagrantfile1 2 3 4 5 6 7 8 9 10 11 12 13 14
| config.vm.define "manager" do | host | host.vm.hostname = "manager" host.vm.network "private_network", ip: "192.168.33.17" end config.vm.define "node1" do | host | host.vm.hostname = "node1" host.vm.network "private_network", ip: "192.168.33.18" end config.vm.define "node2" do | host | host.vm.hostname = "node2" host.vm.network "private_network", ip: "192.168.33.19" end
|
这个vagrant镜像已经在ubuntu的基础上帮我们安装了docker,用起来很方便。然后分别在三个终端运行以下命令启动并连接三台虚拟机。
virtual box host terminal 11 2
| vagrant up vagrant ssh manager
|
搭建环境
想要让swarm管理node,首先得让docker daemon支持TCP。在三台虚拟机上运行以下命令:
manager and node1 and node21 2 3
| sudo sh -c 'echo DOCKER_OPTS=\"-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock\" >> /etc/default/docker' sudo rm /etc/docker/key.json sudo service docker restart
|
接下来,我们用最简单的静态节点列表方式来启动swarm环境。把node1和node2的节点信息都写到参数里即可:
manager1
| docker run -t -p 2376:2375 swarm:1.1.0 manage nodes://192.168.33.18:2375,192.168.33.19:2375
|
2376是我随便设的一个端口,可以改成2375外的其他可用端口,因为2375已经被docker daemon占用了。可以Ctrl+C后,用下面这个命令查看:
manager1
| sudo netstat -tulnp | grep 2375
|
随便在哪台机器运行以下命令就能看到这个集群的信息和节点信息。这里的2376就是上面随便设出来的2376:
1
| docker -H tcp://192.168.33.17:2376 info
|
运行容器
Swarm的环境已经搭建完成,现在我们可以用swarm来运行容器了。随便在哪台机器运行以下命令来创建一个busybox容器:
1
| docker -H tcp://192.168.33.17:2376 run -d busybox sleep 3000
|
可能一开始的时候有点儿慢,这是因为需要下载镜像的缘故。如果等不及,就到两个node里分别先把镜像下载下来:docker pull busybox
。之所以说无缝支持docker API,那是因为swarm里能运行所有的docker命令。跑一下docker -H tcp://192.168.33.17:2376 ps
就能看到一个busybox的容器已经启动起来了。容器的NAMES属性里有node的信息,所以不需要分别在两个node运行docker ps
就能看到这个busybox的容器在哪个node运行。之后,再运行3次上面的命令,共创建4个busybox的容器,就能看到它们被均匀分配到两个node上了。这是因为swarm默认的调度策略所致。目前swarm支持三种调度策略:
- spread:默认,swarm会把任务分配到目前运行的容器数量最少的node上去。这里说的容器数量包括已经停止的容器。
- binpack:把任务分配到目前最大负荷的node上去。目的是把其他机器的资源留给将来可能要运行的大容器。
- random:随机分配。
如果看到的容器分配不均匀,那很可能是存在着非运行中的容器,可以用docker ps -a
看一下。如果想要修改调度策略,可以在manager启动的时候指定--strategy
参数,比如修改成binpack:
manager1 2
| docker rm -f `docker ps -aq` docker run -t -p 2376:2375 swarm:1.1.0 manage nodes://192.168.33.18:2375,192.168.33.19:2375 --strategy binpack
|
这回再试试启动4个新的busybox,是不是都跑到同一个node上去了?Swarm的过滤器功能还允许我们指定让容器运行在哪个node上。目前,swarm支持如下的过滤器:
- node过滤器
- constraint:限制新任务只能在label符合的node上执行
- health:限制新任务只能在“健康”的node上执行
- 容器过滤器
- affinity:使新任务在已运行某个名字或label的容器,或者有某个镜像的node上执行
- dependency:使新任务在有依赖(–volumes-from=dependency、–link=dependency:alias或–net=container:dependency)的node上执行
- port:使新任务在某个端口可用的node上执行
可以在manager启动的时候指定--filter
参数来启用过滤器功能。我们先来试验一下constraint。由于Label是docker daemon的属性,所以我们又要修改/etc/default/docker
并重启docker daemon。假设node1为ssd,node2为普通disk:
node11 2 3 4
| docker rm -f `docker ps -aq` sudo sed -i '$d' /etc/default/docker sudo sh -c 'echo DOCKER_OPTS=\"-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --label storage=ssd\" >> /etc/default/docker' sudo service docker restart
|
node21 2 3 4
| docker rm -f `docker ps -aq` sudo sed -i '$d' /etc/default/docker sudo sh -c 'echo DOCKER_OPTS=\"-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --label storage=disk\" >> /etc/default/docker' sudo service docker restart
|
随便在哪台机器运行以下命令,看看两个node是不是分别多出来storage==ssd
和storage==disk
:
1
| docker -H tcp://192.168.33.17:2376 info
|
如果不是,就重启一下manager的swarm容器。然后就可以指定storage=ssd
的node运行:
1
| docker -H tcp://192.168.33.17:2376 run -d -e constraint:storage==ssd busybox sleep 3000
|
随便再创建几个容器玩玩,再换constraint:storage==disk
试试看。熟悉之后,我们再试验一下affinity:
1
| docker -H tcp://192.168.33.17:2376 run -d -e constraint:storage==disk --name=bb busybox sleep 3000
|
要的就是bb这个名字。然后运行以下命令让新容器运行在有bb容器的node上,也就是node2:
1
| docker -H tcp://192.168.33.17:2376 run -d -e affinity:container==bb busybox sleep 3000
|
在node2上运行docker ps
应该能看到新容器已经启动起来了。如果constraint和affinity冲突会怎样呢?试试看:
1
| docker -H tcp://192.168.33.17:2376 run -d -e affinity:container==bb -e constraint:storage==ssd busybox sleep 3000
|
不出意外的话,应该能看见unable to find a node that satisfies storage==ssd的错误消息了吧。
主机发现
Swarm共支持下面几种主机发现方式:
- 分布式键值存储
- Consul 0.5.1或更高版本
- Etcd 2.0或更高版本
- ZooKeeper 3.4.5或更高版本
- 静态方式
- Docker Hub
我们刚才搭建环境用到的是静态的节点列表方式,现在我们再试试其它几种方式。
文件
先从简单的开始。文件的主机发现方式和节点列表很类似,它们都是静态的。首先把node的信息都写到一个临时文件/tmp/cluster
里,然后让swamp容器管理这个文件即可:
manager1 2
| echo 192.168.33.[18:19]:2375 > /tmp/cluster docker run -t -p 2376:2375 -v /tmp/cluster:/tmp/cluster swarm:1.1.0 manage file:///tmp/cluster
|
随便选台虚拟机检查一下:
1
| docker -H tcp://192.168.33.17:2376 info
|
是不是有换汤不换药的感觉?
ZooKeeper
接下来试验一下ZooKeeper。先在manager上启动一个ZooKeeper的服务:
manager1 2 3 4 5 6
| docker run -d \ --net=host \ --name=zk \ -e MYID=1 \ -e SERVERS=192.168.33.18 \ mesoscloud/zookeeper:3.4.6-ubuntu-14.04
|
然后运行swarm manager:
manager1
| docker run -t -p 2376:2375 swarm:1.1.0 manage zk://192.168.33.17:2181/swarm
|
由于这回不像文件和节点列表方式那样静态,我们需要把两个node加入到集群里:
node11
| docker run -d swarm:1.1.0 join --addr=192.168.33.18:2375 zk://192.168.33.17:2181/swarm
|
node21
| docker run -d swarm:1.1.0 join --addr=192.168.33.19:2375 zk://192.168.33.17:2181/swarm
|
随便选台虚拟机检查一下:
1
| docker -H tcp://192.168.33.17:2376 info
|
Consul和Etcd也都很类似,这里就不一一列举了。
Docker Hub
Docker Hub的主机发现方式,就是在docker hub上使用发现服务来生成一个唯一的集群ID(别在生产环境上这么干!)。Docker hub会为我们保留大概一个星期。在任意一台机器上运行以下命令:
manager or node1 or node21
| docker run --rm swarm:1.1.0 create
|
然后我们就能看见上面的命令生成了一个字符串,这就是我们的集群ID。在我的机器上是这样的:3137ebf83d771f1db06bf4eab7ccc73b
。我大天朝的网络,有时候会出现TLS handshake timeout,那就再运行一次吧。
这时候可以把manager启动起来了,别忘了替换成你自己的token:
manager1
| docker run -t -p 2376:2375 swarm:1.1.0 manage token://3137ebf83d771f1db06bf4eab7ccc73b
|
然后可以在两个node上分别运行以下命令,启动swarm的代理并加入到集群中,别忘了替换成你自己的token:
node11
| docker run -d swarm:1.1.0 join --addr=192.168.33.18:2375 token://3137ebf83d771f1db06bf4eab7ccc73b
|
node21
| docker run -d swarm:1.1.0 join --addr=192.168.33.19:2375 token://3137ebf83d771f1db06bf4eab7ccc73b
|
随便选台虚拟机检查一下:
1 2
| docker -H tcp://192.168.33.17:2376 info docker run --rm swarm:1.1.0 list token://3137ebf83d771f1db06bf4eab7ccc73b
|