官网:https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/
docker swarm 是 docker 官方提供的容器编排和集群管理工具。它允许用户将多个 docker 主机组成一个虚拟的 docker 集群,以便更高效地管理和运行容器化应用程序。
docker swarm 采用主从架构,其中有一个主节点和多个工作节点。主节点负责管理整个集群,维护集群状态,并接受用户的命令进行应用程序的部署和管理。工作节点是实际运行容器的节点,它们接收来自主节点的任务指令,并在自己的主机上创建、启动和管理相应的容器。
使用 docker swarm,用户可以通过简单的命令或配置文件定义应用程序的服务和任务,然后将其部署到整个集群中。swarm 会自动将应用程序的任务分配到可用的工作节点上,并提供负载均衡和容器的高可用性。如果某个节点发生故障或新增节点加入集群,swarm 会自动进行容器的迁移和重新分配,以保证应用程序的稳定运行。
总而言之,docker swarm 为用户提供了一个简单、可扩展和高可用的容器编排和集群管理解决方案,使得容器化应用程序的部署和管理更加便捷和可靠。
192.168.0.111
192.168.0.112
192.168.0.113
192.168.0.114
命名服务器(方便查看,node111、node112、node113、node114)
每一个服务器都安装 docker
swarm 基本命令
[root@node111 ~]# docker swarm --help
Usage: docker swarm COMMAND
Manage Swarm
Commands:
# 初始化节点
init Initialize a swarm
# 加入节点
join Join a swarm as a node and/or manager
# 初始化一个节点并暴露出去
[root@node111 ~]# docker swarm init --advertise-addr 192.168.0.111
Swarm initialized: current node (h6cjybqx8m7fqc9vih7z1qcdy) is now a manager.
# 添加工作节点的命令
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-019i2ettz5yuv6j62eqpwk4ensnmc50fauda6ohd6p0bgkn27b-dzbzn9jzsz9q3zrf6zvdena70 192.168.0.111:2377
# 添加管理节点的命令 docker swarm join-token manager
# 初始化的节点为主节点,必须先由初始化的节点先加入管理节点后其它节点才可以加入到管理节点,也就是192.168.0.111(node111)这个节点
# node111 需要先执行 docker swarm join-token manager 加入到 manager 管理节点
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
[root@node111 ~]# docker swarm join-token manager
# node111 加入管理节点后,如果再想加入其它管理节点,执行下面的命令
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-019i2ettz5yuv6j62eqpwk4ensnmc50fauda6ohd6p0bgkn27b-bprv9pj27xgt5hq1m1b4xhguu 192.168.0.111:2377
第一个初始化的节点(node111)在集群中是 leader 领导者节点
docker swarm leave
docker swarm leave --force # 强制离开
[root@node112 ~]# docker swarm join --token SWMTKN-1-019i2ettz5yuv6j62eqpwk4ensnmc50fauda6ohd6p0bgkn27b-dzbzn9jzsz9q3zrf6zvdena70 192.168.0.111:2377
This node joined a swarm as a worker.
[root@node113 ~]# docker swarm join --token SWMTKN-1-019i2ettz5yuv6j62eqpwk4ensnmc50fauda6ohd6p0bgkn27b-bprv9pj27xgt5hq1m1b4xhguu 192.168.0.111:2377
This node joined a swarm as a manager.
[root@node114 ~]# docker swarm join --token SWMTKN-1-019i2ettz5yuv6j62eqpwk4ensnmc50fauda6ohd6p0bgkn27b-bprv9pj27xgt5hq1m1b4xhguu 192.168.0.111:2377
This node joined a swarm as a manager.
列出当前 docker swarm集群中的所有节点(包括主节点和工作节点)的详细信息
docker node ls
这个命令只能在 manager 管理节点上运行,不能在 worker 工作节点上运行
这里为什么有构建3台 manager 管理节点,是因为 Raft 协议
Raft 协议是一种用于分布式一致性的共识算法。它旨在解决分布式系统中的领导者选举、日志复制和安全性等问题,以保证多个节点之间的一致性和可靠性。
在 Raft 协议中,一个集群由多个节点组成,其中包括一个领导者节点和多个跟随者节点。所有的操作都必须经过领导者节点进行处理和协调,而跟随者节点则按照领导者节点的指令执行相应的操作。
Raft协议的核心机制是通过选举来确定领导者节点。当集群启动或者当前的领导者节点出现故障时,会触发一次新的选举过程。在选举中,节点会互相发送请求并进行投票,最终得票最多的节点成为新的领导者。
一旦领导者选举完成,Raft协议使用日志复制机制来确保集群中的节点都具有相同的日志序列。领导者节点负责接收客户端的操作请求,并将其转化为一条指令记录到自己的日志中。然后,领导者节点通过心跳机制将日志复制给跟随者节点,跟随者节点在收到并复制日志后,返回确认给领导者节点。当大多数节点都确认了一条日志后,该日志被认为是已提交的,并可以执行相应的操作。
通过以上机制,Raft协议保证了分布式系统中的一致性和可靠性。它提供了明确的领导者选举过程、日志复制机制和安全性保障,使得分布式系统的设计和实现更加可靠和简单。
为什么使用3个管理者节点?
如果我们使用双主双从搭建,只有两个管理节点,如果一个节点挂了,另外一个节点也不能用,这是因为 Raft 一致性算法,必须要确保大多数节点存活才可以用,所以要保证有奇数个节点,生产环境最少3 manager
先保证有两个管理节点,挂掉其中一台。另一个管理节点docker node ls
命名不可用。
如果有 worker 和 manager 节点离开了,状态会更新为 down,不可用了。
可以没有 worker 工作节点,全是管理节点。
如果 leader 领导者节点挂了,就全部都挂掉了。
结论:
Raft 协议保证:至少要保证有两个及两个以上的管理者节点,集群才可以使用,否则直接挂掉。
这就是 Raft 协议,确保大多数节点存活才可以用!高可用!
命令:
docker service
示例1:创建 nginx
# 集群下 docker service create
[root@node111 ~]# docker service create -p 8888:80 --name my-nginx nginx
通过docker service
启动服务,服务会挂载任意一个节点上,在任何服务器都可以访问到该服务,不需要在启动容器的节点中访问。
# 查看服务的详细信息
[root@node111 ~]# docker service inspect --pretty my-nginx
ID: v3dzdnv1hokey3174ytg7ydbs
Name: my-nginx
# 副本数量 Replicated
Service Mode: Replicated
Replicas: 1
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
RollbackConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Rollback order: stop-first
ContainerSpec:
Image: nginx:latest@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Init: false
Resources:
Endpoint Mode: vip
Ports:
PublishedPort = 8888
Protocol = tcp
TargetPort = 80
PublishMode = ingress
[root@node111 ~]# docker service ps my-nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
v0ukz27ag5tg my-nginx.1 nginx:latest node112 Running Running 3 minutes ago
如果一台服务器不够用了,可以进行扩容。
所有和服务相关的命令 docker service
使用参数--replicas
# 创建时指定副本个数
docker service create --replicas 3 my-nginx
# 对已有的服务进行扩容
[root@node111 ~]# docker service update --replicas 3 my-nginx
my-nginx
overall progress: 3 out of 3 tasks
1/3: running
2/3: running
3/3: running
verify: Service converged
回滚命令:rollback
# 回滚到之前的状态!(当前和上一个来回回滚)
docker service rollback my-nginx
# 灰度发布
# --image nginx:1.18.0-alpine 新的容器镜像
# --update-parallelism 1 同时更新的数量
# --update-delay 10s
[root@node111 ~]# docker service update --image nginx:1.18.0-alpine --update-parallelism 1 --update-delay 10s my-nginx
示例2:tomcat
# 给服务创建一个专属网络
docker network create -d overlay tomcat-net
# 启动服务
[root@node111 ~]# docker service create --name tomcat \
> --network tomcat-net \
> -p 8080:8080 \
> --replicas 3 \
> tomcat
yscxmfw6uchsivqrsald8tj11
overall progress: 3 out of 3 tasks
1/3: running
2/3: running
3/3: running
verify: Service converged
# 扩缩容
# docker service scale tomcat=5
# 服务删除
#[root@node111 ~]# docker service rm tomcat
tomcat
# 服务一旦移除,所有节点上的容器就自动停止
示例3:wordpress
[root@node111 ~]# docker service create --name mysql --env MYSQL_ROOT_PASSWROD=root --env MYSQL_DATABASE=wordpress --network demo --mount type=volume,source=mysql-data,destination=/var/lib/mysql mysql:5.7.24
# 如果做了数据共享,那么启动多份的话,是可以保证数据不同的。
[root@node111 ~]# docker service create --name wordpress -p 80:80 --env WORDPRESS_DB_USER=root --env WORDPRESS_DB_PASSWORD=root --env WORDPRESS_DB_HOST=mysql:3306 --env WORDPRESS_DB_NAME=wordpress --network demo wordpress
说明:服务模式
服务模式一共有两种:Ingress 和 Host,如果不指定,则默认的是 Ingress;
Ingress 模式(overlay 网络)下,到达 swarm 任何节点的8080端口的流量,都会映射到任何服务副本的内部80端口,就算该节点上没有 tomcat 服务副本也会映射;
Host 模式下,仅在运行有容器副本的机器上开放端口,使用 Host 模式的命令如下:
docker service create --name tomcat \
--network host \
--publish published=8080,target=8080,mode=host \
--replicas 2 \
tomcat:7.0.96-jdk8-openjdk
swarm
:集群的管理和编排是使用嵌入 docker 引擎的 SwarmKit ,可以在 docker 初始化时启动 swarm 模式或者加入已存在的 swarm
主要是init
初始化节点,join
加入节点
node
:一个节点是 docker 引擎集群的一个实例。您还可以将其视为 docker 节点。您可以在单个物理计算机或云服务器上运行一个或多个节点,但生产群集部署通常包括分布在多个物理和云计算机上的 docker 节点。
要将应用程序部署到 swarm,请将服务定义提交给 管理器节点。管理器节点将称为任务的工作单元分派 给工作节点。
manager 节点还执行维护所需群集状态所需的编排和集群管理功能。manager 节点选择单个领导者来执行编排任务。
工作节点接收并执行从管理器节点分派的任务(Task)。默认情况下,管理器节点还将服务作为工作节点运行,但您可以将它们配置为仅运行管理器任务并且是仅管理器节点。代理程序在每个工作程序节点上运行,并报告分配给它的任务。工作节点向管理器节点通知其分配的任务的当前状态,以便管理器可以维持每个工作者的期望状态。
service
:一个服务是任务的定义,管理机或工作节点上执行。它是群体系统的中心结构,是用户与群体交互的主要根源。创建服务时,你需要指定要使用的容器镜像。
说明:docker service 不管镜像的构建的。必须要自己去构建镜像。通过docker service
启动
task
:任务是在 docekr 容器中执行的命令,manager 节点根据指定数量的任务副本分配任务给 worker 节点
使用 docker engine cli 创建一个 docker engine 的 swarm 模式,在集群中部署应用程序服务。链接数以万计的 docker 节点。
swarm 角色分为 manager 和 worker 节点,manager 节点故障不影响应用使用,raft 协议原则。
可以声明每个服务运行的容器数量,通过添加或删除容器数自动调整期望的状态。
swarm manager 节点不断监视集群状态,并调整当前状态与期望状态之间的差异。例如,设置一个服务运行10个副本容器,如果两个副本的服务器节点崩溃,manager 将创建两个新的副本替代崩溃的副本。并将新的副本分配到可用的 worker 节点。
可以为服务指定 overlay 网络。当初始化或更新应用程序时,swarm manager 会自动为 overlay 网络上的容器分配IP地址。
swarm manager 节点为集群中的每个服务分配唯一的 DNS 记录和负载均衡 VIP。可以通过 swarm 内置的 DNS 服务器查询集群中每个运行的容器。
实现服务副本负载均衡,提供入口访问。也可以将服务入口暴露给外部负载均衡器再次负载均衡。
swarm 中的每个节点使用TLS相互验证和加密,确保安全的其他节点通信。
升级时,逐步将应用服务更新到节点,如果出现问题,可以将任务回滚到先前版本。
node
:service
:swarm manager:
-- 1、API:这个请求直接由Swarm manager的API进行接收,接收命令并创建服务对象。
-- 2、orchestrator:为服务创建一个任务。
-- 3、allocater:为这个任务分配IP地址。
-- 4、dispatcher:将任务分配到指定的节点。
-- 5、scheduler:在该节点中下发指定命令。
worker node:接收manager任务后去运行这个任务。
-- 1、container:创建相应的容器。
-- 2、worker:连接到调度程序以检查分配的任务
-- 3、executor:执行分配给工作节点的任务
服务副本与全局服务
在 docker swarm 中部署的 service,有几种类型?
这个问题的答案,非常的简单,2种:
下面的图表显示了一个有3个副本的 service(黄色)和一个 global 的 service(灰色):
调整 service 以什么方式运行
--mode string
Service mode (replicated or global) (default "replicated")
docker service create --mode replicated --name mytom tomcat:7 默认的
# 副本类型的 service,就是你需要部署几个副本,指定一下就可以有几个 task 在 swarm 集群中运行
docker service create --mode global --name test alpine ping baidu.com
# 全局类型的 service,类似于 k8s 的 daemonset 对象,就是在每个节点上都运行一个 task,不需要预先指定副本的数量,如果有新的节点加入到集群中,也会自动的在这个节点上运行一个新的 task.
补充 Label 的说明
我们讨论了 service 部署的两种模式:global mode 和 replicated mode。无论采用 global mode 还是 replicated mode,副本运行在哪些节点都是由 swarm 决定的,作为用户我们有没有可能精细控制 service 的运行位置呢?
能,使用 label
逻辑分两步:
docker node update --label-add env=test 节点1
docker node update --label-add env=prod swarm-worker2
# 指定在那个机器上来拉起这个服务。很少用
docker service create \
--constraint node.labels.env==test \
--replicas 3 \
--name my_web \
--publish 8080:80 \
httpd
#更新 service,将其迁移到生产环境:
docker service update --constraint-rm node.labels.env==test my_web
docker service update --constraint-add node.labels.env==prod my_web
在 swarm service 中有三个重要的网络概念:
初始化或加入 swarm 集群时会自动创建 ingress 网络,大多数情况下,用户不需要自定义配置,但是 docker 17.05 和更高版本允许你自定义。
docker_gwbridge 网络在初始化或加入 swarm 时自动创建。大多数情况下,用户不需要自定义配置,但是 docker 允许自定义。
名称 | 类型 | 注释 |
---|---|---|
docker_gwbridge | bridge | none |
ingress | overlay | none |
custom-network | overlay | none |
docker swarm init/connect
之后。ingress 网络。vip(虚拟 ip 模式)
到这里 docker 多机通信逻辑及实战就结束了,但 docker swarm 只是匆匆过客,最终还是要回到 kubernetes 上。
我们介绍了 docker compose,它是用来进行一个完整的应用程序相互依赖的多个容器的编排的,但是缺点是不能在分布式多机器上使用;我们也介绍了 docker swarm,它构建了 docker 集群,并且可以通过 docker service
命令在不同集群节点上运行容器服务,但是缺点是不能同时编排多个服务。
单机模式下,我们可以使用 docker compose 来编排多个服务,而 docker swarm 只能实现对单个服务的简单部署。本文的主角 docker stack ,通过 docker stack 我们只需对已有的 docker-compose.yml 配置文件稍加改造就可以完成 docker 集群环境下的多服务编排。
但是在实际的生产开发中,我们一个完整的应用需要的服务往往不止一个,通过 docker service
命令来部署的话会很麻烦,所以这里要讲一下 docker stack,它用于向 swarm 集群部署完整的应用程序堆栈,可以在分布式多机器上同时编排多个有依赖关系的服务。
stack 能够在单个声明文件中定义复杂的多服务应用,还提供了简单的方式来部署应用并管理其完整的生命周期:初始化部署 -> 健康检查 -> 扩容 -> 更新 -> 回滚,以及其他功能!可以简单地理解为 stack 是集群下的 compose。
给 docker 集群部署服务的两种方式
# 效果:单机部署。自己产生默认的网络
docker compose up -d -c docker-compose.yml
# 集群部署,compose里面的所有服务会被发配到集群的各个地方
docker stack deploy docker-compose.yml
https://gitee.com/landylee007/voting-app
部署一个投票APP,包含如下服务:
首先创建一个 docker-compose.yml 文件,使用 docker compose v3 语法
version: "3"
services:
redis:
image: redis:alpine
networks:
- frontend
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
db:
image: postgres:9.4
environment:
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "postgres"
POSTGRES_HOST_AUTH_METHOD: "trust"
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- 5000:80
networks:
- frontend
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
restart_policy:
condition: on-failure
result:
image: dockersamples/examplevotingapp_result:before
ports:
- 5001:80
networks:
- backend
depends_on:
- db
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
depends_on:
- db
- redis
deploy:
mode: replicated
replicas: 1
labels: [APP=VOTING]
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints: [node.role == manager]
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
frontend:
backend:
volumes:
db-data:
# 使用stack
docker stack deploy vote
docket stack services vote
docket stack ls
docket stack rm
[root@node111 vote]# docker stack ls
NAME SERVICES
vote 6
[root@node111 vote]# docker stack rm vote
Removing service vote_db
Removing service vote_redis
Removing service vote_result
Removing service vote_visualizer
Removing service vote_vote
Removing service vote_worker
Removing network vote_frontend
Removing network vote_backend
Removing network vote_default
vi sua lizer 监控页面:
stack 会忽略了“构建”指令,无法使用 stack 命令构建新镜像,它是需要镜像是预先已经构建好的。 所以 compose 更适合于开发场景;
compose 是一个 python 项目,在内部,它使用 docker API 规范来操作容器。所以需要安装 docker compose,以便与 docker 一起在您的计算机上使用;
stack 功能包含在 docker 引擎中。你不需要安装额外的包来使用它,docker stack 只是 swarm mode 的一部分。
stack 不支持基于第2版写的 docker-compose.yml ,也就是 version 版本至少为3。然而 compose 对版本为2和3的 文件仍然可以处理;
stack 把 compose 的所有工作都做完了,因此 stack 将占主导地位。而且,对于大多数用户来说,切换到使用 stack 既不困难,也不需要太多的开销。如果您是 docker 新手,或正在选择用于新项目的技术,请使用 docker stack。
查看官网介绍,secret 是 daemon API 1.25 之后引入的,它是运行在 swarm 上的命令。
生产环境下,为了安全,我们不能把各项目的配置密码写入到配置文件。
我们可以引入 docker 的 secret 方式保护密码。
场景:
示例
echo "123456" |docker secret ceate xxx -
# 传递参数
[root@node111 ~]# docker service create --name mysql --secret mysql_pwd -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pwd -p 3306:3306 mysql:5.7
# 写到yaml配置中
version: "3"
services:
mysql:
image: mysql:5.7
ports:
- 3306:3306
secrets:
- mysql_pwd
enviroment:
- MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_pwd
# 探究
[root@node111 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11b0a5f6eb2c mysql:5.7 "docker-entrypoint.s…" 24 seconds ago Up 23 seconds 3306/tcp, 33060/tcp mysql.1.xfll5c4mxp9d7h5uyz2u052pe
[root@node111 ~]# docker exec -it 11b0 /bin/bash
root@11b0a5f6eb2c:/# cd /run/secrets/
root@11b0a5f6eb2c:/run/secrets# ls
mysql_pwd
root@11b0a5f6eb2c:/run/secrets# cat mysql_pwd
123456root@11b0a5f6eb2c:/run/secrets# exit
exit
原理:
我们使用--secret mysql_pwd
以后,secret 密码文件就会被解码保存到容器内部的/run/secrets/secret
中。这样我们就可以在容器中任意使用。但是外部无感知。
不管怎么使用,secret 最好提前创建好。到时候声明使用就行。其实是在内存中的。整个集群 manager 是利用 raft 同步的
docker config create [OPTIONS] CONFIG file|-
# 使用文件方式创建
docker config create redis.conf redis.conf
docker config ls
docker service create --config redis.conf --name redis redis
#config内容base64编码,是可以inspect出来的。
docker config inspect redis.conf
在线解码工具:https://c.runoob.com/front-end/693/
#secret文件是在容器中 /run/secrets/xxxx 暴露的
#config默认是在根目录暴露的。
docker ps
docker exec -it 容器id /bin/bash
#指定位置
docker service create --name redis \
--config source=redis-conf,target=/etc/redis/redis.conf,mode=0400 redis:3.0.6
#2、compose文件
version: "3"
services:
mysql:
image: redis
ports:
- 6379:6379
config:
- redis_conf
enviroment:
- MYSQL_ROOT_PASSWORD_FILE: /
更多【容器-docker进阶篇,docker集群介绍】相关视频教程:www.yxfzedu.com