Docker-Swarm集群管理

2,221 阅读19分钟

伸手摘星,即使一无所获,亦不致满手污泥

请关注公众号:星河之码

一、Docker Swarm介绍

Docker Swarm是Docker的集群管理工具,它提供了标准的Docker API,所有任何已经与Docker守护程序通信的工具都可以使用Swarm轻松地扩展到多个主机。支持的工具包括Dokku、Docker Compose、Docker Machine和Jenkins等。

compose、machine 和 swarm 是docker 原生提供的三大编排工具,简称docker三剑客。其官网地址

https://docs.docker.com/engine/swarm/
  • Docker Swarm 和 Docker Compose

    Docker Swarm 和 Docker Compose都是 Docker 官方容器编排项目

    • Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,可以将组成某个应该的多个docker容器编排在一起,同时管理

    • Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口(docker stack)统一管理这些Docker主机上的各种Docker资源

  • docker stack

    • docker stack 是构成特定环境中的 service 集合, 它是自动部署多个相互关联的服务的简便方法,而无需单独定 义每个服务。
    • stack file 是一种 yaml 格式的文件,类似于 docker-compose.yml 文件,它定义了一个或多个服务,并 定义了服务的环境变量、部署标签、容器数量以及相关的环境特定配置等。

Docker Swarm就是用来管理Docker集群的,但是现在基本上使用的很少,一般都是用的K8S,学习K8S之前可以先学习一个Docker Swarm,将其作为一个容器编排的一个学习基础,了解一下即可

二、Docker Swarm运行原理

Swarm集群由多个运行在swarm mode的docker主机组成,docker主机分为管理节点(manager)和工作节点(work node)两种类型

  • 管理节点(manager):负责整个集群的管理工作包括集群配置、服务管理,服务的创建和调度等

  • 工作节点(work node):负责运行相应的服务来执行任务(运行容器服务)

    manager节点也可以运行的容器服务,但是一般不这么做,只是让它管理work node

Swarm集群的优点:

  • 在线修改Service的配置,包括networks和volumes,不需要重启docker服务
  • 可以将其它standalone模式的docker主机加入到Swarm集群

Standalone模式简单点说就是 manager 和 work 的一种管理关系模式

在Docker Swarm中有几个基本概念:nodes、Service、tasks、load balancing。需要简单了解一下

2.1 nodes

Node是加入到Swarm集群中的Docker实例,即是一个docker节点,包含上面说的【管理节点(manager)和工作节点(work node)】

  • 在部署应用到Swarm集群的时候,会向管理节点提交service定义,管理节点会将这些这些work也就是tasks分发到work节点中。
  • Work节点接收并执行管理节点分配的任务,work节点也会将当前tasks的状态通知到管理节点以维护节点的状态信息。

  • 管理节点(manager node)

    Manager节点主要通过raft算法实现整个集群和运行的service的内部状态维护,Docker官方建议一个集群最好使用基数manager节点数(最大使用7个manager节点)保证可用性 ,Manager节点主要工作是完成以下tasks:

    • 维护cluster state
    • scheduling服务
    • service swarm mode集群服务
  • 工作节点(work node)

    Work节点是容器实际运行的实例节点,在默认情况下manager节点也是work节点,而且在在Swarm集群中必须存在manager节点

    manager节点状态、信息的同步根据Raft consensus group(Raft一致性算法)的网络进行通信同步的,而worker之间的通信依靠的是Gossip network通信协议实现的。

  • 管理节点与工作节点的切换

    在多节点的Swarm集群中,节点有两种模式:【Active模式,Drain模式】。

    Swarm调度不会将任务分配到Drain模式,只会在Active模式的节点上分配任务。因此可以将manager节点设置为Drain模式(避免调度任务运行在manager节点,manager指做管理)

    docker node promote
    

    通过以上命令可以修改节点模式,将worker节点变为manager节点,也可以将manager节点转换为worker节点。

2.1 Service与tasks

Service是manage和work节点上执行的task的定义,创建service的时候可以指定使用哪个container image以及执行的命令。

当Service部署到Swarm集群的时候,swarm管理节点会将service为标准(container image以及执行的命令),然后将service调度到集群的节点上,以一个或多个tasks执行,这些nodes上运行的tasks之间是相互独立的。

  • 在replicated service模式下,swarm管理节点会根据desired state中设置的scale分发replica tasks
  • 在globalservice模式,swarm集群会向每个可用的节点运行tasks

如上service中有三个replicas tasks,每个实例是Swarm集群中的一个task。

Task是Swarm集群中调度的最小单元,当创建或更新service时候给定了desired state,集群会调度tasks来实现这种理想状态

  • Task是一种单向机制,它整个周期过程中会完成一系列的状态(assigned、prepared和running等),tasks运行失败集群会remove这个tasks并创建新的tasks来替代。

2.1 load balancing

负载均衡:Swarm集群使用ingress loading balancing提供集群服务,Swarm集群会自动为service分配PublishedPort,默认使用30000-32767范围

三、Docker-swarm安装部署

3.1 准备工作

  • 官方地址

    https://docs.docker.com/engine/swarm/
    
  • 添加私服仓库地址

    由于官方镜像下载比较慢,由于网络原因可能拉取不下来,而集群的每个节点都需要安装镜像,所以使用私有仓库会快很多,当然也可以不使用私有仓库,直接自己下载上传。

    #编辑配置文件
    vi /etc/docker/daemon.json
    #增加仓库配置信息
    # 在daemon.json中添加以下 key,保存退出。此步用于让 docker 信任私有仓库地址
    {"insecure-registries":["192.168.242.130:5000"]} 
    
    
    #重新加载docker配置
    systemctl daemon-reload
    #重启docker
    systemctl restart docker
    

3.2 docker-swarm安装

这里模拟安装集群,以三个节点搭建集群在加上一个Harbor节点,节点信息如下

节点Ip说明
manager-01192.168.242.131swarm-manager 节点
work-01192.168.242.132swarm-work节点
work-02192.168.242.133swarm-work节点
harbor192.168.242.130harbor 私服

安装上述配置,克隆出相应的虚拟机,其中harbor之前已经存在,这里用之前的,所以一共克隆出三个服务器

  • 查看网络情况

    docker network ls
    

  • 初始化manager管理节点

    • 语法

      docker swarm init 
      
    • 参数说明

      这个命令需要指定两个参数--advertise-addr 与--listen-addr

      • --advertise-addr:指定其他节点连接manager时的地址
      • --listen-addr:监控swarm集群manager的IP和端口

    初始化manager管理节点完整命令如下

    #这里使用192.168.242.131这台主机作为manager 所以以下命令在192.168.242.131上执行 端口默认是2377
    docker swarm init --advertise-addr 192.168.242.131:2377 --listen-addr 192.168.242.131:2377
    

    执行上面命令后,就会初始化swarm集群,并且会告诉我们如何增加wrok 节点和manager节点

    • 再次查看网络情况

      #集群初始化后会新增集群网络
      docker network ls
      

  • 查看节点

    docker node ls
    

  • 新加一个work节点

    通过上面初始化manager返回的命令,给集群加入新的节点,只需要在对应的主机上执行该命令即可

    docker swarm join --token SWMTKN-1-55wujoaco7zp7kdvot57wu15drul4m3svoifnitz69r6jv2xyj-5o009d6f4oxlnahfwfzke5ukj 192.168.242.131:2377
    

    我在192.168.242.132这台主机上执行上述命令,将其加入到集群中

    这个命令本质上就是manager初始化的时候返回了一个token,其他主机通过这个token加入集群,并且token只有24小时。如果失效,则需要重新获取

    • 重新获取token

      #获取一个worker加入集群的token
      docker swarm join-token worker
      

  • 查看节点

    docker node ls
    

  • 新加一个manager节点

    一个集群要有多个manager节点,上面加入了work节点,接下来在集群中加入一个manager节点,加入方式一样的,先获取manager的token

    • 获取manager节点的token

      #获取一个manager加入集群的token  ,这个命令要在之前的那个manager 192.168.242.131 上执行
      docker swarm join-token manager
      

    • 加入集群

      这里就用 192.168.242.133 这个主机作为一个manager加入集群

3.3 swarm节点说明

  • manager与work的权限

    swarm集群中,只有manager节点可以执行swarm命令(比如docker node ls),work节点会报错,因为只有manager节点才可以管理集群,执行集群相关的命令

    work 节点只是不能执行swarm的集群命令,但是docker本身的命令是可以执行的,比如docker ps等

  • 查看节点信息

    可以分别在manager和node中查看节点的swarm信息,对比差异

    docker info
    

  • 节点可用性与状态说明

    在使用docker node ls 命令查看集群的节点信息的时候,有两列需要注意一下:AVAILABILITY,MANAGER STATUS

    • AVAILABILITY

      决定当前节点可用性,是否用于运容器,它有三个值:

      • Active:调度程序可以将任务分配给当前节点。
      • Pause:调度程序不会将新任务分配给当前节点,但现有任务仍在运行。
      • Drain:调度程序不会向当前节点分配新任务。调度程序关闭所有现有任务并在可用节点上重新调度这些任务。

      改变节点的可用性(availability)

      docker node update --availability drain 节点Id/名称
      
    • MANAGER STATUS

      表示manger节点的状态,work节点为空,它也有三个状态值

      • Leader:该节点是集群管理和编排决策的主要管理器节点。
      • Reachable:该节点是管理者节点正在参与Raft选举。如果Leader节点不可用,则该节点有资格被选为新领导者。
      • Unavailable:该节点属于不能与其他manager通信的manager。如果manager节点不可用,可以将它加入群集,或者将工作器节点升级为管理器

3.4 集群节点管理

  • 节点权限提升/降低

    节点manager和work两种,他们的权限不一样,我们可以手动的对节点权限提升/降低,也是将manager降级为work,将work升级为manager节点。升级降级的命令都要在manager节点执行。

    • 将work升级为manager节点

      #将worker节点提升为manager节点,在manager节点执行如下命令:
      docker node promote 节点名称|节点ID
      

      比如我将132 节点升级为manager节点

    • 将manager降级为work

      将manager节点降低为worker节点,在manager节点执行如下命令:
      docker node demote 节点名称|节点ID
      docker node ls
      

      将刚刚升级的132 节点重新降级为worker节点

  • work脱离集群

    前面演示了怎么给集群中加入节点,现在来看看将节点脱离集群

    #在要脱离集群的节点上使用一下命令, 主动离开集群,让节点处于down状态,才能删除
    docker swarm leave
    #指向完后,等一会在manager节点使用命令:docker node ls  就会发现该节点已经脱离集群管理
    

    这里我将132节点脱离集群

  • 删除脱离集群的节点

    上述节点脱离集群后,才能删除节点,删除节点使用如下命令

    docker node rm 节点名称|节点ID
    

  • manager脱离集群

    manager节点不能脱离集群,使用docker swarm leave会报错

    manager节点不能脱离集群,只能强制退出,manager退出后意味着整个swarm 不复存在。

    #manager节点强制退出
    docker swarm leave --force
    

3.5 Docker-swarm命令汇总

  • swarm命令汇总

    命令描述
    docker swarm init初始化一个 swarm 群集
    docker swarm join加入群集作为节点或管理器
    docker swarm join-token管理用于加入群集的令牌
    docker swarm leave离开 swarm 群集
    docker swarm unlock解锁 swarm 群集
    docker swarm unlock-key管理解锁钥匙
    docker swarm update更新 swarm 群集
  • node命令汇总

    命令描述
    docker node demote从 swarm 群集管理器中降级一个或多个节点
    docker node promote将一个或多个节点推入到群集管理器中(也就是升级节点)
    docker node inspect显示一个或多个节点的详细信息
    docker node ls列出 swarm 群集中的节点
    docker node ps列出在一个或多个节点上运行的任务,默认为当前节点
    docker node rm从 swarm 群集删除一个或多个节点
    docker node update更新一个节点

四、图形界面

上述安装过程是通过命令行的方式安装docker-swarm,docker-swarm也提供了一个图形界面来操作,接下来就来安装一下docker-swarm的图形界面。

docker-swarm的图形界面需要安装在manager节点上,不然无法操作节点

#docker官网地址
https://hub.docker.com/r/dockersamples/visualizer
  • 拉取镜像

    docker pull dockersamples/visualizer:latest
    
  • 备份镜像

    备份镜像有两种方式:私服和tar包。

    • tar包

      镜像拉取下来之后,可以把它打成一个tar,保存起来,后面使用的时候直接还原即可,就不用下载了

      #打成一个tar 包
      docker save dockersamples/visualizer:latest -o dockersamples.visualizer.tar
      #需要用的时候还原成镜像
      docker load -i dockersamples.visualizer.tar
      
    • 私服

      除了打成tar 存在本地之外,还可以将镜像上传私服,以后在私服拉取

      # 1、标记镜像打一个tag
      docker tag dockersamples/visualizer:latest 192.168.242.130:5000/edwinedu/dockersamples/visualizer:latest
      
      # 2、上传标记的镜像  上传之前要先登录  docker login -u admin -p Harbor12345 192.168.242.130:5000
      docker push 192.168.242.130:5000/edwinedu/dockersamples/visualizer:latest
      

  • 运行镜像

    # /var/run/docker.sock 是必须要的挂载目录  HOST是指定Ip,需要是manager节点的Ip
    docker run -itd --name visualizer -p 8099:8080 -e HOST=192.168.198.131 -e PORT=8080 -v /var/run/docker.sock:/var/run/docker.sock 192.168.242.130:5000/edwinedu/dockersamples/visualizer:latest
    

  • 访问图形界面

    http://192.168.242.131:8099/
    

五、Docker-service

docker-service 是指一组任务的集合,服务定义了任务的属性,比如任务的个数、服务策略、镜像的版本号等,服务有两种模式:

  • replicated services:按照一定规则在各个工作节点上运行指定个数的任务
  • global services:每个工作节点上运行一个任务

接下来以Nginx为例,分别在几个节点上部署Nginx任务

5.1 Nginx基础镜像准备

  • 拉取Nginx镜像

    docker pull nginx:1.18.0-alpine
    
  • 备份镜像

    由于要在每个节点都安装Nginx,所以需要在每个节点都下载镜像,当然可以使用私服下载,但是这里我不使用私服,练习一个scp命令

    #打成一个tar 包
    mkdir -p /data/nginx
    docker save nginx:1.18.0-alpine -o /data/nginx/nginx:1.18.0.tar
    
  • 传输镜像

    将nginx镜像使用scp 命令传输到192.168.242.132,192.168.242.132两个节点中

    #执行下面命令之前,要确保132 133 两个节点有指定的目录 /data/nginx  
    #注意nginx\:1.18.0.tar 中间有一个反斜杠
    scp /data/nginx/nginx\:1.18.0.tar root@192.168.242.132:/data/nginx
    scp /data/nginx/nginx\:1.18.0.tar root@192.168.242.133:/data/nginx
    

  • 解压nginx

    分别在所有节点中解压nginx (192.168.242.132,192.168.242.132两个节点)

    cd /data/nginx
    docker load -i nginx:1.18.0.tar
    

5.2 部署Nginx

  • 创建nginx网络

    在manager节点中创建overlay网络

    docker network create -d overlay nginx-net
    

  • 部署Nginx

    在集群中创建7个Nginx服务,在manager节点中执行,使用【docker service create】命令

    # --network nginx-net 使用刚刚创建的网络
    # replicas 7 代表 7个副本服务
    docker service create --name nginx --network nginx-net -p 80:80 --replicas 7 nginx:1.18.0-alpine
    
    • 界面查看

    • manager节点也可以查看

      docker service ls
      

  • 访问Nginx

    #三台主机都可以访问
    http://192.168.242.131/80
    http://192.168.242.132/80
    http://192.168.242.133/80
    

  • 剔除manager中非服务

    前面说manager节点只用于管理集群,一般不部署服务,而在上面图形界面中显示,manager中有三个服务,如果要剔除,可以执行以下命令

    docker node update --availability drain 节点Id|名称
    

  • 服务的缩容与扩容

    目前是在两个work中部署了7个nginx,如果要扩容与缩容,只需要修改service的数量就可以无感扩容与缩容,执行一下命令

    #将nginx服务从七个减到5
    docker service scale nginx=5
    

5.3 升级Nginx

在我们日常开发中,版本迭代是非常常见的,可能一周、一个月就迭代一个版本,那么版本迭代升级应该怎么做呢,接下来我们将nginx从1.18升级到1.19。

  • 查看nginx版本

    查看nginx版本可以通过容器查看,也可以通过界面查看

    #通过容器查看版本,先进入容器中
    docker exec -it 503fe639bb89 sh
    nginx -v 
    #退出容器
    exit
    

  • 准备nginx:1.19的镜像

    跟上面1.18的镜像一样,先在manager节点上拉取镜像,然后scp到132 133两台主机上,生产环境我们可以使用私服拉取镜像,不需要打包,这里只是练习scp命令

    #拉取nginx:1.19.3-alpine镜像
    docker pull nginx:1.19.3-alpine
    
    #打成一个tar 包
    mkdir -p /data/nginx
    docker save nginx:1.19.3-alpine -o /data/nginx/nginx:1.19.3.tar
    
    #执行下面命令之前,要确保132 133 两个节点有指定的目录 /data/nginx  
    #注意nginx\:1.18.0.tar 中间有一个反斜杠
    scp /data/nginx/nginx\:1.19.3.tar root@192.168.242.132:/data/nginx
    scp /data/nginx/nginx\:1.19.3.tar root@192.168.242.133:/data/nginx
    
    #分别在132  133 主机上执行解压1.19.3.tar
    cd /data/nginx
    docker load -i nginx:1.19.3.tar
    
  • 升级Nginx

    在manager节点执行以下命令,将nginx从1.18.0-alpine升级到1.19.3-alpine

    docker service update --image nginx:1.19.3-alpine nginx
    

  • 添加一个对外端口

    #将8090 也映射到容器的80端口
    docker service update --publish-add 8090:80 nginx
    

5.4 删除Nginx服务

  • 删除service

    docker service rm nginx
    
  • 删除之前创建的nginx-net

    docker network rm nginx-net
    

5.5 Docker-service命令汇总

命令描述
docker service create创建服务
docker service inspect显示一个或多个服务的详细信息
docker service logs获取服务的日志
docker service ls列出服务
docker service rm删除一个或多个服务
docker service scale设置服务的实例数量
docker service update更新服务
docker service rollback恢复服务至update之前的配置

六、Docker-stack

6.1 Docker-stack的使用

Stack是一组Service,和docker-compose类似,它也可以通过yml的将一组service放在一起操作,docker stack命令可以方便地操作一个Stack,而不用一个个地操作Service

默认情况下,一个Stack共用一个Network,相互可访问,与其它Stack网络隔绝

下面还是以上面的nginx集群为例,通过docker stack 来构建集群

  • 编写docker-stack.yml文件

    docker stack 文件的语法基本与docker-compose类似,

    #版本写高一点,不支持 1 2
    version: '3'
    services:
      edwin-nginx:
        image: nginx:1.19.3-alpine
        container_name: edwin-nginx
        # 指定一个网络
        networks:
          - edwin-net
        restart: always
        ports:
          - 80:80
        deploy:
          replicas: 7
    # 创建nginx网络 networks中也可以不指定driver:overlay,因为docker swarm默认网络类型是overlay。
    networks:
      edwin-net:
        driver: overlay
    
  • 上传docker-stack.yml

    将docker-stack.yml上传到manager节点的/data/nginx目录下
    
  • 启动镜像

    在manager节点中创建docker-stack.yml文件。执行如下命令:

    #nginx-stack 是stack的名字
    docker stack deploy nginx-stack --compose-file=docker-stack.yml 
    #或者是
    docker stack deploy nginx-stack -c docker-stack.yml
    

  • 查看stack服务

    docker stack services nginx-stack
    
  • 查看运行的节点

    查看7个nginx-stack容器分别运行在哪个节点中,可以通过以下命令

    # 查看service的服务名为:nginx-stack_edwin-nginx
    docker service ls
    #查看7个nginx-stack容器分别运行在哪个节点中
    docker service ps nginx-stack_edwin-nginx
    
    • 查看的前提是我们要修改各个主机的名字,不然都会显示localhost.localdomain

    • 修改主机名字

      # 第一步 在各个主机执行  docker-swarm-work-02 为当前主机要设置的主机名
      hostnamectl set-hostname docker-swarm-manager-01
      #第二步
      vi /etc/hosts
      # 将其中的 localhost.localdomain 替换成 docker-swarm-work-02
      127.0.0.1   localhost docker-swarm-work-02 localhost4 localhost4.localdomain4
      ::1         localhost docker-swarm-work-02 localhost6 localhost6.localdomain6
      #第三步 重启服务器
      reboot
      #第四步 查看hostname
      hostname
      

    • 分别按照上述步骤修改主机名字后,再次查看查看7个nginx-stack容器分别运行在哪个节点中,结果如下

  • 删除stack服务

    docker stack rm nginx-stack
    

6.2 docker-stack命令汇总

命令描述
docker stack deploy部署新的stack或更新现有stack
docker stack ls列出现有stack
docker stack ps列出stack中的任务
docker stack rm删除一个或多个stack
docker stack services列出stack中的服务

6.2 Docker Stack和Docker Compose区别

  • Docker stack没有构建指令,无法使用stack命令构建新镜像,需要镜像是预先准备镜像。 docker-compose可以直接构建镜像,所以docker-compose更适合于开发场景;
  • Docker Compose是Python写的,需要安装,Docker Stack是swarm mode的一部分,包含在Docker引擎中
  • Docker stack 不支持version版本为3以下的yml
  • Docker stack 的功能基本上包含了docker compose。

七、Docker-Task

Task是 Swarm 集群中的最小的调度单位,任务包含一个Docker容器和在容器内运行的命令,如果某一个任务奔溃,那么协调器将创建一个新的副本任务,该任务将生成一个新的容器。

Task调度主要分为Manager节点的任务分配和Worker节点的任务执行两部分

  • Manager节点的任务分配
    • 通过 Docker Engine Client 在manage节点使用命令 docker service create 提交 Service 定义
    • Manager节点根据定义创建相应的 Task,并分配IP地址
    • 将Task分发到对应的节点上
    • 节点进行相应的初始化使得它可以执行Task
  • Worker节点的任务执行
    • 连接Manager节点的分配器检查该Task相关定义的信息
    • 验证通过以后在 Worker 节点上执行Task

Task 的执行是一种单向机制,它会按顺序的依次经历 assigned, prepared 和 running 等执行状态,如果Task执行失败了,Manager的编排器会直接将该 Task 以及它的 Container 给删除掉,然后在其它节点上另外创建并执行该 Task