1. 介绍

docker 1.12版本以后就将docker swarm这个工具集成到了docker当中了。老版本使用docker swarm可以参考我的文章docker swarm安装使用

本文对于swarm mode的使用说明主要参考官方文档:Swarm mode overview

swarm mode相比原来的docker swarm在使用上方便了很多。未来肯定是取代docker swarm了,毕竟都内置在docker了。

2. 准备工作

2.1 开启docker node的2375端口

确保开启Docker的TCP连接端口。

PS: 需要被swarm管理的节点上的docker都需要开启2375端口。

#centos: 
vim /lib/systemd/system/docker.service
# 修改ExecStart所在的这一行为如下内容
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375  -H unix:///var/run/docker.sock 
# 重新启动服务
systemctl daemon-reload && service docker restart

#ubuntu: 
vim /etc/default/docker

OCKER_OPTS="-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock"

service docker restart 

2375为Docker默认的tcp通讯端口,稍后在使用主机连接时需要用到。 、

3. 创建和管理swarm集群

3.1 创建swarm集群

docker swarm init --advertise-addr 10.45.10.31

和docker swarm一样,我们得到了一个唯一的token来标识swarm集群。忘记了这个token可以使用以下命令查询:

# 查询worker加入swarm集群的方法
docker swarm join-token worker

docker info 和docker node ls等命令可以来查看node情况。

3.2 将工作节点加入swarm集群

在要加入到swarm集群的节点上执行docker swarm join-taken worker得到的命令,即可加入swarm集群:

现在我们的swarm集群有2个节点,其中一个是本身作为manager的leader,另外个则是普通的工作节点。我们可以在manager节点上用命令查看node信息:

4. 创建和管理服务(重磅特性)

使用swarm引入了service、task等概念。服务可以动收缩、热升级、捆绑部署等等,好处很多。在docker.1.12以前,要实现服务栈、服务等概念需要使用docker compose,现在这些功能也内置集成到docker当中了,十分棒。

注意理解swarm中服务的概念。一个服务并非一个容器,一个服务可以有多个副本任务task(创建service的时候由replicas指定)。每个task对应着一个容器。副本数量可以通过scale操作来增加或者收缩。一般使得副本任务数能均匀分散在各个节点(默认调度策略也是spread),这样一个节点挂了之后,仍然有其他容器可以提供服务。

关于service的基本说明建议再看下官方文档——swarm核心概念说明

众多服务可以打包成一个服务栈来进行部署。关于docker stack的内容不属于不节内容,感兴趣也可以看如下一些docker stack官方文档。注意docker 1.13版本中,集成了docker stack的相关命令。

4.1 为什么引入服务的概念

下文参考自https://linux.cn/article-7660-1.html
在引入 services 之前,我们部署的都是独立容器。如果我们手头有一个 App 应用,包含了 5 个组件,那么部署和管理他们将是一项很沉重的工作。要想使之规模化,是很困难的,运行更新和升级的工作也十分枯燥。

引入 services 后,这些问题都烟消云散了。

有了 services,同样是带有 5 个组件的 App,我们可以把每个组件定义为一个 Docker Service,而且这些全都是声明式的。这也就意味着,我们可以告诉 Docker 说,“嘿,你要保证始终有 5 个容器在支持我的网页前端服务”,然后 Docker 就会哼哧哼哧地保证始终有 5 个容器在支持你的网页前端服务。就算偶尔崩溃了,修复成本也就一美元!

但这还不是 services 的全部。你是想得到一次需求高峰,还是预测一次需求高峰?要快速测量你的 service,只需要一个简单命令即可。

升级也是件手到擒来的事。想要给你 service 使用中的图像换个版本?跟逛公园似的!一个简单的命令下去,你的service 就升级到最新版本了。

而同样是这道简单的命令,还能把升级变成无缝升级(rolling update)。举个例子,拿一个带有 200 个容器的service,20 个容器一批,每次同时升级一批,然后在每一批的间隙等待 15 分钟。

PS: 总的来说,service功能,简直太好用,主要解决了热升级服务、服务部署管理这些痛点问题。

4.2 负载均衡

swarm mode里面已经内置了负载均衡的功能。负载均衡器和容器集成在一起,入下图。swarm里面的服务作为一个整体交给swarm通过一个公有端口暴露给外界访问。对服务的访问,可以通过负载均衡,分配到不同的task上。

4.3 创建服务

我们这里使用alpine这个镜像,构建一个容器作为服务。

# 注意提前下载alpine,否则会在这hang住的
docker service create --replicas 1 --name helloworld alpine ping docker.com
  1. --name: 指明服务的名字
  2. --replicas: 指定服务运行的实例数.
  3. alpine ping docker.com:把 Alpine Linux 这个容器作为一个服务。该容器会执行ping docker.com这个操作

4.4 查看服务

服务的简单信息可以使用命令docker service ls查看

查看服务详情,使用如下命令:

# pretty选项,使得信息不以json形式展现
docker service inspect --pretty helloworld

查看哪个node运行服务,使用如下命令:

# 在manager上查看
docker service ps helloworld

4.5 动态扩展副本任务数

# 实例数扩展为5
docker service scale helloworld=5
# 查看helloworld这个容器的实例数
docker service ps helloworld

PS: 下图中有几个Shutdown的不必太在意,是我之前手动用docker stop helloworld去停止容器的时候生成的。手动stop容器去停止,会发现该容器的服务会自动恢复。

4.6 删除服务

删除服务后,会发现所有该容器的实例都停止了

docker service rm helloworld

4.7 对服务滚动升级

下面来简单演示如何将redis这个服务,从版本3.0.6进行升级

# 部署一个alpine 3.3的服务
docker service create \
  --replicas 3 \
  --name alpine \
  --update-delay 10s \
  alpine:3.3
# 检查一下服务信息,确认下版本信息为3.3
  docker service inspect --pretty alpine
# 对服务进行升级
  docker service update --image alpine:3.4 alpine
# 检查一下服务信息,确认下版本信息为3.4。此外inspect也能观察更新的状态,例如更新被暂停了
  docker service inspect --pretty alpine

4.7.1 docker service的参数说明

  1. --update-delay: 发生升级更新时,多个task(replicas指定)进行update之间进行更新的间隔。主要是为了确保1个更新完毕之后再进行下一个,如果所有的task都进行更新了,这个服务就不能对外进行正常服务了。
  2. --update-parallelism: 可以指定最多同时有几个task容器进行更新操作
  3. --update-failure-action: 设置更新失败时执行的操作

更多参数说明可以参考官方文档:docker service

4.7.2 docker service滚动升级步骤

docker service默认采用如下步骤来进行滚动升级:

  1. 停止第一个task
  2. 对停止的task进行调度,执行更新操作
  3. 对更新好的task启动容器
  4. 如果更新的task最后返回了RUNNING,表示更新成功,等待一段指定好的事件,然后再停止下一个task
  5. 如果更新的task返回FAILED,那么就停止该更新

4.8 修改node的可用性

node的status可以有active和drain。active状态,顾名思义,可以接受新的task分配。改变node节点的可用性为drain,该节点则不会接受新的task,并且原本运行在上面的task会根据service设置的replicas而重新分配到别的active node上运行。

使用方法:

# hostname忘记了可以用docker node ls查看
docker node update --availability drain worker1
docker node update --availability active worker1