[TOC]
Swarm简介和使用介绍
1 Swarm介绍
1.1 简介
Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令。目前,Swarm 是 Docker 社区提供的唯一一个原生支持 Docker 集群管理的工具。它可以把多个 Docker 主机组成的系统转换为单一的虚拟 Docker 主机,使得容器可以组成跨主机的子网网络。
2016年核心团队发现中央服务的扩展被限制之后,Swarm 在内部被再次重新设计为Swarm2,使用了去中心化的集群设计,允许构造数千个节点的集群;随后又发布了SwarmKit(可以作为任规模的分布式服务的编排工具包),将其合并到了Docker Engine,Docker Swarm在设计上遵从了可插拔的设计思想,安装集群只需要启动几个docker就可以完成
Docker三剑客:Docker Swarm、 Docker Machine、 Docker Compose(它们可以无缝的集成)
Docker Machine:预配机器,可以是虚拟机器也可以是物理机器,并可以在若干纯物理机器上运行Docker容器 (Docker Engine和Docker Machine介绍)
Docker Compose:用户可以快速定义Dockerfile,通过简单但是强大的YAML语法描述行为,并且只需要把这些文件“组合”起来就可以启动应用程序(Docker-Compose简介安装使用)
Docker Swarm:强大的集群工具,让用户以为自己管理的是单个巨大的Docker宿主机,而这个宿主机是由很多Docker宿主机组成的
1.2 特性
官网的特性
与Docker Engine集成
使用分散设计:去中心化设计,可大规模部署
声明式服务模式
弹性服务:通过schedule(调度器)Constraint(约束条件)affinity(共同关系)弹性服务
Desired state reconciliation:管理节点收集集群中所有的信息,进行感知和调度
多主机联网:指定overlay 网络,swarm管理器自动将地址分配给覆盖网络上的容器
服务发现:service
负载均衡:使用内建DNS Round-Robin实现集群内的负载均衡,也支持外部负载均衡
回滚更新:高可用和故障恢复机制意味着用户可以创建超过一个master的Swarm
Swarm的特性:
1.工作节点的注册和发现
2.管理节点收集集群中所有的信息
3.管理节点支持HA
4.管理节点能感知集群的变化,在节点挂掉后重新调度上面的container
5.提供filter和scheduler的调度策略调度集群里的容器
1.3 概念
swarm:是一组docker引擎的集群
node:是单个docker引擎的实例,可以在一个物理机上也可以在多个
application:是应用
manager node:部署应用的时候会有一个manager node节点
Worker nodes:对应的就是Worker nodes
service:然后service是一堆被workder执行的任务
replicated services:是负载均衡节点
global services:则是全局的,在所有节点上都会执行的一个服务
task:一个task就是一个docker的容器,是Swarm的工作单元
- docker swarm:集群管理,子命令有 init, join,join-token, leave, update
- docker node:节点管理,子命令有 demote, inspect,ls, promote, rm, ps, update
- docker service:服务管理,子命令有 create, inspect, ps, ls ,rm , scale, update
- docker stack/deploy:用于多应用部署,是创建多容器的应用程序,而不是单个容器的二进制结果
2 使用swarm模式
前提
- 两台网络互通的宿主机
- 安装1.12或更高版本的docker
- 管理节点的IP地址
- 开启宿主机之间的端口(TCP端口2377集群管理端口)
2.1 不使用Docker Machine工具
宿主机名称 | IP |
---|---|
master | 192.168.64.55 |
worker | 192.168.64.56 |
2.1.1 步骤
- 在swarm模式下初始化一个docker引擎的集群
- 添加节点至swarm中
- 发布一个应用服务到swarm中
- 当运行起来之后进行swarm管理
2.1.2 创建swarm集群
创建管理节点
#docker swarm init --advertise-addr <MANAGER-IP>:<PORT>
$docker swarm init --advertise-addr 192.168.64.55:2377
#查看详情
$docker info
#查看节点
$docker node ls
添加节点到集群
#在节点机器上运行如下命令:docker swarm join --token <TOKEN> <MANAGER-IP>:<PORT>
$docker swarm join --token SWMTKN-1-3s7sfvjom026g3eanmt6zym9uxr4qluixl7imuoap4kxbejyqt-da1u66rfp5aiy35baqou7ve8x 192.168.64.55:2377
#在manager节点上查看节点
$docker node ls
2.1.3 发布服务
#在manager上执行如下命令
$docker service create --replicas 1 --name helloBoy alpine ping bilibili.com
-
docker service create
命令创建一个 service. -
--name
标签命名service为helloBoy. -
--replicas
标签来详细声明1个运行实体. - 参数
alpine ping bilibili.com
定义执行pingg bilibili.com
作为alpine容器的服务.
#使用docker service ls查看服务
$docker service ls
#使用docker service inspect审查服务
$docker service inspect --pretty helloBoy
#使用docker service ps <SERVICE-ID>查看服务运行在哪个节点上
$docker service ps helloBoy
#添加更多实例:docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>
$docker service scale helloBoy=5
$docker service ps helloBoy
#删除service
$docker service rm helloBoy
2.1.4 滚动升级
#发布redis服务
#--update-parallelism标签配置服务中同步升级的任务数量 --update-delay标签配置一个服务任务或一系列任务升级的时延:并列度为1,延迟10s,就是一个升完,下一个升,就是所谓的滚动升级了
$docker service create --replicas 3 --name redis --update-delay 10s --update-parallelism 1 redis:3.0.6
$docker service ls
$docker service ps redis
#升级开始
$docker service update --image redis:3.0.7 redis
$docker service ls
$docker service ps redis
$docker service inspect --pretty redis
2.1.5 DRAIN节点
先搞个3.0.6的redis集群
$docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
#drain pbsslave节点
#先查看
$docker node inspect --pretty pbsslave
$docker node update --availability drain pbsslave
$docker node inspect --pretty pbsslave
2.1.6 恢复node
$docker node update --availability active pbsslave
$docker node inspect --pretty pbsslave
2.1.7 使用swarm mode路由网格
ingress routing mesh是个大家伙都参与了的网状网,你就这么理解就好了
Port 7946 TCP/UDP for container network discovery,7946是容器的网络发现端口,TCP
Port 4789 UDP for the container ingress network,4789是容器的ingress网络,UDP
#创建一个my-web的servie然后对外暴露8080端口,内部监听的是80端口
#然后用的image叫nginx
#访问node上的8080端口,任何一个node节点上的,swarm就会自动帮你路由到对应的nginx上去
$docker service create --name my-web --publish 8080:80 --replicas 2 nginx
#对已有的服务
$docker service update --publish-add <PUBLISHED-PORT>:<TARGET-PORT> <SERVICE>
#这两个是TCP ONLY的命令,相互等价
$docker service create --name dns-cache -p 53:53 dns-cache
$docker service create --name dns-cache -p 53:53/tcp dns-cache
#同时使用TCP和UDP
$docker service create --name dns-cache -p 53:53/tcp -p 53:53/udp dns-cache
#仅仅使用UDP
$docker service create --name dns-cache -p 53:53/udp dns-cache
2.1.8 添加全局的网络
#添加 overlay网络,让service和service之间可以通讯
#管理节点上,添加overlay网络my-network
$docker network create --driver overlay my-network
#加--network参数,就可以让所有节点都加入这个网络里去了
$docker service create --replicas 3 --network my-network --name my-web nginx
2.1.9 回滚
#加一个 --rollback参数
$docker service update --rollback --update-delay 0s my_web
2.2 使用Docker Machine工具
在VirtualBox中使用Docker Machine管理主机
Docker Machine:Docker 三剑客之一,是一个工具,用来在虚拟主机上安装Docker Engine,并使用 docker-machine命令来管理这些虚拟主机
宿主机名称 | IP |
---|---|
manager1 | 192.168.64.72 |
worker1 | 192.168.64.73 |
2.2.1 安装Docker Machine
Docker Machine可以安装在Mac、Windows、Linux上
在macOS和Windows上,当您安装Docker for Mac,Docker for Windows或Docker Toolbox时,Machine将与其他Docker产品一起安装。
Linux上需要安装virtualbox作为驱动
1) 安装docker machine
$curl -L https://github.com/docker/machine/releases/download/v0.13.0/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&
chmod +x /tmp/docker-machine &&
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine
#查看版本
$docker-machine -v
#查看虚拟机列表
$docker-machine ls
2) docker-machine命令
- help 查看帮助信息
- active 查看活动的Docker主机
- config 输出连接的配置信息
- create 创建一个Docker主机
- env 显示连接到某个主机需要的环境变量
- inspect 输出主机更新信息
- ip 获取Docker主机地址
- kill 停止某个Docker主机
- ls 列出所有管理的Docker主机
- regenerate-certs 为某个主机重新成功TLS认证信息
- restart 重启Docker主机
- rm 删除Docker主机
- scp 在Docker主机之间复制文件
- ssh SSH到主机上执行命令
- start 启动一个主机
- status 查看一个主机状态
- stop 停止一个主机
- upgrade 更新主机Docker版本为最新
- url 获取主机的URL
以下内容是安装virtualbox,配置使用驱动virtualbox,执行遇到错误,可以改成generic作为驱动,进行集群创建,可以直接调到2.2.2创建集群开始
3) 安装驱动virtualbox
需要给 Docker Machine 提供对应的驱动,这样才能够在上面安装新的虚拟机,
例如可以安装:
vmware 的产品 vSphere:
--driver vmwarevsphere
VirtualBox:
--driver virtualbox
$docker-machine create --driver virtualbox manager1
#出错:Please recompile the kernel module and install it by\\n\\n
#被提示The vboxdrv kernel module is not loaded, 启动一下Virtualbox的Service吧
$/usr/lib/virtualbox/vboxdrv.sh setup
#提示需要安装gcc和kernel-devel-3.10.0-693.el7.x86_64
$yum install -y gcc make
$yum install -y kernel-devel-3.10.0-693.el7.x86_64
#再次启动启动一下Virtualbox的Service
$/usr/lib/virtualbox/vboxdrv.sh setup
#继续尝试
$docker-machine create --driver virtualbox manager1
#出错:Error with pre-create check: "This computer doesn't have VT-X/AMD-v enabled. Enabling it in the BIOS is mandatory"
#设置处理器的虚拟化引擎首选模式为"Intel VT-x/EPT 或AMD-V/RVI"及"虚拟化Intel VT-x/EPT 或AMD-V/RVI(V)"
#继续尝试
$docker-machine create --driver virtualbox manager1
#无法建立ssh服务
#重启virtualbox服务 /usr/lib/virtualbox/vboxdrv.sh restart
错误:225
http://bob-zhangyong.blog.163.com/blog/static/176109820163278754727/
用 docker-machine ssh default 无法连接到 虚拟机,提示 exit status 255 错误。
猜测原因是 在virtual box 中 取消了 NAT 网络。
继续在网上找资料发现可以使用-d generic驱动,制定目标host的IP和用户
#其他的驱动
$docker-machine create -d generic --generic-ip-address=192.168.64.72 --generic-ssh-user=root test
$docker-machine create -d generic --generic-ip-address=192.168.64.73 --generic-ssh-user=root test
-d driver #指定基于什么虚拟化技术的驱动
--generic-ip-address #指定要安装宿主机的IP,这里是本地的IP。也就是说,你也可以给别的主机装Docker,前提是SSH root用户免交互登录或私钥认证
--generic-ssh-user #SSH的用户
--generic-key-key #指定私钥来实现免交互登录
参考:Docker Machine快速安装Docker环境(二)
2.2.2 创建集群
首先使用 Docker Machine 创建一个虚拟机作为 manger 节点
#指定使用generic驱动,将该机器命名为manager1
$docker-machine create -d generic --generic-ip-address=192.168.64.72 --generic-ssh-user=root manager1
$docker-machine create -d generic --generic-ip-address=192.168.64.73 --generic-ssh-user=root worker1
#查看可用的机器
$docker-machine ls
#查看manager1的环境变量
$docker-machine env manager1
#复制最后一行,用本机docker客户端指向manager1的docker(设置一些 Docker 客户端使用的环境变量,从而让本机的 Docker 客户端可以与远程的 Docker 服务器通信)
$eval $(docker-machine env manager1)
#查看当前活跃的机器:*表示目前这台机器已经在使用了
$docker-machine active
#通过ssh到这个节点并验证运行的进程来确认设置信息
$docker-machine ssh manager1 ps aux | grep docker
#本例使用 Docker Machine 来连接虚拟机
#把 manager1 加入集群: --listen-addr 指定监听的 ip 与端口
$docker-machine ssh manager1 docker swarm init --listen-addr 192.168.64.72:2377 --advertise-addr 192.168.64.72
$docker-machine ssh worker1 docker swarm join --token SWMTKN-1-44oi6hca2aej9zf5r6v08yyppysniudl8vjzota23eem9078j0-4hb326sah20vuul4gfbwo5zlj 192.168.64.72:2377
#集群初始化成功,现在我们新建了一个有两个节点的“集群”,现在进入其中一个管理节点查看
$docker-machine ssh manager1 docker node ls
现在每个节点都归属于 Swarm,处在了待机状态。manager1 是leader,worker1 是worker
可以继续添加虚拟机
$docker-machine create -d generic --generic-ip-address=115.159.192.111 --generic-ssh-user=root smoker
$docker-machine ls
$docker-machine env smoker
$docker-machine ssh smoker docker swarm join --token SWMTKN-1-44oi6hca2aej9zf5r6v08yyppysniudl8vjzota23eem9078j0-4hb326sah20vuul4gfbwo5zlj 192.168.64.72:2377
$$docker-machine ssh manager1 docker node ls
至此使用Docker-machine创建虚拟机完毕,添加了三个节点,一个manager,连个worker
2.2.3 建立跨主机网络
#查看网络,可以看到在swarm上默认已有一个名为ingress的overlay 网络, 默认在swarm里使用
$docker-machine ssh manager1 docker network ls
#创建一个新的overlay网络
$docker-machine ssh manager1 docker network create --driver overlay swarm_test
$docker-machine ssh manager1 docker network ls
这样一个跨主机网络就搭建好了,但是现在这个网络只是处于待机状态,下一节在这个网络上部署应用
2.2.4 在跨主机网络上部署应用
首先我们上面创建的节点都是没有镜像的,因此我们要逐一 pull 镜像到节点中
$docker-machine ssh manager1 docker pull nginx
$docker-machine ssh worker1 docker pull nginx
$docker-machine ssh smoker docker pull nginx
上面使用 docker pull 分别在三个个虚拟机节点拉取 nginx镜像。接下来要在三个节点部署一组 Nginx 服务
#部署的服务使用 swarm_test 跨主机网络
$docker-machine ssh manager1 docker service create --replicas 2 --name helloworld --network=swarm_test nginx
#查看服务状态
$docker-machine ssh manager1 docker service ls
#查看 helloworld 服务详情
$docker-machine ssh manager1 docker service ps helloworld
#看到两个实例分别运行在两个节点
#进入两个节点,查看服务状态
$docker-machine ssh manager1 docker ps -a
$docker-machine ssh worker2 docker ps -a
记住上面这两个实例的名称。现在我们来看这两个跨主机的容器是否能互通:
首先使用 Machine 进入 manager1 节点,然后使用 docker exec -i 命令进入 helloworld.1 容器中 ping 运行在 worker2 节点的 helloworld.2 容器
$docker-machine ssh manager1 docker exec -i helloworld.2.f6uumx0l2veyx6xr7sag46cg1 ping
然后使用 Machine 进入 worker2 节点,然后使用 docker exec -i 命令进入 helloworld.2 容器中 ping 运行在 manager1 节点的 helloworld.1 容器
$docker-machine ssh worker2 docker exec -i helloworld.1.uvun0qur61ickqedh5ijzyfk7 ping helloworld.2.f6uumx0l2veyx6xr7sag46cg1
出错:
理论上是可以ping通的,这里假设他两ping通了
此测试结论:两个跨主机的服务集群里面各个容器是可以互相连接的
2.2.5 Swarm 自动服务发现
以上是Swarm 集群的部署方法,现在来搭建一个可访问的 Nginx 集群。体验最新版的 Swarm 所提供的自动服务发现与集群负载功能
#首先删掉上一节我们启动的helloworld服务
$docker-machine ssh manager1 docker service rm helloworld
#然后在新建一个服务,提供端口映射参数,使得外界可以访问这些 Nginx 服务
$docker-machine ssh manager1 docker service create --replicas 2 --name helloworld -p 7080:80 --network=swarm_test nginx
#查看服务运行状态
$docker-machine ssh manager1 docker service ls
不知你有没有发现,虽然我们使用 --replicas 参数的值都是一样的,但是上一节中获取服务状态时,REPLICAS 返回的是 0/2,现在的 REPLICAS 返回的是 2/2
同样使用 docker service ps 查看服务详细状态时(下面输出已经手动调整为更易读的格式),可以看到实例的 CURRENT STATE 中是 Running 状态的,而上一节中的 CURRENT STATE 中全部是处于 Preparing 状态
#查看服务helloworld列表
$docker-machine ssh manager1 docker service ps helloworld
这就涉及到 Swarm 内置的发现机制了,目前 Docker 1.12 中 Swarm 已经内置了服务发现工具,我们不再需要像以前使用 Etcd 或者 Consul 这些工具来配置服务发现。对于一个容器来说如果没有外部通信但又是运行中的状态会被服务发现工具认为是 Preparing 状态,本小节例子中因为映射了端口,因此有了 Running 状态。
2.2.6 Swarm 集群负载
现在我们来看 Swarm 另一个有趣的功能,当我们杀死其中一个节点时,会发生什么。
#首先 kill 掉 worker1 的实例
$docker-machine ssh worker1 docker kill helloworld.1.x5uzksc1ej6xb05zz8y9ttbs5
#查看服务状态
$docker-machine ssh manager1 docker service ps helloworld
可以看到即使我们 kill 掉其中一个实例,Swarm 也会迅速把停止的容器撤下来,同时在节点中启动一个新的实例顶上来。这样服务依旧还是两个实例在运行
2.2.7 scale 命令
添加更多实例可以使用 scale 命令
$docker-machine ssh manager1 docker service scale helloworld=3
想减少实例数量,一样可以使用 scale 命令
$docker-machine ssh manager1 docker service scale helloworld=2
参考
1 Swarm容器编排与Docker原生集群---电子工业出版社
5 Swarm入门
2017-12-11-Boy