MYF

Get Started, Part 4: Swarms

参考文档:Get Started, Part 4: Swarms

Prerequisites

  • 安装1.13或者更高版本的Docker
  • 如Part 3中所说的安装Docker Compose
  • 安装Docker Machine,Windows版本和Mac版本的Docker已经预先就有了,但是在Linux系统你需要直接安装。在Windows 10之前的版本(没有Hyper V),以及Windows 10 家庭版本使用Docker Toolbox
  • 看Part 1中的内容
  • 看Part 2中的内容学会如何创建container
  • 确保你已经发布了friendlyhello镜像,你应应该在发布到registry这一节中创建了,在本节中我们将使用这个镜像
  • 确保你的image作为一个部署了的容器一样运行,运行下面这个指令,将username, repo, tag三个换成你自己的docker run -p 80:80 username/repo:tag,然后访问http://localhost/
  • 复制你在Part 3中创建的docker-compose.yml文件

Introduction

在Part 3中,你已经知道怎么将Part 2中写的app运行起来了,并且定义了它在生产环境中应该如何运行,也就是作为一个服务,将其规模化,形成进程中的5个容器

在这里Part 4,你需要部署这个application在一个集群上(cluster),将其运行在多个机器上。通过将多台机器加入docker化的集群,多个容器多台机器的应用的程序将会形成,我们称之为集群(swarm)。

Understanding Swarm clusters

一个swarm是一组运行Docker的机器,他们的加入形成了cluster。之后,你继续运行你习惯的Docker指令,但是现在他们现在是通过swarm manager运行在一个cluster上。集群中的机器可以是实体的也可是虚拟的,通过加入一个集群,每一台机器称为一个结点(node)。

Swarm manager可以使用多种策略来运行容器,比如“emptiest node”策略,这个策略是指使用最少的已经有容器的主机(fills the least utilized machines with containers)。或者”global”策略,这个策略确保每一个机器只会获得一个特定容器的实例。你可以通过swarm manager来使用Compose文件中的这些策略,就像你已经使用了的。

Swarm managers是sawrm中唯一运行你的指令的那些机器,或者授权其他用户作为workers加入swarm。Workers是指那些提供能力(capacity)但是无权告诉其他机器能做什么或者不能做什么的。

直到现在,你一直使用Docker在一个单一主机的模式上。但是Docker同样可以切换到swarm模式,这样就可以使用swarm了。启动swarm mode立刻就会让当前的机器称为一个swarm manager。从这时起,Docker会在你管理的机器上运行指令,而不仅仅是当前的机器。

Set up your swarm

一个swarm由多个node组成,这些node可以是实体机器也可以是虚拟机器。最基本的概念非常简单,运行docker swarm init就可以启动swarm模式,让你当前的机器成为swarm manager了,然后运行docker swarm join在其他的机器上,这样别的机器就可以作为workers加入。选择下面之一的一个tab,去看看如何在多个环境下做这些事情。我们这里使用虚拟机来快速创建一个包含两个机器的cluster,并且将其转化为一个swarm。

Create a cluster

VMS ON YOUR LOCAL MACHINE (MAC, LINUX, WINDOWS 7 AND 8)

这里只翻译Local VM(Mac, Linux, Windows 7 and 8)部分,Local VMs(Windows 10/Hyper-V)请见doc

你需要一个可以创建虚拟机的管理程序(hypervisor),所以安装适合你机器系统的Oracle VirtualBox

注意:如果你使用已安装Hyper-V的Windows系统,比如Windows 10,那么就不需要安装VirtualBox了,并且你应该直接使用Hyper-V。通过另一个tab(就是没翻译的那部分)查看Hyper-V的使用教程。如果你咋使用Docker Toolbox,你应该已经安装了VirtualBox,所以你可以继续了。

现在,使用docker-machine创建一系列虚拟机,使用Virtualbox driver:

1
2
docker-machine create --driver virtualbox myvm1
docker-machine create --driver virtualbox myvm2

LIST THE VMS AND GET THEIR IP ADDRESSES

现在你有两个虚拟机了,名字为myvm1myvm2

使用这个指令列出这些主机,并且获取他们的ip地址

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

INITIALIZE THE SWARM AND ADD NODES

第一个机器作为manager,它来执行指令,控制其他worker加入swarm,第二个十一个worker。

你可以通过使用docker-machine ssh来将指令发送到虚拟机上。在myvm1上执行docker swarm init指令使之成为swarm manager,然后你会看到这样的输出:

1
2
3
4
5
6
7
8
9
10
$ docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"
Swarm initialized: current node <node ID> is now a manager.

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

docker swarm join \
--token <token> \
<myvm ip>:<port>

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

端口2377和2376
总是通过运行docker swarm initdocker swarm join在2377端口(这个端口是swarm的管理端口),或者不指定端口让其使用默认端口
通过docker-machine ls返回的机器IP地址包括了2376,这个是Docker守护进程的端口,不要占用这个端口,否则你会遇到一些错误

使用SSH的时候遇到了问题?试试加上--native-ssh标记
Docker Machine允许你使用系统的SSH,如果因为某种原因你无法向你的Swarm manager发送指令,那么使用--native-ssh标记当使用ssh指令的时候
docker-machine --native-ssh ssh myvm1 ...

如你所见,docker swarm init指令的反馈包含了一句配置好的docker swarm join指令,你可以用他运行在任何nodes上。复制这个指令,通过docker-machine ssh指令发送到myvm2上,让你的myvm2加入你的swarm。

1
2
3
4
5
$ docker-machine ssh myvm2 "docker swarm join \
--token <token> \
<ip>:2377"

This node joined a swarm as a worker.

恭喜你,你已经创建好了一个swarm了。

运行docker node ls在manager机器上,就可以看到swarm中的集群了

脱离一个swarm
如果你想重来,你可以在node上运行docker swarm leave来脱离swarm

Deploy your app on the swarm cluster

最难的部分已经结束了,现在你可以重复你在part 3的过程来部署你的swarm了。但是记住一点,只有像myvm1一样的manager具有执行docker指令的权力,其他的worker只是用来被调用资源的(for their capacity)。

Configure a docker-machine shell to the swarm manager

目前位置,你已经把Docker指令包装在了docker-machine ssh中发送给了虚拟机。另一个选择是运行docker-machine env <machine>来获取和运行一个指令从而配置你当前的Shell,让其将指令传送给虚拟机中的Docker守护进程。这个方法对于下一步效果更好,因为他允许你使用本地的docker-compose.yml文件来远程部署你的文件,而不用把它复制来复制去。

键入docker-machine env myvm1,然后复制粘贴运行你向myvm1发送指令时输出的最后一行。

输出的指令会因为你是Mac/Linux/Windows系统的不同而不同,下面列出了不同系统的反馈实例

Mac, Linux

DOCKER MACHINE SHELL ENVIRONMENT ON MAC OR LINUX

运行docker-machine env myvm1来获取指令,然后配置你的shell向myvm1发送指令

1
2
3
4
5
6
7
$ docker-machine env myvm1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/sam/.docker/machine/machines/myvm1"
export DOCKER_MACHINE_NAME="myvm1"
# Run this command to configure your shell:
# eval $(docker-machine env myvm1)

运行给出的指令

1
eval $(docker-machine env myvm1)

运行docker-machine ls来验证myvm1是一个活跃的机器,如同下面的*所表示的那样

1
2
3
4
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 * virtualbox Running tcp://192.168.99.100:2376 v17.06.2-ce
myvm2 - virtualbox Running tcp://192.168.99.101:2376 v17.06.2-ce

Windows

运行docker-machine env myvm1来获取指令,然后配置你的shell向myvm1发送指令

1
2
3
4
5
6
7
8
PS C:\Users\sam\sandbox\get-started> docker-machine env myvm1
$Env:DOCKER_TLS_VERIFY = "1"
$Env:DOCKER_HOST = "tcp://192.168.203.207:2376"
$Env:DOCKER_CERT_PATH = "C:\Users\sam\.docker\machine\machines\myvm1"
$Env:DOCKER_MACHINE_NAME = "myvm1"
$Env:COMPOSE_CONVERT_WINDOWS_PATHS = "true"
# Run this command to configure your shell:
# & "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression

运行给出的指令

1
& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression

运行docker-machine ls来验证myvm1是一个活跃的机器,如同下面的*所表示的那样

1
2
3
4
PS C:PATH> docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 * hyperv Running tcp://192.168.203.207:2376 v17.06.2-ce
myvm2 - hyperv Running tcp://192.168.200.181:2376 v17.06.2-ce

Deploy the app on the swarm manager

现在你有myvm1了,你可以发挥他作为swarm manager的作用来部署你的app,通过和part 3中你用过的相同的指令docker stack deploy,以及你本地的docker-compose.yml文件。这个指令可能需要花几秒来完成,部署同样需要一些时间。使用docker service ps <service_name>指令来验证是否所有的服务都被重新部署了。

你现在通过docker-machine来连接到myvm1,你仍然可以访问你主机的文件,确保你已经在相同的文件目录下了,也就是说会有一个你在part3中创建的docker-compose.yml文件。

如同之前,运行下面的指令来在myvmm1上部署你的app。

1
docker stack deploy -c docker-compose.yml getstartedlab

就这样,你的app部署在一个swarm的cluster上了。

注意:如果你的镜像存储在私有的registry而不是Docker Hub上,你需要使用docker login <your-registry>来登录你的registry,然后你需要对上面的指令添加--with-registry-auth标记,比如:

1
2
3
> docker login registry.example.com
> docker stack deploy --with-registry-auth -c docker-compose.yml getstartedlab
>

这会发送你登录的令牌到你部署服务的swarm结点上,使用加密的WAL日志。有了这个信息,结点就可以登录到registry上并且把image给pull下来。

现在你可以使用part 3中相同的docker指令了。不过请注意,这里指令会被部署到myvm1myvm2上。

1
2
3
4
5
6
7
8
$ docker stack ps getstartedlab

ID NAME IMAGE NODE DESIRED STATE
jq2g3qp8nzwx getstartedlab_web.1 john/get-started:part2 myvm1 Running
88wgshobzoxl getstartedlab_web.2 john/get-started:part2 myvm2 Running
vbb1qbkb0o2z getstartedlab_web.3 john/get-started:part2 myvm2 Running
ghii74p9budx getstartedlab_web.4 john/get-started:part2 myvm1 Running
0prmarhavs87 getstartedlab_web.5 john/get-started:part2 myvm2 Running

通过docker-machine envdocker-machine ssh连接到虚拟机

  • 为了让你的Shell向不同的机器发送指令(比如myvm2),重新执行docker-machine env在相同或者不同的Shell中,然后运行给出的指向myvm2的指令。这个总是针对当前的shell。如果你切换到一个未识别的shell或者新开一个,你需要重新运行指令。使用docker-machine ls来列出所有机器,看他们是什么状态,获得他们的IP地址,找出你正在连接哪个。更多资料请访问Docker Machine getting started topics
  • 或者,你可以把指令包装在docker-machine ssh <machine> "<command>",但是日志会直接记录在虚拟机中,并不会给你任何访问你本机的权力
  • 在Mac和Linux中,你可以使用docker-machine scp <file> <machine>:~指令来将文件在多个机器间拷贝,但是Windows用户需要像Git Bash这种的Linux终端来进行此类操作。

这个教程展现了docker-machine sshdocker-machine env,由于这些在全平台的docker-machine客户端上都可用。

Accessing your cluster

你可以访问你的app通过myvm1或者myvm2的IP地址。

你创建的网络对于两者来说是共享的,并且可以实现负载均衡。运行docker-machine ls来获取你的虚拟机的IP地址,然后访问两者中的任意一个,然后点击刷新。

总共有5个可能的container ID,随机循环,表示负载均衡。

两个IP都有效的原因是swarm中的nodes参与了一个ingress routing mesh。这确保了你的swarm中部署在一个特定端口的一个服务总是有留给自身的端口,不管哪个node实际上在运行容器。这有一个图可以表示一个名为my-web的服务的routeing mesh,这个服务发布在8080端口,是一个三结点的swarm:

有连接问题?
记住,在swarm中使用ingress网络,你需要在你开启swarm mode前在swarm node间开启这些端口

  • 7946端口 TCP/UDP for container network discovery.
  • 4789端口 UDP for the container ingress network.

Iterating and scaling your app

在这里你可以做你在part 2和part 3中学习的东西了。

通过更改docker-compose.yml文件来规模化你的app。

通过修改代码来更改app行为,然后重建,然后push新的image。(按照你之前学习的build the apppublish the image来)

不管在哪个情况下,只运行docker stack deploy一次来部署这些改变。

你可以加入任何的机器,实体的或者虚拟的,通过使用docker swarm join命令,如同你使用在myvm2上的一样,新的capacity会加入你的cluster。通过使用docker stack depoly,你的app可以利用新的资源。

Cleanup and reboot

Stacks and swarms

你可以通过docker stack rm指令来拆掉stack,比如

1
docker stack rm getstartedlab

保留swarm还是移除他?
在后面的某些时候,你能够移除这个swarm,通过在worker机上运行docker-machine ssh myvm2 "docker swarm leave"以及在manager机器上运行docker-machine ssh myvm1 "docker swarm leave --force",但是在Part 5中你需要这个swarm,所以暂时先留着他吧

Unsetting docker-machine shell variable settings

在你当前的shell中,通过以下指令,你可以重置docker-machine的环境变量:

1
eval $(docker-machine env -u)

这会让shell和docker-machine创建的虚拟机分开,并且允许你继续在相同的shell下工作,现在使用本地的docker指令(比如,在Docker for Mac或者Docker for Windows)。了解更多,请看Machine topic on unsetting environment variables

Restarting Docker machines

如果你关掉你的本地主机,Docker machine会停止运行。你可以检查机器的状态通过运行docker-machine ls命令

1
2
3
4
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 - virtualbox Stopped Unknown
myvm2 - virtualbox Stopped Unknown

想要重启已经停止的机器,运行:

1
docker-machine start <machine-name>

比如,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker-machine start myvm1
Starting "myvm1"...
(myvm1) Check network to re-create if needed...
(myvm1) Waiting for an IP...
Machine "myvm1" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

$ docker-machine start myvm2
Starting "myvm2"...
(myvm2) Check network to re-create if needed...
(myvm2) Waiting for an IP...
Machine "myvm2" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

Recap and cheat sheet (optional)

在Part4中,你学习了Swarm是什么,swarm中的nodes如何成为manager或者worker,创建一个swarm,并且在上面部署一个应用,你可以看到Docker核心指令从Part3开始就没有变化,他们只是必须要被运行在swarm manager上。你也看到了Docker的网络方面的能力,这保证了container之间的负载均衡,尽管他们运行在不同的机器上,最后,你学习了如何iterate和scale你的app在cluster上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 node ls # View nodes in swarm (while logged on to manager)
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 ls # list VMs, asterisk shows which VM this shell is talking to
docker-machine start myvm1 # Start a VM that is currently not running
docker-machine env myvm1 # show environment variables and command for myvm1
eval $(docker-machine env myvm1) # Mac command to connect shell to myvm1
& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression # Windows command to connect shell to myvm1
docker stack deploy -c <file> <app> # Deploy an app; command shell must be set to talk to manager (myvm1), uses local Compose file
docker-machine scp docker-compose.yml myvm1:~ # Copy file to node's home dir (only required if you use ssh to connect to manager and deploy the app)
docker-machine ssh myvm1 "docker stack deploy -c <file> <app>" # Deploy an app using ssh (you must have first copied the Compose file to myvm1)
eval $(docker-machine env -u) # Disconnect shell from VMs, use native docker
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