跳转至

上一章,把我们的应用转变成一个服务并部署在了单节点机群上,单节点机群使用多个进程模拟机群。

这一章我们将把应用部署在多物理机器组成的机群上。多容器多机器应用可以放在被Docker化的机群上,即swarm

理解Swarm机群

Swarm是运行Docker并组成集群的一组机器。你可以像在一台机器上运行Docker命令,但实际上,它会通过Swarm Manager在整个机群上运行。Swarm机群中的机器可以是虚拟的也可以是物理的,当它们加入Swarm机群后,被称作节点

Swarm管理器可以使用多种策略来运行容器,空结点是指那些运行最不常用容器的机器。全局策略会确保每一台机器只运行一个指定的容器实例。你在docker-compose.yml中指示swarm机群使用哪一种策略。

Swarm管理是机群中唯一的一台允许你执行命令或授权其它机器作为工作者加入机群的角色。工作者只提供处理能力,不能指挥其它机器。

目前为止,我们的操作都是在单主机环境下进行的。但是Docker可以转换成机群模式,转换为机群模式会把当前的机器变成Swarm Manager。至此,Docker运行的命令会作用在所管理的机群所有机器上,而不仅仅只在当前机器上执行。

建立你的Swarm机群

一个Swarm机群由多个节点组成,这些节点可以是虚拟的也可以是物理的。

运行docker swarm init开启swarm模式,并把当前的机器变为swarm manager

使用docker swarm join来使其它的机器作为工作者加入到Swarm机群中,创建机群需要多个机器,我们可以使用虚拟机来创建多个虚拟的机器。

创建机群

安装Virtual Box

注意:如果你是Windows 10系统,它自带的Hyper-V就可以创建虚拟机,所以不需要安装Virtual Box

安装完Virtual Box后,使用docker-machine来创建多个虚拟机:

$ docker-machine create --driver virtualbox myvm1
$ docker-machine craete --driver virtualbox myvm2

你现在创建了两个虚拟机了,可以使用命令docker-machine ls来查看。第一个会指定为manager,第二个会被受权加入机群,成为工作者。

$ docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
myvm1   -        virtualbox   Running   tcp://192.168.99.100:2376           v17.06.0-ce   
myvm2   -        virtualbox   Running   tcp://192.168.99.101:2376           v17.06.0-ce   

可以使用docker-machine ssh来登录myvm1,并使其成为一个Swarm Manager

$ docker-machine ssh myvm1 "docker swarm init"
Error response from daemon: could not choose an IP address to advertise since this system has multiple addresses on different interfaces (10.0.2.15 on eth0 and 192.168.99.100 on eth1) - specify one with --advertise-addr
exit status 1

如果碰到需要使用--advertise-addr的错误,可以使用docker-machine ls先查看myvm1的IP地址,再使用命令运行一次,但是我们需要使用端口2377,因为swarm join使用这个端口工作:

$ docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.100:2377"
Swarm initialized: current node (7z8gne0xkr4nixklkx8t1sb3g) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-5t4tfzrmtnw9prl7fcpcwpgp924vvntg03urytnw1g2c7ou0ej-6thxazc7buydklnmyi1idr1rv 192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

docker swarm init会输出一段用来加入机群的指令,你可以复制这段指令并在想加入的机器上运行就可以把机器转化成工作者了。

$ docker-machine ssh myvm2 "docker swarm join --token SWMTKN-1-5t4tfzrmtnw9prl7fcpcwpgp924vvntg03urytnw1g2c7ou0ej-6thxazc7buydklnmyi1idr1rv 192.168.99.100:2377"
This node joined a swarm as a worker.

恭喜你,已经创建了你的第一个机群了。

直接使用docker-machine ssh myvm1这种方式会登录机器,需要使用exit来登出

而使用docker-machine ssh myvm1 "command"这种方法会登录机器后执行命令,并自动登出。

在机群上部署你的应用

最难的部分过去了,现在只需要重复在上一章已经做过的流程来就可以了。只需要记住myvm1Swarm Manager可以执行指令,其它的是工作者,只处理事务。

把我们之前创建的docker-compose.yml文件拷到myvm1这个swarm manager上:

$ docker-machine scp docker-compose.yml myvm1:~
docker-compose.yml                                                                    100%  368   333.7KB/s   00:00 

然后开始部署我们的应用到机群上:

$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose.yml hello"
Creating network hello_webnet
Creating service hello_web

查看部署情况:

$ docker-machine ssh myvm1 "docker stack ps hello"
ID                  NAME                IMAGE                      NODE                DESIRED STATE       CURRENT STATE                  ERROR               PORTS
fla301e97hse        hello_web.1         zhulongyixian/hello:v1.0   myvm2               Running             Preparing about a minute ago                       
jhp43be5v3op        hello_web.2         zhulongyixian/hello:v1.0   myvm1               Running             Preparing about a minute ago                       
k58kkikey222        hello_web.3         zhulongyixian/hello:v1.0   myvm2               Running             Preparing about a minute ago                       
85gtwdojwots        hello_web.4         zhulongyixian/hello:v1.0   myvm1               Running             Preparing about a minute ago   

可以看到应用已经被部署到机群上了。

访问你的机群

你可以通过myvm1或者myvm2的IP地址来访问我们已经部署的应用。因为我们创建了在机群机器间共享的网络层,用来平衡负载。

使用docker-machine ls查看机器的IP地址:

$ docker-machine ls
NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
myvm1   -        virtualbox   Running   tcp://192.168.99.100:2376           v17.06.0-ce   
myvm2   -        virtualbox   Running   tcp://192.168.99.101:2376           v17.06.0-ce

在浏览器中打开:http://192.168.99.100就可以访问服务了。多刷新几次浏览器,会发现容器ID会不停的变化,说明我们的机群可以处理负载平衡。

我们可以通过机群内任意一个节点的IP来访问服务的原因是我们的机群设置了路由网。这可以使部署的服务在机群内部有指定端口,不用关心容器是如果被执行的。下面是一张三节点机群图用来说明发布在8080端口的my-web服务的内部网络结构:

ingress network

可能遇到的连接问题: 为了使用Swarm机群,我们在开启Swarm模式前要确保节点之间的以下端口是打开的:

  • 7946 TCP/UDP端口,这个端口用于网络发现
  • 4789 UDP端口,这个端口用于容器的ingress网络

扩展你的应用

你可以像第三章学到的那样,通过改变docker-compose.yml中的设置并重新运行命令docker stack deploy -c docker-compose.yml hello来改变部署的方式。也可以使用命令docker swarm join命令来加入更多的工作者节点,然后使用前面的命令更新部署一次。

清理工作

可以使用下面的命令停止应用栈的运行:

$ docker-machine ssh myvm1 "docker stack rm hello"
Removing service hello_web
Removing network hello_webnet

这只是移除了机群上的应用,但机群本身还在运行。

可以使用下面的命令关闭机群:

$ docker-machine ssh myvm2 "docker swarm leave"
Node left the swarm. # 工作者节点离开机群

$ docker-machine ssh myvm1 "docker swarm leave --force"
Node left the swarm. # 机群管理节点离开机群

常用到的指令列表

docker-machine create --driver virtualbox myvm1 # Create a VM (Mac, Win7, Linux)
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1 # Win10
docker-machine env myvm1                # View basic information about your node
docker-machine ssh myvm1 "docker node ls"         # List the nodes in your swarm
docker-machine ssh myvm1 "docker node inspect <node ID>"        # Inspect a node
docker-machine ssh myvm1 "docker swarm join-token -q worker"   # View join token
docker-machine ssh myvm1   # Open an SSH session with the VM; type "exit" to end
docker-machine ssh myvm2 "docker swarm leave"  # Make the worker leave the swarm
docker-machine ssh myvm1 "docker swarm leave -f" # Make master leave, kill swarm
docker-machine start myvm1            # Start a VM that is currently not running
docker-machine stop $(docker-machine ls -q)               # Stop all running VMs
docker-machine rm $(docker-machine ls -q) # Delete all VMs and their disk images
docker-machine scp docker-compose.yml myvm1:~     # Copy file to node's home dir
docker-machine ssh myvm1 "docker stack deploy -c <file> <app>"   # Deploy an app