文章目录
  1. 1. 准备工作
  2. 2. 搭建环境
  3. 3. 运行容器
  4. 4. 主机发现
    1. 4.1. 文件
    2. 4.2. ZooKeeper
    3. 4.3. Docker Hub

Docker Swarm是官方发布的集群容器管理工具。它的特点是:比较轻量级,无缝支持标准的docker API。深入浅出Swarm一文很清晰地讲解了它的架构和命令。本文从零开始搭建并管理一个swarm集群。

准备工作

我们需要先安装virtualBoxvagrant。通过vagrant来驱动virtualBox搭建一个虚拟测试环境。首先在本地任意路径新建一个空文件夹比如test,运行以下命令:

virtual box host
1
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;另两台叫做node1node2,它们的IP是192.168.33.18192.168.33.19

Vagrantfile
1
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 1
1
2
vagrant up
vagrant ssh manager

virtual box host terminal 2
1
vagrant ssh node1
virtual box host terminal 3
1
vagrant ssh node2

搭建环境

想要让swarm管理node,首先得让docker daemon支持TCP。在三台虚拟机上运行以下命令:

manager and node1 and node2
1
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 # 免得我们用vagrant生成的docker id都一样,删掉了重启docker服务会自动生成一个新的
sudo service docker restart

接下来,我们用最简单的静态节点列表方式来启动swarm环境。把node1和node2的节点信息都写到参数里即可:

manager
1
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后,用下面这个命令查看:

manager
1
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:

manager
1
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:

node1
1
2
3
4
docker rm -f `docker ps -aq`
sudo sed -i '$d' /etc/default/docker # 删掉最后一行,因为要加新的label
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

node2
1
2
3
4
docker rm -f `docker ps -aq`
sudo sed -i '$d' /etc/default/docker # 删掉最后一行,因为要加新的label
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==ssdstorage==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容器管理这个文件即可:

manager
1
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的服务:

manager
1
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:

manager
1
docker run -t -p 2376:2375 swarm:1.1.0 manage zk://192.168.33.17:2181/swarm

由于这回不像文件和节点列表方式那样静态,我们需要把两个node加入到集群里:

node1
1
docker run -d swarm:1.1.0 join --addr=192.168.33.18:2375 zk://192.168.33.17:2181/swarm

node2
1
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 # 由于是动态加载,可能需要等待半分钟左右才能看见node

Consul和Etcd也都很类似,这里就不一一列举了。

Docker Hub

Docker Hub的主机发现方式,就是在docker hub上使用发现服务来生成一个唯一的集群ID(别在生产环境上这么干!)。Docker hub会为我们保留大概一个星期。在任意一台机器上运行以下命令:

manager or node1 or node2
1
docker run --rm swarm:1.1.0 create

然后我们就能看见上面的命令生成了一个字符串,这就是我们的集群ID。在我的机器上是这样的:3137ebf83d771f1db06bf4eab7ccc73b。我大天朝的网络,有时候会出现TLS handshake timeout,那就再运行一次吧。

这时候可以把manager启动起来了,别忘了替换成你自己的token:

manager
1
docker run -t -p 2376:2375 swarm:1.1.0 manage token://3137ebf83d771f1db06bf4eab7ccc73b

然后可以在两个node上分别运行以下命令,启动swarm的代理并加入到集群中,别忘了替换成你自己的token:

node1
1
docker run -d swarm:1.1.0 join --addr=192.168.33.18:2375 token://3137ebf83d771f1db06bf4eab7ccc73b

node2
1
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

文章目录
  1. 1. 准备工作
  2. 2. 搭建环境
  3. 3. 运行容器
  4. 4. 主机发现
    1. 4.1. 文件
    2. 4.2. ZooKeeper
    3. 4.3. Docker Hub