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 官网的这张图片形象的展示了集群中管理节点与工作节点的关系:
任务 (Task)是 Swarm 中的最小的调度单位,目前来说就是一个单一的容器。
服务 (Services) 是指一组任务的集合,服务定义了任务的属性。服务有两种模式:
replicated services 按照一定规则在各个工作节点上运行指定个数的任务。
global services 每个工作节点上运行一个任务
两种模式通过 docker service create 的 --mode 参数指定。
Docker 官网的这张图片形象的展示了容器、任务、服务的关系
网络模式
在Swarm集群中,由于在容器上层又增加了一个service概念,因此对容器的访问更改成了对service的访问,然后再由一个service对应多个容器。那么一个service可能会包含多个容器副本,而这些容器副本多数情况下是运行在不同的主机中,为了实现service到具体容器副本的转发,在网络模式上与之前的单机的容器网络也将有
所不同
swarm service是一个抽象的概念,它只是一个对运行在swarm集群上的应用服务,所期望状态的描述。它就像一个描述了下面物品的清单列表一样:
在Docker Swarm中,task是一个部署的最小单元,task与容器是一对一的关系。
stack是描述一系列相关services的集合。我们通过在一个YAML文件中来定义一个stack。
由于一个service会包含多个容器副本,多个副本可以看成一个service整体,它们通常只干一类相同的事情。而稍复杂一点的情况是,一个service可能还需要依赖其他service的能力才能完成任务,那么这就涉及从一个service到另一个service的调用。那么因此在swarm中最常见的2种网络访问是:
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。
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 |
加入命令:
sudo docker swarm join --token SWMTKN-1-3daa7g97rlpms4aon7lwsnggdsbj24hh6ll9xx1tpxcbnmrh2p-9b7varm8ukgzrkiuaicbg93k6 192.168.79.129:2377
执行结果:
命令与主机2 一致
提示:
主机2 / 主机 3 不需要执行init,直接加入即可
在manager节点,输入命令查看:
sudo docker node ls
从中执行结果可以看到,一共有三个节点每个节点的docker版本信息,其中一个是Leader节点
sudo docker info
通过info命令可以查看当前节点(manager)的swarm详细信息
提示:
默认情况下manager同时也是worker,会承担工作发布容器任务。如果不想让manger节点执行任务,则可以在manager节点执行下面命令:
drain参数的意思是manager节点不再接受新的task,如果节点上已经有task在运行,则停止掉并调度到其它worker节点上去:sudo docker node update --availability drain manager
最好只设置一个为管理节点,如果有两个以上管理节点,会因为开机的先后顺序,搞得leader来回跳,服务命令又只能在管理节点运行
docker service 适合启动单个服务,对于多服务部署和管理有些无能为力,可以使用docker stack来管理操作
至此,docker swarm集群已经搭建好并就绪工作了。
manager 节点执行命令
sudo docker service create --replicas 3 -p 80:80 --name nginx nginx:1.13-alpine
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在进行多服务部署和管理时通常会使用Docker Stack来解决大规模部署管理问题,Docker引擎在1.12 版本集成了Docker Swarm, 内置新的容器编排工具docker stack,通过提供期望状态、滚动升级、简单易用、扩缩容、健康检查等特性简化了应用的管理,这些功能都封装在一个完美的声明式模型当中。
如果你之前单机用过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
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:
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:
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:
https://www.leftso.com/article/1063.html