Docker 系统性入门+进阶实践-08docker swarm详解
- 作为集群的编排工具,docker swarm虽然不如k8s流行,但是万变不离其宗,掌握起基本原理和使用将大大降低学习其它编排工具的难度
docker swarm介绍
- 为什么不建议在生产环境中使用docker-compose?
- 多机器如何管理
- 如何跨机器做scale横向扩展
- 容器失败退出时如何新建容器确保服务正常运行
- 如何确保零宕机时间
- 如何管理密码、key等敏感数据
- 其它
- swarm的基本架构
swarm单节点快速上手
- 初始化
docker info
这个命令可以查看我们的docker engine有没有激活swarm模式,默认是没有的,我们会看到
Swarm: inactive - 激活swarm有两个方法
- 初始化一个swarm集群,自己成为manager
- 加入一个已经存在的swarm集群
- docker swarm init背后发生了什么
主要是PKI和安全相关的自动化:
- 创建swarm集群的根证书
- manager节点的证书
- 其它节点加入集群需要的tokens
创建raft数据库用户存储证书、配置、密码等数据
raft是一个协议,这个协议主要用于分布式的、对一致性要求比较高的数据库
raft分布式一致性,带图形界面的
raft算法中的三个重要的概念:领导者选举、日志复制、snapshop快照。
- 将当前节点移除swarm集群
sudo docker swarm leave [--force]
swarm单节点service初体验
- 创建一个serice服务
sudo docker service create nginx:latest
查看service服务列表
sudo docker service ls
查看刚刚创建的容器服务:
sudo docker service ps service_id/name
也可以通过docker命令查看刚刚创建的容器:
sudo docker ps
- 通过刚刚创建的service更新为3个容器服务
sudo docker service update x6h --replicas 3
- service并不仅仅是只能创建多个replicas,当service中的容器服务有挂掉之后,它还能为我们自动创建一个
我们通过移除一个容器服务看一下:
sudo docker container rm -f container_id
然后我们看一下service状态:
sudo docker service ps service_id
- 删除service
sudo docker service rm service_id
swarm三节点环境的搭建
- 多节点的环境涉及到机器之间的通信需求,当使用云主机的时候,下面的防火墙或安全组需要打开
TCP port 2376
TCP port 2377
TCP and UDP port 7946
UDP port 4789
- 云厂商购买3台云服务器,安装好docker和docker-compose,安全组打开上面的端口,一切就绪,准备开始了。
- 在其中的一台主机器上初始化swarm集群
sudo docker swarm init
在其它两台机器上执行下面的命令,加入这个swarm集群:
sudo docker swarm join --token xxxxxxxxxxxxxxxxxxxxxxxxxxx 172.17.82.242:2377
在manager节点执行命令查看集群节点信息:
sudo docker node ls
swarm三节点service在体验
- 创建一个service,并指定其名字
sudo docker service create --name web nginx
查看创建的service
sudo docker service ls
查看service详情,包括在哪一个节点上运行
sudo docker service ps web
- 通过--replics复制刚刚起的nginx服务
sudo docker service update --replicas=3 web
我们测试杀死一个容器服务:
sudo docker container rm -f container_id
当我们杀死一个容器服务后,docker swarm会帮我们在起一个新的服务 - 另一种扩展/增加服务的方法
sudo docker service scale web=4
- 将服务的数量减少为1
sudo docker service scale web=1
会保留swarm集群中的一个容器服务,其它节点容器服务会被删除,但是其它节点的镜像和网络会保留。
查看service的详细信息:
sudo docker service inspect web
- 查看service服务的日期信息,包括该条日志对应在哪个节点上的哪个服务上
sudo docker service logs -f web
swarm的overlay网络初体验
- 对弈swarm的网络,有两个重要点
- 外部如何访问部署在swarm集群内的服务,可以称为入方向流量,在swarm里,我们通过ingress来解决
- 部署在swarm集群内的服务,如何对外进行访问,可以分为两块
(1)东西向流量,也就是说不同swarm节点上的容器之间如何进行通信,swarm通过overlay网络来解决
(2)南北向流量,也就是说swarm集群里的容器如何对外访问,比如互联网,这个是linux bridge + iptables NAT来解决
- 创建一个overlay网络用于swarm不同节点上的容器之间的通信
sudo docker network create --driver overlay mynet
- 创建一个service服务,使用我们刚刚创建的overlay网络
sudo docker service create --network mynet --name test --replicas 2 busybox ping 8.8.8.8
当在worker节点上创建该服务的时候,如果没有创建该网络,就会自动创建 - 查看容器服务的ip地址
sudo docker exec container_id ip addr
我们可以发现,该容器同时连接了两个网络,一个是overlay: mynet, 另一个是bridge: docker_gwbridge
swarm的overlay网络详解
- 容器内查看走哪个网络
ip route
- 我们通过tcpdump抓包,来测试不同节点间容器通信走overlay通信
sudo apt-get install tcpdump
在当前机器上开启抓包:sudo tcpdump -i eth0 port 4789
在另外一台机器发起ping命令,与当前机器进行容器间通信
ping 10.0.1.3 -c 3
查看抓包结果:
swarm的ingress网络详解(上)
- docker swarm的ingress网络又叫Igress Routing Mesh
主要是为了实现把service的服务端口对外发布出去,让其能够被外部网络访问到
Ingress Routing Mesh是docker swarm网络里最复杂的一部分内容,包括一下几个方面:
- iptables的Destination NAT流量转发
- linux bridge, network namespace
- 使用IPVS技术做负载均衡
- 包括容器间的通信overlay和入方向流量的端口转发
- 创建一个service服务,开启两个副本
sudo docker service create --name web --network mynet -p 8008:80 --replicas 2 containous/whoami
通过curl请求我们刚刚创建的服务,manage节点
curl 172.17.82.242:8008
多次请求,会发现服务器会以负载均衡的方式向我们响应。
当我们访问另一个容器服务所在的节点work1时:
curl 172.17.82.241:8008
多次请求,发现跟访问manage节点一致,
当我们再次访问没有部署容器服务的work2节点时:
curl 172.17.82.240
多次请求,还能正常请求,还是进行负载均衡。
swarm的ingress网络详解(下)
- ingress数据包的走向
sudo iptables -nvL -t nat
输出
Chain DOCKER-INGRESS (2 references)
pkts bytes target prot opt in out source destination
14 816 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8008 to:172.19.0.2:8008
387 23282 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
我们可以看到会把本机ip:8008端口转发到172.19.0.2:8008端口,为啥呢?
我们查看本机的ip地址:ip addr
我们会发现172.19.0.2和本机的docker_gwbridge:172.19.0.1在同一网络下,
2. 查看docker_gwbridge网络详情
sudo docker network inspect docker_gwbridge
我们发现该网络下有两个Containers,一个是我们运行的web容器,另一个就是ingress-sbox: 172.19.0.2IP地址的network namespace(网络命名空间)
3. 进入ingress-box命名空间
sudo docker run -it --rm -v /var/run/docker/netns:/netns --privileged=true nicolaka/netshoot nsenter --net=/netns/ingress_sbox sh
该命令会启动一个容器并加载我们的命名空间
4. 进入去命名空间后,查看ip地址
ip a
里面有两个ip地址,一个是连接到了docker_gwbridge网络,另一个是连接到了ingress网络
5. ipvs负载均衡
ipvsadm
6. 关于这里的ipvs负载均衡
这是一个stateless load balancing(无状态负载均衡)
这是三层的负载均衡,不是四层的 LB is at OSI Layer 3 (TCP), not Layer 4 (DNS)
以上两个限制可以通过Nginx或者HAProxy LB proxy解决
swarm内部的负载均衡_batch
- 创建一个mynet的overlay网络,创建一个service
sudo docker network create --driver overlay mynet
sudo docker service create --name web --network mynet --replicas 2 containous/whoami
- 创建一个client
sudo docker service create --name client --network mynet 1341935532/net-box ping 8.8.8.8
- 尝试进入client这个容器,去ping web这个service name, 获取到的IP 10.0.1.30,称之为VIP(虚拟IP)
sudo docker exec -it container_id sh
ping一下我们的web服务
ping web
查看我们创建的网络的详情
sudo docker network inspect mynet
发现容器里面有一个叫lb_mynet网络命名空间network namespace - 查看lb_mynet
sudo ls /var/run/docker/netns
参考文档
部署多service应用_batch
- 如何像docker-compose一样部署多服务应用,这一节我们先看手动的方式
创建一个mynet的overlay网络
sudo docker network create --driver overlay mynet
- 创建一个redis service
sudo docker service create --network mynet --name redis redis:latest redis-server --requirepass ABC123
- 创建一个flask服务
sudo docker service create --network mynet --name flask --env REDIS_PASS=ABC123 --env REDIS_HOST=redis -p 8008:5000 xiaopeng163/flask-redis:latest
注意:swarm里面是不能进行镜像的构建、因为swarm是为了生产环境使用的,生产环境不能进行镜像的构建
而docker-compose适用于开发环境,所以可以进行镜像的构建
stack部署多service应用
- 克隆代码
git clone https://github.com/xiaopeng163/flask-redis
- 构建镜像,注意将docker-compose.yml中的镜像id改为自己的
docker-compose build
- 将镜像推送到我们自己的docker hub上
sudo docker-compose push
- stack这个命令就是swarm版本的compose
compose是用于单机环境,stack是用于swarm集群环境 - 通过stack启动服务
sudo env REDIS_PASSWORD=ABC123 docker stack deploy --compose-file docker-compose.yml flask-demo
查看服务
sudo docker stack ls
查看服务列表
sudo docker stack ps flask-demo
访问我们刚刚启动的服务
curl 127.0.0.1:8008
- 删除stack创建的服务
sudo docker stack rm flask-demo
在swarm中使用secret
- 从标准输入创建一个secret
sudo echo abc123 | sudo docker secret create mysql_pass -
查看secret
sudo docker secret ls
查看secret详情
sudo docker secret inspect secret_id
我们可以看到secret的id、name,但是看不到secret本身,因为它存在了raft数据库里面了。 - 删除secret
sudo docker secret rm mysql_pass
- 通过文件创建secret
sudo docker secret create mysql_pass mysql_pass.txt
- 查看容器中加载的secret
sudo docker service create --name test --secret mysql_pass 1341935532/net-box ping 8.8.8.8 // 创建service服务
sudo docker service ls // 查看服务id
sudo docker service ps service_id // 通过服务id查看服务所在的节点
sudo docker ps -a // 通过节点查看容器服务
sudo docker exec -it container_id sh // 通过容器id进入容器服务
cd /run/secrets/ // 进入到secrets目录下
ls // 查看到了mysql_pass
more mysql_pass // 查看到了密码:abc123
- 使用secret
sudo docker service create --secret mysql_pass --name mysql-demo -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pass -d mysql:5.7 // 创建一个mysql服务,密码使用secret秘钥的形式
sudo docker exec -it container_id sh // 进入容器shell
mysql -uroot -pabc123 // 使用刚刚创建的秘钥连接mysql,成功
注意:secret并不是适用于所有的镜像,需要查看docker hub官方的文档,看支持不支持secret.
secrets 官方文档
swarm使用本地volume
- docker-compose.yml文件
version: "3.8"
services:
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pass
secrets:
- mysql_pass
volumes:
- data:/var/lib/mysql
volumes:
data:
secrets:
mysql_pass:
file: mysql_pass.txt
- mysql_pass.txt文件
abc123456
- 通过stack和docker-compose.yml创建我们的集群服务, db就是stack的名字
sudo docker stack deploy --compose-file docker-compose.yml db
- 删除stack
sudo docker stack rm db
swarm练习之投票app
- 克隆代码
git clone https://github.com/dockersamples/example-voting-app
- 通过stack构建投票服务
sudo docker stack deploy --compose-file docker-stack.yml vote
由于原版有点bug,所以我们需要打开docker-stack.yml文件,对postgres增加如下envrironment配置
POSTGRES_HOST_AUTH_METHOD: "trust"
此问题参考官方文档
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)