Docker Swarm项目

 

Docker SwarmDocker官方编排(项目之一,负责对Docker集群进行管理.Docker Swarm将一群Docker宿主机变成一个单一的,虚拟的主机.

 

Swarm使用标准的Docker API接口作为其前端访问入口,换言之,各种形式的Docker工具比如Dokku,Compose,Krane,Deis,Docker-py,Docker本身等都可以很容易的与Swarm进行集成.

 

在使用Swarm管理docker集群的时候, 会有一个swarm manager以及若干swarm node,swarm manager上运行swarm daemon,用户只需要跟swarm manager通信,然后swarm manager再根据discovery service的信息选择一个swarm node来运行container.

 

需要注意的是,swarm daemon只是一个任务调度器(scheduler)和路由器(router),他本身不运行容器,它只接受Docker Client发送过来的请求,调度合适的swarm node来运行container.这意味着,即使swarm daemon由于某些原因挂掉了,已经运行起来的容器也不会有任何影响.


有两点需要注意:


急集群中的每台节点上面的Docker版本都不能小于1.4

为了让swarm manager能够每台swarm node进行通信,集群中的每台几段的Docker daemon都必须监听同一个网络接口.

 

 

安装

 

安装swarm的最简单的方式是使用Docker官方的swarm镜像.但是楼主使用的是Daocloud的镜像.

$docker pull swarm #这是一般从官网的方式下载
$dao pull swarm #这是楼主使用的方式


使用如下命令来测试一下swarm是否安装成功.

$docker run --rm swarm -v

如果显示的信息如下:

swarm version 1.2.3 (eaa53c7)



使用

在使用swarm管理集群前,需要把集群中的所有节点的docker daemon的监听方式更改为0.0.0.0:2375.

 

可以有两种方式达到这个目的.

第一种,再启动docker daemon的时候指定

docker -H 0.0.0.0:2375

 

第二种,直接修改Docker的配置文件(ubuntu/etc/default/docker,linux的版本不同,这个文件可能不同),在文件最后添加这样的一句话:

DOCKER_OPTS=”-H 0.0.0.0:2375 -H unix:///var/run/docker.sock”.


 

需要注意的是,一定是要在所有被swarm管理的节点上进行的,修改之后需要重启Docker.

service docker restart

 

Docker 集群管理需要使用服务发现(Discovery service backend)功能.

 

实验环境:本次实验包括三台集群,IP地址分别为192.168.1.84,192.168.1.83,192.168.1.124,这个时候你能看出咱们前面使用vagrant来管理虚拟机是多方便了吗,配置环境挺爽啊.你只需要改改配置文件就可以了.在上面的任何一台机器上使用swarm carete命令来获取一个集群标志,这个标志是全球唯一的.这条命令执行完毕之后,获得的标志叫做token,这个token用来标示要管理的集群.

 

我们在84这台机器上执行这条命令,输出如下:

$docker run --rm swarm create
b7625e5a7a2dc7f8c4faacf2b510078e


 

加入集群

在所有要加入集群的节点上面执行swarm join命令,标示要把这台机器加入这个集群当中,本次实验环境中,就是在83,84,124这三台机器上执行下面的这条命令:

docker run --rm swarm join --addr=ip_address:2375 token://token_id


 

其中的ip_address换成执行这条命令的机器IP,token_ip换成上一步执行swarm create返回的token.

83这台机器上面的执行结果如下:

docker run -d swarm join --addr=192.168.1.83:2375 token://
b7625e5a7a2dc7f8c4faacf2b510078e

 

这条命令通过 -d 参数启动了一个容器,使得83这台机器加入到集群,如果这个容器被停止或者被删除,83这台机器就会从集群中消失.

 

 

启动swarm manager

 

我们要使用83这台机器当做swarm管理节点,所以需要在83这台机器上执行swarm manager命令:

docker rn -d -p 2376:2375 swarm manage token://b7625e5a7a2dc7f8c4faacf2b510078e

这条命令如果执行成功后悔返回已经启动的swarm的容器ID, 此时整个集群已经启动起来了.

我们可以使用docker ps命令来看下有没有启动成功:

docker ps


 

在执行swarm manag这条命令的时候有几点需要注意:

这条命令需要在充当swarm管理者的机器上执行.

swarm要以saemon的形式执行.

映射的端口可以使用任意的除了2375以外的并且未被占用的端口.

 

我们可以在任何一台机器上执行swarm list命令来查看集群中的节点,例如我们在124这台机器上执行swarm list:

docker run --rm swarm list token://b7625e5a7a2dc7f8c4faacf2b510078e

 

如果不出意外,我们会输出我们加入到swarm的主机IP.

 

现在我们可以在任何一台安装了Docker的机器上面通过命令(命令中要指明swarm manager机器的IP地址)来在集群中运行container.本次实验,我们在192.168.1.85,这台机器上使用docker info命令来查看集群中的节点的信息.

 

其中info也可以换成其他的Docker支持的命令.

注意这句命令不在前面我们加入swarm三台机器上执行.是在一个新的机器上执行的.

docker -H 192.168.1.83:2376 info

 

如果你发现上面命令只出现了两台机器,这样的话,可能是某一台机器的监听方式没有修改.只需要按照上面两种监听方式的一种来修改一下就可以了.

 

还有可能在使用swarm careta的时候,可能会因为网络原因出现错误.

 
这个时候就出现了我们的第二种方案,使用文件.

 

这种方法相对于第一种方法要简单的多,把要加入集群的机器IP地址和端口号写入文件中,本次实验就是要在83这台机器上操作:

$echo 192.168.1.83:2375 >> cluster
$echo 192.168.1.84:2375 >> cluster
$echo 192.168.1.124:2375 >> cluster


 

$cat cluster

192.168.1.83:2375
192.168.1.84:2375
192.168.1.124:2375


 

第二步是在83这台机器上执行swarm manage:

docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage file:///tmp/cluster


这条命令成功后返回的也是一个ID.

 

还是使用docker ps命令来查看有没有启动成功.

 

测试内容和上面的一样.这里不多说了.

 

 

swarm调度策略

 

说一点前面没数过的东西,swarm支持多种调度策略来选择节点.每次在swarm启动container的时候,swarm会根据选择的调度策略来选择节点运行container.目前支持的有:spread,binpackrandom.通过名字就能看出他们的调度策略有啥不同.

 

在执行swarm manage命令启动swarm集群的时候可以通过--strategy参数来指定,默认是spread.spreadbinpack策略会根据每台节点的可用CPU,内存以及运行的containers的数量来给各个节点分级,random策略是随机选择一个节点来启动container.

 

使用spread策略,swarm会选择一个正在运行的container的数量最少的那个节点来运行container.这种情况会导致启动的container会尽可能的分布在不同的机器上运行,这样的好处就是如果有节点坏掉的时候不会损失太多的container.

 

binpack则相反,这种情况下,swarm会尽可能的把所有的容器放在一台节点上运行.这种策略会避免容器碎片化,因为它会把未使用的机器分配给更大的容器,带来的好处就是swarm会使用最少的几点运行最多的容器.

 

 

spread策略

 

演示一下spread策略:

$sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage --strategy=spread file:///tmp/cluster

成功之后会返回一个ID.

 

使用docker ps来看一下运行情况

三台机器除了83运行了swarm之外,其他的都没有运行任何一个容器,现在在85这台机器上面在swarm集群上启动一个容器:

$docker -H 192.168.1.83:2376 run --name node-1 -d -P redis

成功还是返回一个ID

$docker -H 192.168.1.83:2376 ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                  PORTS                          NAMES
2553799f1372        redis:latest        /entrypoint.sh redis   24 minutes ago      Up Less than a second   192.168.1.84:32770->6379/tcp   084/node-1

 

启动一个redis容器,查看结果

$docker -H 192.1687.1.83:2376 run --name node-2 -d -P redis
$docker -H 192.168.1.83:2376 ps
CONTAINER ID        IMAGE                            COMMAND                CREATED                  STATUS              PORTS                           NAMES
7965a17fb943        redis:latest   /entrypoint.sh redis   Less than a second ago   Up 1 seconds        192.168.1.124:49154->6379/tcp   124/node-2                  
2553799f1372        redis:latest                     /entrypoint.sh redis   29 minutes ago           Up 4 minutes        192.168.1.84:32770->6379/tcp    084/node-1


 

再次启动一个redis容器,查看结果:

$docker -H 192.1687.1.83:2376 run --name node-2 -d -P redis
$docker -H 192.168.1.83:2376 ps
 
CONTAINER ID        IMAGE                            COMMAND                CREATED                  STATUS              PORTS                           NAMES
7965a17fb943        redis:latest                     /entrypoint.sh redis   Less than a second ago   Up 4 minutes        192.168.1.227:49154->6379/tcp   124/node-2
65e1ed758b53        redis:latest                     /entrypoint.sh redis   25 minutes ago           Up 17 seconds       192.168.1.83:32770->6379/tcp    083/node-3
2553799f1372        redis:latest                     /entrypoint.sh redis   33 minutes ago           Up 8 minutes        192.168.1.84:32770->6379/tcp    084/node-1


 

能看出三个容器是分布在不同的节点上面的.

 

 

binpack策略

 

现在来看看binpack策略下的情况.83上面执行命令:

docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage ---strategy=binpack  file:///tmp/cluster


现在在集群中启动三个redis容器,查看分布情况.

 

还是在85这台机器上执行如下命令:

$docker -H 192.168.1.83:2376 run --name node-1 -d -p redis
 
$docker -H 192.168.1.83:2376 run --name node-2 -d -p redis
 
$docker -H 192.168.1.83:2376 run --name node-3 -d -p redis


 

查看一下

$docker -H 192.168.1.83:2376 ps
 
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                  PORTS                          NAMES
2195086965a7        redis:latest        /entrypoint.sh redis   24 minutes ago      Up Less than a second   192.168.1.83:32773->6379/tcp   083/node-3
7e778bde1a99        redis:latest        /entrypoint.sh redis   24 minutes ago      Up Less than a second   192.168.1.83:32772->6379/tcp   083/node-2
18ceefa5e86f        redis:latest        /entrypoint.sh redis   25 minutes ago      Up 22 seconds           192.168.1.83:32771->6379/tcp   083/node-1


 

这些容器都是在一个节点上运行的.

 

 

Swarm过滤器

 

swarm的调度器(scheduler)在选择节点运行容器的时候支持几种过滤器(filter):Constraint,Affinity,Port,Dependency,Health.

 

可以在执行swarm manage命令的时候通过--filter选择来设置.

 

Constraint Filter

 

constraint是一个跟具体节点相关联的键值对,可以看做是每个节点的标签,这个标签可以在启动docker daemon的时候指定,比如:

$docker -d --label label_name=label01


 

也可以写在docker的配置文件里面(ubuntu上是在/etc/default/docker).

 

本次试验中,83添加标签--label label_name083,84124添加的类似.83为例,打开/etc/default/docker文件,修改DOCKER_OPTS:

DOCKER_OPTS="-H 0.0.0.0:2375 -H unix:///var/run/docker.sock  --label label_name=083"

别忘了,三台机器的DOCKER_OPTS都需要修改.

 

在使用docker run命令启动容器的时候,使用 -e constarint:key=value 的形式,可以指定container运行的节点.

 

比如我们想在84上面启动一个redis容器.

$docker -H 192.168.1.83:2376 run --name redis_1 -d -e constraint:label_name==084 redis

成功之后返回一个ID.

 

需要注意的是,这里是两个等号,不是一个!

接下来再在084这台机器上启动一个redia容器.

$docker -H 192.168.1.83:2376 run --name redis_2 -d -e constraint:label_name==084 redis


然后再在083这台机器上启动另外一个redis容器.

$docker -H 192.168.1.83:2376 run --name redis_3 -d -e constraint:label_name==083 redis


 

接下来看一下执行情况:

$docker -H 192.168.1.83:2376 ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
7786300b8d22        redis:latest        "/entrypoint.sh redi   15 minutes ago      Up 53 seconds       6379/tcp            083/redis_3
4968d617d9cd        redis:latest        "/entrypoint.sh redi   16 minutes ago      Up 2 minutes        6379/tcp            084/redis_2
fee1b7b9dde1        redis:latest        "/entrypoint.sh redi   19 minutes ago      Up 5 minutes        6379/tcp            084/redis_1


 

可以看到,执行结果跟预期的一样.

 

但是如果指定一个不存在的标签的话来运行容器会报错.

 

 

Affinity Filter

 

通过使用Affinity Filter,可以让一个容器紧挨着另一个容器启动,也就是说让两个容器在同一个节点上面启动.

 

先在其中一台机器上面启动一个redis容器.

$docker -H 192.168.1.83:2376 run -d --name redis redis


 

查看一下

$docker -H 192.168.1.83:2376 ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                  PORTS               NAMES
ea13eddf6679        redis:latest        /entrypoint.sh redis   24 minutes ago      Up Less than a second   6379/tcp            083/redis

 

然后再次启动两个redis容器.

 

$docker -H 192.168.1.83:2376 run -d --name redis_1 -e addinity:container==redis redis
 
$docker -H 192.168.1.83:2376 run -d --name redis_1 -e addinity:container==redis redis


 

查看一下结果,可以看到三个容器都是在一台机器上运行:

 
$docker -H 192.168.1.83:2376 ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                  PORTS               NAMES
449ed25ad239        redis:latest        /entrypoint.sh redis   24 minutes ago      Up Less than a second   6379/tcp            083/redis_2
bac50c2e9552        redis:latest        /entrypoint.sh redis   25 minutes ago      Up 10 seconds           6379/tcp            083/redis_1
ea13eddf6679        redis:latest        /entrypoint.sh redis   28 minutes ago      Up 3 minutes            6379/tcp            083/redis
 

通过-e affinity:image=image_name 命令可以指定只有已经下载了image_name镜像的机器才运行容器.

 

$docker -H192.168.1.83:2376 run -name redis1 -d -e affinity:image==~redis redis


这条命令的效果是:在有redis镜像的节点上启动一个名字叫做redis的容器,如果每个节点上面都没有redis容器,就按照默认的启动策略启动redis容器.

 

Port Filter

Port会被认为是一个唯一的资源

$docker -H 192.168.1.83:2376 run -d -p 80:80 nginx


执行完这条命令,之后任何使用80端口的容器都会启动失败.

 

说句题外话,这些东西,如果你是使用Vagrantfile来创建的虚拟机,那么你可以很好地给虚拟机分配你想要的任何东西,包括IP地址.这些东西如果使用vagrang来管理虚拟机的话,会显得很简单.

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐