Docker swarm 简介

Docker swarm 集群,Docker swarm是docker官方提供的一种集群方式,用于小量微服务部署还算不错,比庞大的k8s体系更轻量。

节点

运行 Docker 的主机可以主动初始化一个 Swarm 集群或者加入一个已存在的 Swarm 集群,这样这个运行 Docker 的主机就成为一个 Swarm 集群的节点 (node) 。

节点分为管理 (manager) 节点和工作 (worker) 节点。

管理节点用于 Swarm 集群的管理,docker swarm 命令基本只能在管理节点执行(节点退出集群命令 docker swarm leave 可以在工作节点执行)。一个 Swarm 集群可以有多个管理节点,但只有一个管理节点可以成为 leader,leader 通过 raft 协议实现。通常,第一个启用docker swarm的节点将成为leader,后来加入的都是follower。当前的leader如果挂掉,剩余的节点将重新选举出一个新的leader。每一个manager都有一个完整的当前集群状态的副本,可以保证manager的高可用。

工作节点是任务执行节点,管理节点将服务 (service) 下发至工作节点执行。管理节点默认也作为工作节点。你也可以通过配置让服务只运行在管理节点。worker节点之间,通过control plane进行通信,这种通信使用gossip协议,并且是异步的。

Docker 官网的这张图片形象的展示了集群中管理节点与工作节点的关系:
docker swarm结构图
docker swarm结构图

服务和任务

任务 (Task)是 Swarm 中的最小的调度单位,目前来说就是一个单一的容器。

服务 (Services) 是指一组任务的集合,服务定义了任务的属性。服务有两种模式:

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

global services 每个工作节点上运行一个任务

两种模式通过 docker service create 的 --mode 参数指定。

Docker 官网的这张图片形象的展示了容器、任务、服务的关系
任务下发结构图
任务下发结构图
网络模式
在Swarm集群中,由于在容器上层又增加了一个service概念,因此对容器的访问更改成了对service的访问,然后再由一个service对应多个容器。那么一个service可能会包含多个容器副本,而这些容器副本多数情况下是运行在不同的主机中,为了实现service到具体容器副本的转发,在网络模式上与之前的单机的容器网络也将有

所不同
层次结构图
层次结构图

services

swarm service是一个抽象的概念,它只是一个对运行在swarm集群上的应用服务,所期望状态的描述。它就像一个描述了下面物品的清单列表一样:
  •   服务名称
  •   使用哪个镜像来创建容器
  •   要运行多少个副本
  •   服务的容器要连接到哪个网络上
  •   应该映射哪些端口

task

在Docker Swarm中,task是一个部署的最小单元,task与容器是一对一的关系。

stack

stack是描述一系列相关services的集合。我们通过在一个YAML文件中来定义一个stack。


由于一个service会包含多个容器副本,多个副本可以看成一个service整体,它们通常只干一类相同的事情。而稍复杂一点的情况是,一个service可能还需要依赖其他service的能力才能完成任务,那么这就涉及从一个service到另一个service的调用。那么因此在swarm中最常见的2种网络访问是:
 
  1. 外部至swarm内部的service的调用
  2. swarm内部,service至service的调用
 

网络调用


       Service到Service的调用,在swarm中将使用overlay网络解决该问题,overlay是一种覆盖多个主机的虚拟网络,它是利用路由转发策略将对虚拟网络中ip的请求转发至具体容器IP上来完成通信。

       而在swarm中不紧如此,还将使用Docker内部的DNS为服务名进行DNS解析,这意味着你可以在swarm集群内部使用服务名称来访问对应的service。

       在swarm集群中一个service可被其他容器应用调用,该调用可以基于服务名的DNS记录,如果一个service分配的vip,那么使用服务名调用DNS将解析为vip,vip在对应具体的容器副本IP,而如果使用dnsrr模式(轮询),则使用服务名调用时会直接返回一个具体的容器副本ip。

       外部到service的调用,在swarm中仍然采用端口映射方式,使用宿主机端口映射到overlay网络分配的容器副本IP,而这种映射仍然基于一种多副本间的轮询。
即使宿主机中并没有实际运行对应的容器副本,那么该主机仍然会使用本地端口,转发请求至其他主机上的容器副本

       在swarm初始化过程中,会创建一个默认的overlay网络名为ingress,当然也支持用户自定义自己的overlay网络。要让service使用自定义的网络,那么在创建service时,指定需要使用的网络名称即可。

       在Swarm初始化完成后,默认会创建一个网桥docker_gwbridge,和一个veth设备,而在docker中对应的会出现两个网络,一个名为ingress的overlay网络,一个为docker_gwbridge桥接网络。不仅如此还会创建两个默认network namespace,这两个网络空间的名称为ingress_sbox和另一个ingress,数据包需要进入这两个网络空间中进行一些处理,然后才到达容器的网络空间中。

       在Swarm集群中配置使用overlay网络的服务,首先overlay网络会拥有独立的网段,如10.0.0.0/24。那么默认情况下会从该网段中为服务分配的一个IP,该IP是一个虚拟IP,docker使用IPVS对该虚拟IP进行负载,负载至具体的容器IP上,该IP同样来自overlay网络段。

       而容器也会拥有2个veth对,一个用于连接容器至docker_gwbridge,另一个用于连接容器至ingress网络空间;因此在容器的网络空间中会出现2个veth接口,分别拥有不同的IP。

 

Docker swarm 集群环境安装部署

 
  • 主机1(manager|192.168.79.129),
  • 主机2(worker|192.168.79.130),
  • 主机3(worker|192.168.79.133)

主机1初始化为manager

sudo docker swarm init

初始化命令

init 命令更多参数,参考 docker swarm init | Docker Documentation
Name, shorthand Default Description
--advertise-addr   Advertised address (format: <ip|interface>[:port])
--autolock   Enable manager autolocking (requiring an unlock key to start a stopped manager)
--availability active Availability of the node ("active"|"pause"|"drain")
--cert-expiry 2160h0m0s Validity period for node certificates (ns|us|ms|s|m|h)
--data-path-addr   Address or interface to use for data path traffic (format: <ip|interface>)
--data-path-port   API 1.40+
Port number to use for data path traffic (1024 - 49151). If no value is set or is set to 0, the default port (4789) is used.
--default-addr-pool   API 1.40+
default address pool in CIDR format
--default-addr-pool-mask-length 24 API 1.40+
default address pool subnet mask length
--dispatcher-heartbeat 5s Dispatcher heartbeat period (ns|us|ms|s|m|h)
--external-ca   Specifications of one or more certificate signing endpoints
--force-new-cluster   Force create a new cluster from current state
--listen-addr 0.0.0.0:2377 Listen address (format: <ip|interface>[:port])
--max-snapshots   Number of additional Raft snapshots to retain
--snapshot-interval 10000 Number of log entries between Raft snapshots
--task-history-limit 5 Task history retention limit
 

主机2加入到主机1

加入命令:
sudo docker swarm join --token SWMTKN-1-3daa7g97rlpms4aon7lwsnggdsbj24hh6ll9xx1tpxcbnmrh2p-9b7varm8ukgzrkiuaicbg93k6 192.168.79.129:2377
执行结果:
主机2作为worker加入主机1
主机2作为worker加入主机1

主机3加入到主机1

命令与主机2 一致
主机3作为worker加入主机1
主机3作为worker加入主机1

提示:
主机2 / 主机 3 不需要执行init,直接加入即可

查看docker节点信息


在manager节点,输入命令查看:
sudo docker node ls
节点信息
节点信息
从中执行结果可以看到,一共有三个节点每个节点的docker版本信息,其中一个是Leader节点
 
sudo docker info
info命令
manager节点info命令
通过info命令可以查看当前节点(manager)的swarm详细信息
worker节点docker info信息
worker节点docker info信息

提示:
默认情况下manager同时也是worker,会承担工作发布容器任务。如果不想让manger节点执行任务,则可以在manager节点执行下面命令:
 

sudo docker node update --availability drain manager
drain参数的意思是manager节点不再接受新的task,如果节点上已经有task在运行,则停止掉并调度到其它worker节点上去:
 
 

最好只设置一个为管理节点,如果有两个以上管理节点,会因为开机的先后顺序,搞得leader来回跳,服务命令又只能在管理节点运行

docker service 适合启动单个服务,对于多服务部署和管理有些无能为力,可以使用docker stack来管理操作


至此,docker swarm集群已经搭建好并就绪工作了。

Docker Swarm 部署任务

部署nginx案例

manager 节点执行命令
sudo docker service create --replicas 3 -p 80:80 --name nginx nginx:1.13-alpine
任务发布
nginx部署任务发布

查看当前swarm运行的服务

sudo docker service ls
查看当前集群运行的服务
查看当前集群运行的服务

查看某个服务的详情

sudo docker service ps nginx

sudo docker service ps (服务名称)

查看运行服务详情
查看运行服务详情

集群运行的服务日志查看

##查看服务日志
sudo docker service logs nginx
##实时观察日志 
sudo docker service logs -f nginx 


集群服务扩容

sudo docker service scale nginx=5
服务扩容执行
服务扩容执行
 
扩容后的运行情况
扩容后的运行情况

从运行时间可以看到,扩容的时候并不会影响正在运行的

集群服务缩容

有些时候服务并不需要那么多节点,需要收缩,如下:服务收索

服务收缩与扩容命令一致,只需要修改后面的任务数量即可。

集群服务删除

服务删除
服务删除

使用Docker stack 部署服务

Docker stack 简介

       Docker在进行多服务部署和管理时通常会使用Docker Stack来解决大规模部署管理问题,Docker引擎在1.12 版本集成了Docker Swarm, 内置新的容器编排工具docker stack,通过提供期望状态、滚动升级、简单易用、扩缩容、健康检查等特性简化了应用的管理,这些功能都封装在一个完美的声明式模型当中。

compose配置文件

如果你之前单机用过docker-compose这个组件,则会非常熟悉,与之部分配置一致。

配置案例文件:
endpoint_mode
  为连接到一个群的外部客户端指定一个服务发现方法
  endpoint_mode: vip -docker 为服务分配一个虚拟 ip (vip) ,作为客户端到达网络上服务的前端。Docker 在客户端和服务的可用工作节点之间传递请求,而客户端不知道有多少节点参与服务,也不知道它们的 ip 地址或端口。(这是默认的。)
  endpoint_mode: dnsrr - 服务发现不使用单个虚拟 ip。Docker 为服务设置 dns 条目,以便对服务名称的 dns 查询返回一个 ip 地址列表,客户机直接连接到其中一个。Dns round-robin 在需要使用自己的负载均衡器或混合 windows 和 linux 应用程序的情况下非常有用
  version: "3.9"
  services:
    wordpress:
      image: wordpress
      ports:
        - "8080:80"
      networks:
        - overlay
      deploy:
        mode: replicated
        replicas: 2
        endpoint_mode: vip
  
    mysql:
      image: mysql
      volumes:
         - db-data:/var/lib/mysql/data
      networks:
         - overlay
      deploy:
        mode: replicated
        replicas: 2
        endpoint_mode: dnsrr
  volumes:
    db-data:
  networks:
    overlay:
labels
  为服务指定标签。这些标签只在服务上设置,而不在服务的任何容器上。
  version: "3.9"services:
    web:
      image: web
      deploy:
        labels:
          com.example.description: "This label will appear on the web service"
  要在容器上设置标签,请在 deploy 之外使用标签键:
  version: "3.9"services:
    web:
      image: web
      labels:
        com.example.description: "This label will appear on all containers for the web service"
mode
  要么是全局的(每个群集节点只有一个容器),要么是复制的(指定数量的容器)。默认是复制的。(了解更多信息,请查看 swarm 主题中的replicated和global services)
  version: "3.9"services:
    worker:
      image: dockersamples/examplevotingapp_worker
      deploy:
        mode: global
placement
  指定约束和首选项的位置。请参阅 docker 服务创建文档,了解语法和约束、首选项的可用类型的完整描述,并指定每个节点的最大副本
  version: "3.9"services:
    db:
      image: postgres
      deploy:
        placement:
          constraints:
            - "node.role==manager"
            - "engine.labels.operatingsystem==ubuntu 18.04"
          preferences:
            - spread: node.labels.zone
max_replicas_per_node
  如果服务设置了副本数(这是默认值),限制任何时候在一个节点上运行的副本数量。当请求的任务比运行的节点多时,不会引发合适的节点错误(每个节点的最大副本限制超过)。
  version: "3.9"services:
    worker:
      image: dockersamples/examplevotingapp_worker
      networks:
        - frontend
        - backend
      deploy:
        mode: replicated
        replicas: 6
        placement:
          max_replicas_per_node: 1
replicas
  如果服务设置了副本数(这是默认值),则指定在任何给定时间应该运行的容器数量。
  version: "3.9"services:
    worker:
      image: dockersamples/examplevotingapp_worker
      networks:
        - frontend
        - backend
      deploy:
        mode: replicated
        replicas: 6   
resources
  配置资源约束
  (cpu_shares, cpu_quota, cpuset, mem_limit, memswap_limit, mem_swappiness).
  redis 服务被限制使用不超过50m 的内存和0.50(单核的50%)的可用处理时间(cpu) ,并且有20m 的内存和0.25的 cpu 时间(总是可用)。
  version: "3.9"services:
    redis:
      image: redis:alpine
      deploy:
        resources:
          limits: ##最大值
            cpus: '0.50'
            memory: 50M
          reservations:  ##初始值
            cpus: '0.25'
            memory: 20M
restart_policy
  配置如何在容器退出时重新启动容器
  condition: 定义什么时机进行重启,One of none,on-failure是在运行失败时进行重启或者any(默认any)
  delay: 发生错误后多长时间执行重启,指定为持续时间(默认值: 5秒)。
  max_attempts: 在放弃之前尝试重新启动容器的次数(默认值: 永远不要放弃)。如果重新启动在配置的窗口内不成功,则此尝试不计入配置的 max_attempts 值。例如,如果 max _ attempts 设置为‘2’,并且第一次尝试重启失败,则可能会尝试两次以上的重启。
  window: 设置重启的超时时间,指定为持续时间(默认值: 立即决定)。
  version: "3.9"services:
    redis:
      image: redis:alpine
      deploy:
        restart_policy:
          condition: on-failure
          delay: 5s
          max_attempts: 3
          window: 120s
rollback_config
  配置在更新失败的情况下应该如何回滚服务。
  parallelism: 每次回滚的容器数量。如果设置为0,所有容器同时回滚。
  delay: 每个容器组回滚之间的等待时间(默认值为0)
  failure_action:如果回滚失败,应该怎么做。一个 continue 或 pause (default pause) 
  monitor: 每次任务更新后监视故障后的持续时间(ns | us | ms | s | m | h)(缺省值5s)注意: 设置为0将使用缺省值5s。
  max_failure_ratio: 回滚期间容忍的故障率(默认值为0)。
  order: 回滚期间的操作顺序。stop-first(在启动新任务之前停止旧任务)或start-first(先启动新任务,然后运行任务短暂重叠)之一(默认stop-first)。
update_config
  配置如何更新服务,对于配置滚动更新很有用
  parallelism: 每次更新的容器数量
  delay: 更新一组容器之间的等待时间
  failure_action:如果更新失败了怎么办。选择 continue、 rollback 或 pause (默认值: pause)
  monitor: 每个容器更新后,持续观察是否失败了的时间(ns | us | ms | s | m | h)(缺省值5s)注意: 设置为0将使用缺省值5s
  max_failure_ratio: 更新过程中容忍的故障率
  order: 更新期间的操作顺序。Stop-first (在启动新任务之前停止旧任务)或 start-first (先启动新任务,然后运行任务短暂重叠)(默认 stop-first) 注意:只支持 v3.4版本和更高版本的文件格式。
docker stack deploy不支持以下子选项(支持 docker-compose up 和 docker-compose run)。
  build
  cgroup_parent
  container_name
  devices
  tmpfs
  external_links
  links
  network_mode
  restart
  security_opt
  userns_mode

案例2
version: "3.9"
services:
   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "80:80"
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
     deploy:
       mode: replicated
       replicas: 3
     healthcheck:
      test: ["CMD", "wget", "-qO", "-", "http://localhost"]
      interval: 2s
      timeout: 2s
      retries: 3
      start_period: 2s
     networks:
       - overlay
   db:
     image: mysql:8.0.18
     command:
      - --default_authentication_plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
     volumes:
       - db-data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD: root123
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
     deploy:
       placement:
         constraints: [node.role == manager]
     networks:
       - overlay
volumes:
  db-data:
networks:
  overlay:

案例3
version: '3.5'
networks:
  gogs:
    #网络类型必须是overlay
    driver: overlay
    external: false
volumes:
  db-data:
  db-conf:
  gogs-data:
services:
  mysql:
    image: mysql:5.7
    networks:
      - gogs
    ports:
      - "3306:3306"
    environment:
      - MYSQL_DATABASE=gogs
      - MYSQL_ROOT_PASSWORD=YOUR_PWD
    command:
      --lower_case_table_names=1
      --character-set-server=utf8
      --collation-server=utf8_general_ci
      --explicit_defaults_for_timestamp=true
      --sql-mode=STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO
    volumes:
      - db-data:/var/lib/mysql
      - db-conf:/etc/mysql/conf.d
    deploy:
      placement:
        constraints: [node.role == manager]
  gogs:
    image: gogs/gogs:latest
    networks:
      - gogs
    ports:
      - "1122:22"
      - "3000:3000"
    volumes:
      - gogs-data:/data
    depends_on:
      - mysql
    deploy:
      mode: replicated
      replicas: 3
      


docker stack 部署服务
\
sudo docker stack deploy -c docker-compose.yml wordpress

查看:
sudo  docker stack ps wordpress
移除服务,但是不会移除数据卷:
sudo docker stack down wordpress
移除数据卷
sudo docker volume prune


 

更新与回滚策略

1.配置重启策略

version: "3.9"
services:
  web:
    image: nginx:1.13-alpine
    ports:
      - "80:80"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 7
      restart_policy: ##重启设置
        condition: on-failure ##发生错误多长时间执行重启
        delay: 10s  ##发生错误多长时间执行重启
        max_attempts: 3 ##在放弃之前尝试重新启动容器的次数
        window: 120s ##设置重启的超时时间
networks:
  overlay:
 

2.配置更新策略

version: "3.9"
services:
  web:
    image: nginx:aaaa ###将镜像设置为不存在的
    ports:
      - "80:80"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 7
      restart_policy: ##重启设置
        condition: on-failure ##发生错误多长时间执行重启
        delay: 10s  ##发生错误多长时间执行重启
        max_attempts: 3 ##在放弃之前尝试重新启动容器的次数
        window: 120s ##设置重启的超时时间
      update_config:
        parallelism: 2 ##每次更新容器数量
        delay: 10s   ##更新一组容器之间的等待时间
        failure_action: pause ##如果更新失败了怎么办,选择 continue、 rollback 或 pause (默认值: pause)
        monitor: 500ms ###每个容器更新后,持续观察是否失败了的时间
        max_failure_ratio: 0.5 ##在更新过程中可以容忍的故障率
networks:
  overlay:
 

3.配置回滚策略

version: "3.9" ##这个能写具体就具体点,之前3,启动服务直接报不支持rollback_config
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 7
      restart_policy: ##重启设置
        condition: on-failure ##发生错误多长时间执行重启
        delay: 10s  ##发生错误多长时间执行重启
        max_attempts: 3 ##在放弃之前尝试重新启动容器的次数
        window: 120s ##设置重启的超时时间
      update_config:
        parallelism: 2 ##每次更新容器数量
        delay: 10s   ##更新一组容器之间的等待时间
        failure_action: rollback ##如果更新失败了怎么办,选择 continue、 rollback 或 pause (默认值: pause)
        monitor: 500ms ###每个容器更新后,持续观察是否失败了的时间
        max_failure_ratio: 0.5 ##在更新过程中可以容忍的故障率
      rollback_config:
        parallelism: 1 ##每次回滚的容器数量。如果设置为0,所有容器同时回滚。
        delay: 0s ##每个容器组回滚之间的等待时间(默认值为0)
        monitor: 500ms ##每次任务更新后监视故障后的持续时间
networks:
  overlay:
 

健康检查

version: "3.9"
services:
  web:
    image: nginx:1.13-alpine
    ports:
      - "80:80"
  networks:
      - overlay
  deploy:
    mode: replicated
    replicas: 7
    restart_policy: ##重启设置
      condition: on-failure ##在运行失败的时候
      delay: 10s  ##发生错误多长时间执行重启
      max_attempts: 3 ##在放弃之前尝试重新启动容器的次数(默认值: 永远不要放弃)
      window: 120s ##设置重启的超时时间
    update_config:
      parallelism: 2 ##每次更新容器数量
      delay: 10s     ##更新一组容器之间的等待时间
      failure_action: pause ##如果更新失败了怎么办,选择 continue、 rollback 或 pause (默认值: pause)
      monitor: 500ms ###每个容器更新后,持续观察是否失败了的时间
      max_failure_ratio: 0.5 ##在更新过程中可以容忍的故障率
    rollback_config:
      parallelism: 1 ##每次回滚的容器数量。如果设置为0,所有容器同时回滚。
      delay: 0s ##每个容器组回滚之间的等待时间(默认值为0)
      monitor: 500ms ##每次任务更新后监视故障后的持续时间
    healthcheck:
      test: ["CMD", "wget", "-qO", "-", "http://localhost"] ##定义检测的命令 
      interval: 2s #命令执行间隔,默认30秒
      timeout: 2s #命令超时时间,默认30秒
      retries: 3  #命令失败重试次数
      start_period: 2s #启动延时,即容器启动后多久开始执行检测
networks:
  overlay:



 

评论区域