docker系列教程之集群搭建

一、Docker Machine
Docker Machine 是一种可以让您在虚拟主机上安装 Docker 的工具,并可以使用 docker-machine 命令来管理主机。

Docker Machine 也可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker。

其实说白了,就是用docker machine来创建多个虚拟机,也就是一台物理虚拟机上,可以创建多个虚拟机,也就是虚拟机中创建虚拟机。 我们这里使用docker machine来创建多个虚拟机的目的是为了后面的集群搭建时,每个节点安装都不同的虚拟主机上, 如果你已经在windows环境搭建多个虚拟机主机的话,就不需要用docker machine了

安装docker-machine

base=https://github.com/docker/machine/releases/download/v0.16.0 &&
  curl -L $base/docker-machine-$(uname -s)-$(uname -m) >/tmp/docker-machine &&
  sudo mv /tmp/docker-machine /usr/local/bin/docker-machine &&
  chmod +x /usr/local/bin/docker-machine

检查是否安装成功

docker-machine version

创建虚拟机主机

docker-machine create -d virtualbox swarm-manager

执行上面命令时会出现两处错误

Error with pre-create check: "VBoxManage not found. Make sure VirtualBox is installed and VBoxManage is in the path"

这是没有安装VirtualBox ,接下来安装VirtualBox

yum -y install wget
wget http://download.virtualbox.org/virtualbox/rpm/rhel/7/x86_64/VirtualBox-5.1-5.1.20_114628_el7-1.x86_64.rpm
yum -y install VirtualBox-5.1-5.1.20_114628_el7-1.x86_64.rpm

安装完成后,再次创建机器,会出现如下错误

Error with pre-create check: "This computer doesn't have VT-X/AMD-v enabled. Enabling it in the BIOS is mandatory"

docker系列教程之集群搭建_第1张图片
二、创建虚拟机

docker-machine create -d virtualbox swarm-manager

如果没有boot2docker.iso镜像文件就会下载,但是下载很慢
在这里插入图片描述

解决如下:
https://github.com/boot2docker/boot2docker/releases/download/v19.03.12/boot2docker.iso 把这个下载地址放到迅雷下载,很快的。下载后放到Linux系统的/root/.docker/machine/cache目录下即可。

如果你使用的都是物理机或虚拟机。上面的操作不需要做

三、Docker Swarm集群

Docker Swarm 和 Docker Compose 一样,都是 Docker 官方容器编排项目,但不同的是,Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,而 Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,对于微服务的部署,显然 Docker Swarm 会更加适合。

从 Docker 1.12.0 版本开始,Docker Swarm 已经包含在 Docker 引擎中(docker swarm),并且已经内置了服务发现工具,我们就不需要像之前一样,再配置 Etcd 或者 Consul 来进行服务发现配置了。

Swarm deamon只是一个调度器(Scheduler)加路由器(router),Swarm自己不运行容器,它只是接受Docker客户端发来的请求,调度适合的节点来运行容器,这就意味着,即使Swarm由于某些原因挂掉了,集群中的节点也会照常运行,放Swarm重新恢复运行之后,他会收集重建集群信息。

四、Docker Swarm 基本结构图
docker系列教程之集群搭建_第2张图片
在结构图可以看出 Docker Client使用Swarm对 集群(Cluster)进行调度使用。

上图可以看出,Swarm是典型的master-slave结构,通过发现服务来选举manager。manager是中心管理节点,各个node上运行agent接受manager的统一管理,集群会自动通过Raft协议分布式选举出manager节点,无需额外的发现服务支持,避免了单点的瓶颈问题,同时也内置了DNS的负载均衡和对外部负载均衡机制的集成支持

五、Swarm的几个关键概念

1.Swarm
集群的管理和编排是使用嵌入docker引擎的SwarmKit,可以在docker初始化时启动swarm模式或者加入已存在的swarm
 
2.Node
一个节点是docker引擎集群的一个实例。您还可以将其视为Docker节点。您可以在单个物理计算机或云服务器上运行一个或多个节点,但生产群集部署通常包括分布在多个物理和云计算机上的Docker节点。
要将应用程序部署到swarm,请将服务定义提交给 管理器节点。管理器节点将称为任务的工作单元分派 给工作节点。
Manager节点还执行维护所需群集状态所需的编排和集群管理功能。Manager节点选择单个领导者来执行编排任务。
工作节点接收并执行从管理器节点分派的任务。默认情况下,管理器节点还将服务作为工作节点运行,但您可以将它们配置为仅运行管理器任务并且是仅管理器节点。代理程序在每个工作程序节点上运行,并报告分配给它的任务。工作节点向管理器节点通知其分配的任务的当前状态,以便管理器可以维持每个工作者的期望状态。
 
3.Service
一个服务是任务的定义,管理机或工作节点上执行。它是群体系统的中心结构,是用户与群体交互的主要根源。创建服务时,你需要指定要使用的容器镜像。
 
4.Task
任务是在docekr容器中执行的命令,Manager节点根据指定数量的任务副本分配任务给worker节点
 
------------------------------------------使用方法-------------------------------------
docker swarm:集群管理,子命令有init, join, leave, update。(docker swarm --help查看帮助)
docker service:服务创建,子命令有create, inspect, update, remove, tasks。(docker service--help查看帮助)
docker node:节点管理,子命令有accept, promote, demote, inspect, update, tasks, ls, rm。(docker node --help查看帮助)
   
node是加入到swarm集群中的一个docker引擎实体,可以在一台物理机上运行多个node,node分为:
manager nodes,也就是管理节点
worker nodes,也就是工作节点
 
1)manager node管理节点:执行集群的管理功能,维护集群的状态,选举一个leader节点去执行调度任务。
2)worker node工作节点:接收和执行任务。参与容器集群负载调度,仅用于承载task。
3)service服务:一个服务是工作节点上执行任务的定义。创建一个服务,指定了容器所使用的镜像和容器运行的命令。
   service是运行在worker nodes上的task的描述,service的描述包括使用哪个docker 镜像,以及在使用该镜像的容器中执行什么命令。
4)task任务:一个任务包含了一个容器及其运行的命令。task是service的执行实体,task启动docker容器并在容器中执行任务。

六、Swarm的调度策略

Swarm在调度(scheduler)节点(leader节点)运行容器的时候,会根据指定的策略来计算最适合运行容器的节点,目前支持的策略有:spread, binpack, random.
1)Random
顾名思义,就是随机选择一个Node来运行容器,一般用作调试用,spread和binpack策略会根据各个节点的可用的CPU, RAM以及正在运
行的容器的数量来计算应该运行容器的节点。
  
2)Spread
在同等条件下,Spread策略会选择运行容器最少的那台节点来运行新的容器,binpack策略会选择运行容器最集中的那台机器来运行新的节点。
使用Spread策略会使得容器会均衡的分布在集群中的各个节点上运行,一旦一个节点挂掉了只会损失少部分的容器。
  
3)Binpack
Binpack策略最大化的避免容器碎片化,就是说binpack策略尽可能的把还未使用的节点留给需要更大空间的容器运行,尽可能的把容器运行在
一个节点上面。

七、Swarm Cluster模式特性

1)批量创建服务
建立容器之前先创建一个overlay的网络,用来保证在不同主机上的容器网络互通的网络模式
   
2)强大的集群的容错性
当容器副本中的其中某一个或某几个节点宕机后,cluster会根据自己的服务注册发现机制,以及之前设定的值--replicas n,
在集群中剩余的空闲节点上,重新拉起容器副本。整个副本迁移的过程无需人工干预,迁移后原本的集群的load balance依旧好使!
不难看出,docker service其实不仅仅是批量启动服务这么简单,而是在集群中定义了一种状态。Cluster会持续检测服务的健康状态
并维护集群的高可用性。
   
3)服务节点的可扩展性
Swarm Cluster不光只是提供了优秀的高可用性,同时也提供了节点弹性扩展或缩减的功能。当容器组想动态扩展时,只需通过scale
参数即可复制出新的副本出来。
   
仔细观察的话,可以发现所有扩展出来的容器副本都run在原先的节点下面,如果有需求想在每台节点上都run一个相同的副本,方法
其实很简单,只需要在命令中将"--replicas n"更换成"--mode=global"即可!
  
复制服务(--replicas n)
将一系列复制任务分发至各节点当中,具体取决于您所需要的设置状态,例如“--replicas 3”。
  
全局服务(--mode=global)
适用于集群内全部可用节点上的服务任务,例如“--mode global”。如果大家在 Swarm 集群中设有 7 台 Docker 节点,则全部节点之上都将存在对应容器。
   
4. 调度机制
所谓的调度其主要功能是cluster的server端去选择在哪个服务器节点上创建并启动一个容器实例的动作。它是由一个装箱算法和过滤器
组合而成。每次通过过滤器(constraint)启动容器的时候,swarm cluster 都会调用调度机制筛选出匹配约束条件的服务器,并在这上面运行容器。
   
------------------Swarm cluster的创建过程包含以下三个步骤----------------------
1)发现Docker集群中的各个节点,收集节点状态、角色信息,并监视节点状态的变化
2)初始化内部调度(scheduler)模块
3)创建并启动API监听服务模块
   
一旦创建好这个cluster,就可以用命令docker service批量对集群内的容器进行操作,非常方便!
   
在启动容器后,docker 会根据当前每个swarm节点的负载判断,在负载最优的节点运行这个task任务,用"docker service ls" 和"docker service ps + taskID"
可以看到任务运行在哪个节点上。容器启动后,有时需要等待一段时间才能完成容器创建。

八、machine创建 集群管理节点(manager)

有两种方式创建machine机器:

  1. 使用virtualbox 创建machine —必须使用VMware workerstation, 可以在一台虚拟机或物理机上创建多个机器,ip动态分配
  2. 使用通用驱动创建machine ----使用VMware workerstation和virtualbox 都可以,但是最好准备多台虚拟机或物理机,因为它创建是要指定ip也就是主机ip,如果创建多台机器他们ip会重复

使用virtualbox 创建machine
如果使用的是虚拟机创建,在创建之前要把cup和内存调大写,否则会出现unexpected EOF错误

docker-machine create -d virtualbox swarm-manager
运行上面命令会报如下错误:
Error with pre-create check: "SSH key does not exist: \"/root/.ssh/id_rsa\""

使用通用驱动创建machine

运行命令:
docker-machine create --driver generic --generic-ip-address=192.168.25.129 --generic-ssh-key=/root/.ssh/id_rsa --generic-ssh-user=root --generic-ssh-port=22 swarm-manager
运行上面命令会报如下错误:
Error with pre-create check: "SSH key does not exist: \"/root/.ssh/id_rsa\""

–generic-ip-address=192.168.25.129:这里的ip是指本机,如果需要为其他远程docker主机安装可以改为其他docker主机ip(这里是本地创建docker-machine)
​ --generic-ssh-key=/root/.ssh/id_rsa:指定私钥路径
​ --generic-ssh-user=root;ssh登录machine的用户
​ --generic-ssh-port=22:ssh登录machine的端口

​ 注意: 如果指定machine的名称(swarm-manager)与远端主机的名称不一致,会使用machine的名称覆盖掉主机的名称。

以上就是创建机器的两种方式

​ 上述两种方式都会报错,是由于docker-machine为本机创建machine时需要进行ssh认证,而本地root账号下没有私钥,创建私钥:

ssh-keygen

会让你输入密码,一路按回车即可

docker系列教程之集群搭建_第3张图片

将生成的公钥发给宿主机,受信任

ssh-copy-id [email protected]

本例我们使用第一种方式virtualbox :
创建管理节点

docker-machine create -d virtualbox swarm-manager

查看管理节点
在这里插入图片描述

备注: 如果你不是使用的docker-machine创建的机器 ,而是使用的物理机或虚拟机,第八条就不需要操作了

九、搭建 swarm 集群

1、初始化 swarm 集群,进行初始化的这台机器,就是集群的管理节点。

docker-machine ssh swarm-manager
docker swarm init --advertise-addr 192.168.99.100  #这里的ip为创建机器时分配的ip
如果报下面错误:
Error response from daemon: This node is already part of a swarm. Use "docker swarm leave" to leave this swarm and join another one.
# 解决方法
docker swarm leave -f
这里的leave就是在集群中删除节点,-f参数强制删除,执行完在重新执行OK
如果报下面错误:
Error response from daemon: must specify a listening address because the address to advertise is not recognized as a system address, and a system's IP address to use could not be uniquely identified
#解决方法:
需要指定监听地址
docker swarm init --advertise-addr 192.168.99.100:2376 --listen-addr 127.0.0.1:2377

--listen-addr 就是监听的地址和端口,我这里选择本机,端口号2377,如果报端口号已被占用,在换一个试试

在这里插入图片描述

以上输出,证明已经初始化成功。需要把以下这行复制出来,在增加工作节点时会用到:

docker swarm join --token SWMTKN-1-2x0guc33dplz1m0x4e0wrfifojsnj32d8zm4ttczip7uphduga-cfknrh4momayz7b3xeuly4l50 192.168.99.100:2376

2、创建 swarm 集群工作节点(worker)

这里直接创建好俩台机器,swarm-worker1 和 swarm-worker2 。
在这里插入图片描述

分别进入两个机器里,指定添加至上一步中创建的集群,这里会用到上一步复制的内容。
在这里插入图片描述

中间遇到的问题:
1. 出现下面错误
Error response from daemon: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection closed
解决方法:
docker swarm init --advertise-addr 192.168.99.100   #执行命令重新初始化管理节点获取新的token

如果还不行开通2376认证端口试试,参考docker开启2376端口CA认证

3、查看集群信息
进入管理节点,执行:docker info 可以查看当前集群的信息。

docker info

docker系列教程之集群搭建_第4张图片

通过画红圈的地方,可以知道当前运行的集群中,有三个节点,其中有一个是管理节点。

查看集群,swarm-manager是leader角色,另外两个是从节点
docker node ls

在这里插入图片描述

十、在Swarm中部署服务(nginx为例)

Docker 1.12版本提供服务的Scaling、health check、滚动升级等功能,并提供了内置的dns、vip机制,实现service的服务发现和负载均衡能力
# 创建网络
docker network create -d overlay nginx_net
#查询网络
docker network ls | grep nginx_net

# 部署服务,就创建了一个具有一个副本(--replicas 1 )的nginx服务,使用镜像nginx
docker service create --replicas 1 --network nginx_net --name my_nginx -p 80:80 nginx

在manager-node节点上使用上面这个覆盖网络创建nginx服务:其中,--replicas 参数指定服务由几个实例组成。注意:不需要提前在节点上下载nginx镜像,这个命令执行后会自动下载这个容器镜像(比如此处创建tomcat容器,就将下面命令中的镜像改为tomcat镜像)。

#查看正在运行服务的列表
docker service ls 

#查询Swarm中服务的信息-pretty 使命令输出格式化为可读的格式,不加 --pretty 可以输出更详细的信息
docker service inspect --pretty my_nginx

#查询到哪个节点正在运行该服务。http://节点ip, 即可访问这个容器应用(如果调度到其他节点,访问也是如此)
docker service ps my_nginx
温馨提示:如果上面命令执行后,上面的 STATE 字段中刚开始的服务状态为 Preparing,需要等一会才能变为 Running 状态,其中最费时间的应该是下载镜像的过程

#登录服务所在的节点,查看服务运行的容器,比如my_nginx服务在swarm-manager节点运行,就登录swarm-manager节点
docker ps

在这里插入图片描述

在Swarm中动态扩展服务(scale),当然,如果只是通过service启动容器,swarm也算不上什么新鲜东西了。Service还提供了复制(类似kubernetes里的副本)功能。可以通过 docker service scale 命令来设置服务中容器的副本数 比如将上面的my_nginx容器动态扩展到4个

docker service scale my_nginx=4

和创建服务一样,增加scale数之后,将会创建新的容器,这些新启动的容器也会经历从准备到运行的过程,过一分钟左右,服务应该就会启动完成,这时候可以再来看一下 nginx 服务中的容器
docker系列教程之集群搭建_第5张图片

模拟宕机node节点
特别需要清楚的一点:如果一个节点宕机了(即该节点就会从swarm集群中被踢出),则Docker应该会将在该节点运行的容器,调度到其他节点,以满足指定数量的副本保持运行状态。

比如将swarm-worker1宕机后或将swarm-worker1的docker服务关闭,那么它上面的task实例就会转移到别的节点上。当swarm-worker1节点恢复后,它转移出去的task实例不会主动转移回来,只能等别的节点出现故障后转移task实例到它的上面

登录swarm-worker1节点,关闭docker服务:systemctl stop docker

登录swarm-manager节点,docker node ls命令查看服务swarm-worker1的docker服务已经停止。
运行命令docker service ps my_nginx查看swarm-worker1上的服务已经被转移到其他节点上

Swarm 动态缩容服务(scale)

#如下,将my_nginx容器变为1个
docker service scale my_nginx=1

#除了上面使用scale进行容器的扩容或缩容之外,还可以使用docker service update 命令。 可对 服务的启动 参数 进行 更新/修改。如下修改成3个副本
docker service update --replicas 3 my_nginx

#docker service update 命令,也可用于直接 升级 镜像等
docker service update --image nginx:new my_nginx
注意IMAGE列 变成了nginx:new

删除所有节点上的所有my_nginx服务

docker service rm my_nginx

Swarm中使用Volume(挂在目录,mount命令)
查看volume的帮助信息

docker volume --help
#创建一个volume
docker volume create --name testvolume
#查看volume
docker volume ls
#查看详情
docker volume inspect testvolume

创建新的服务并挂载testvolume(nginx为例)

docker service create --replicas 3 --mount type=volume,src=testvolume,dst=/zjz --name test_nginx nginx

参数src写成source也可以;dst表示容器内的路径,也可以写成target

#查看服务
docker service ls
docker service ps test_nginx

登录test_nginx所在的节点,现在是在swarm-worker1节点上
docker ps查出容器
进入容器docker exec -it 99be0e7a11f1 /bin/bash
docker系列教程之集群搭建_第6张图片
执行docker volume inspect testvolume 可以看到本地的路径(上面已经执行过了)
就是mnt/sda1/var/lib/docker/volumes/testvolume/_data

cd mnt/sda1/var/lib/docker/volumes/testvolume/_data

会报如下错误,这是因为没有挂载目录的访问权限,可以百度解决下,然后进去就能查看到在容器中创建的文件了
在这里插入图片描述

# 还有一种挂载方式
命令格式:
docker service create --mount type=bind,target=/container_data/,source=/host_data/
其中,参数target表示容器里面的路径,source表示本地硬盘路径
 
# 示例创建并挂载并使用网络
docker service create --replicas 1 --mount type=bind,target=/usr/share/nginx/html/,source=/opt/web/ --network nginx_net --name zjz_nginx -p 8880:80 nginx

十一、多服务Swarm集群部署

通过docker-compose.yml的文件

version: '3'
networks:
    app-network:
services:

 demo: 
   networks:
    - app-network
   build: ./demo
   container_name: demo
   ports:
     - "8099:8099"
   deploy:
      mode: replicated
      replocas: 3
 test: 
   networks:
    - app-network
   build: ./test
   container_name: test
   ports:
     - "8085:8085"
   deploy:
      mode: replicated
      replocas: 3

上班的docker-compose文件中我们创建了app-network网络,并部署两个应用demo和test。 这两个应用的jar已经提前放到了 build: ./test和 build: ./demo目录

执行下面命令创建多个服务

docker stack deploy -c docker-compose.yml deploy_deamon

十二、Docker Swarm 容器网络

负载均衡
负载均衡分为两种:Swarm集群内的service之间的相互访问需要做负载均衡,称为内部负载均衡(Internal LB);从Swarm集群外部访问服务的公开端口,也需要做负载均衡,称外部部负载均衡(Exteral LB or Ingress LB)

Internal LB
内部负载均衡就是集群内部通过DNS访问service时,Swarm默认通过VIP(virtual IP)、iptables、IPVS转发到某个容器

docker系列教程之集群搭建_第7张图片
Exteral LB(Ingress LB)
外部负载均衡和Ingress网络有关。Swarm网络要提供对外访问的服务就需要打开公开端口,并映射到宿主机。Ingress LB就是外部通过公开端口访问集群时做的负载均衡。

docker系列教程之集群搭建_第8张图片
上图是三个节点的Swarm集群,app服务公开了8000端口,并且有两个副;虽然服务只有两个副本,分别在A、B两台主机上,但是访问C主机的8000端口,ingress网络会通过IPVS将请求转到A、B之一的容器中处理,依然可以对外提供服务这就是 routing mesh 的作用。

在Docker版本1.12之后swarm模式原生支持覆盖网络(overlay networks),可以先创建一个覆盖网络,然后启动容器的时候启用这个覆盖网络,
这样只要是这个覆盖网络内的容器,不管在不在同一个宿主机上都能相互通信,即跨主机通信!不同覆盖网络内的容器组之间是相互隔离的(相互ping不通)。
swarm模式的覆盖网络包括以下功能:
1)可以附加多个服务到同一个网络。
2)默认情况下,service discovery为每个swarm服务分配一个虚拟IP地址(vip)和DNS名称,使得在同一个网络中容器之间可以使用服务名称为互相连接。
3)可以配置使用DNS轮循而不使用VIP
4)为了可以使用swarm的覆盖网络,在启用swarm模式之间你需要在swarm节点之间开放以下端口:
5)TCP/UDP端口7946 – 用于容器网络发现
6)UDP端口4789 – 用于容器覆盖网络

创建覆盖网络

docker network create --driver overlay --opt encrypted --subnet 10.10.19.0/24 nginx_net

参数解释:
–opt encrypted 默认情况下swarm中的节点通信是加密的。在不同节点的容器之间,可选的–opt encrypted参数能在它们的vxlan流量启用附加的加密层。
–subnet 命令行参数指定overlay网络使用的子网网段。当不指定一个子网时,swarm管理器自动选择一个子网并分配给网络。

docker系列教程之集群搭建_第9张图片

由上可知,Swarm当中拥有2套覆盖网络。其中"nginx_net"网络正是我们在部署容器时所创建的成果。而"ingress"覆盖网络则为默认提供。
Swarm 管理节点会利用 ingress 负载均衡以将服务公布至集群之外。
在将服务连接到这个创建的网络之前,网络覆盖到manager节点。上面输出的SCOPE为 swarm 表示将服务部署到Swarm时可以使用此网络。
在将服务连接到这个网络后,Swarm只将该网络扩展到特定的worker节点,这个worker节点被swarm调度器分配了运行服务的任务。
在那些没有运行该服务任务的worker节点上,网络并不扩展到该节点。

创建应用并连接到nginx_net网络, 上面我们在创建集群服务时也讲过

docker service create --replicas 5 --network nginx_net --name my-test -p 80:80 nginx

查看虚拟ip

docker service inspect --format='{{json .Endpoint.VirtualIPs}}' my_nginx

[{"NetworkID":"mpqn34908ds3icvfkd1ddsxh9","Addr":"10.0.0.7/24"},{"NetworkID":"yqjzysxckvhujo30yprrz2pv5","Addr":"10.0.1.5/24"}]

由上结果可知,10.0.1.5其实就是swarm集群内部的vip

进入容器,通过ip可以ping通,在同一个覆盖网络下的其他容器

swarm模式的服务发现

默认情况下,当创建了一个服务并连接到某个网络后,swarm会为该服务分配一个VIP。此VIP根据服务名映射到DNS。在网络上的容器共享该服务的DNS映射,
所以网络上的任意容器可以通过服务名访问服务。

在同一overlay网络中,不用通过端口映射来使某个服务可以被其它服务访问。Swarm内部的负载均衡器自动将请求发送到服务的VIP上,然后分发到所有的
active的task上。

#进入容器
docker exec -ti 容器名 /bin/bash
#用来查找my-test服务的dns
nslookup my-test
#使用特殊查询 查询DNS,来找到my-test服务的所有容器的IP地址
nslookup tasks.my-test
#通过wget来访问my-test服务中运行的nginx网页服务器
wget -O- my-test

需要注意的是:一定要确认VIP的连通性
通常Docker官方推荐使用dig,nslookup或其它DNS查询工具来查询通过DNS对服务名的访问。因为VIP是逻辑IP,ping并不是确认VIP连通性的正确的工具。

Swarm的负载均衡器自动将HTTP请求路由到VIP上,然后到一个active的task容器上。它根据round-robin选择算法将后续的请求分发到另一个active的task上。

你可能感兴趣的:(容器技术,docker)