Docker实战指南 0x07 Docker Swarm
https://docs.docker.com/swarm/overview/
2015 年年初,libswarm 项目开发六个月之后,Docker 向公众发布了 Swarm 的第一个 Beata 版本。Swarm 的目的是为 docker 客户端工具提供统一的接口,让它不仅能管理单个 Docker 守护进程,还能管理整个集群。Swarm 不是配置应用或实现可重复部署的工具,其作用是为 Docker 现有的工具提供集群资源管理能力。
架构
进阶
Swarm集群(2manager-3worker)
https://docs.docker.com/engine/swarm/ swarm入门操作
In Docker 1.12 and higher;Swarm已经内置了,无需安装
8容器-->1个服务。 redis有8个实例。
对象-->类。
raft:大多,manager节点存活。worker不参与集群一致性。
2-manager >1台;生产环境最少3 manager;炸一个集群完美工作。
在所有docker主机上,选定一个主节点。运行docker swarm init --advertise-addr ip地址
,初始化一个manager
docker swarm init \
--advertise-addr 192.168.121.142
--listen-addr 192.168.121.142
#关于advertise-addr和listen-addr这两个参数,前者用来指定其他节点连接m0时的地址,后者指定承载swarm流量的IP和端口
以后告别docker run
#1、docker-compose up 使用compose启动一个服务。docker-compose是单机下的玩具
#2、集群:docker service (使用docker管理服务。)容器升级为服务。
# docker service:管理集群里面的所有服务
# docker stack:管理集群的app stack;一个完整的应用有超多服务,就是一个服务栈
#扩容;
docker service create --name hello-nginx -p 8888:80 --replicas 3 nginx
docker service update --replicas 3 hello-nginx
#升级。滚动升级
docker service rollback hello-nginx; 当前+之前 来回回滚
#灰度发布,迭代。
docker service update --image nginx:1.18.0-alpine --update-parallelism 1 --update-delay 10s hello-nginx
docker service create
#为什么每一个机器8888都能访问。
剩下节点使用docker swarm join即可;
在主节点
docker swarm join-token manager
#可以生成Manager节点的join信息,再选中一个节点,运行命令就可以作为manager加入
docker node ls #查看节点信息
基本概念
1.Swarm
集群的管理和编排是使用嵌入docker引擎的SwarmKit,可以在docker初始化时启动swarm模式或者加入已存在的swarm
2.Node
一个节点是docker引擎集群的一个实例。您还可以将其视为Docker节点。您可以在单个物理计算机或云服务器上运行一个或多个节点,但生产群集部署通常包括分布在多个物理和云计算机上的Docker节点。
要将应用程序部署到swarm,请将服务定义提交给 管理器节点。管理器节点将称为任务的工作单元分派 给工作节点。
Manager节点还执行维护所需群集状态所需的编排和集群管理功能。Manager节点选择单个领导者来执行编排任务。
工作节点接收并执行从管理器节点分派的任务。默认情况下,管理器节点还将服务作为工作节点运行,但您可以将它们配置为仅运行管理器任务并且是仅管理器节点。代理程序在每个工作程序节点上运行,并报告分配给它的任务。工作节点向管理器节点通知其分配的任务的当前状态,以便管理器可以维持每个工作者的期望状态。
3.Service
一个服务是任务的定义,管理机或工作节点上执行。它是群体系统的中心结构,是用户与群体交互的主要根源。创建服务时,你需要指定要使用的容器镜像。
4.Task
任务是在docekr容器中执行的命令,Manager节点根据指定数量的任务副本分配任务给worker节点
------------------------------------------使用方法-------------------------------------
docker swarm:集群管理,子命令有init, ``join``, leave, update。(docker swarm --help查看帮助)
docker service:服务创建,子命令有create, inspect, update, remove, tasks。(docker service--help查看帮助)
docker node:节点管理,子命令有accept, promote, demote, inspect, update, tasks, ``ls``, ``rm``。(docker node --help查看帮助)
Swarm的工作模式
Node
Service
3.任务与调度
4.服务副本与全局服务
3、测试
在Swarm中部署服务(nginx为例)
#1、可以创建网络
# docker network create -d overlay nginx_net
#2、部署service
docker service create --replicas 1 --name my_nginx -p 88:80 nginx
# 就创建了一个具有一个副本(--replicas 1 )的nginx服务,使用镜像nginx
docker service ls
docker service inspect --pretty my_nginx
docker service ps my_nginx
#3、扩容
docker service scale my_nginx=4
docker service ps my_nginx
#4、模拟宕机查看效果
systemctl stop docker
docker node ls
docker service ps my_nginx
#5、Swarm 动态缩容服务(scale)
docker service scale my_nginx=1
#6、update扩缩容
docker service update --replicas 3 my_nginx
#7、update镜像升级
docker service update --image nginx:latest my_nginx
#8、服务移除
docker service rm my_nginx
#1、创建名为tomcat-net的覆盖网络(Overlay Netowork),这是个二层网络,处于该网络下的docker容器,即使宿主机不一样,也能相互访问:
docker network create -d overlay tomcat-net
#2、创建名为tomcat的服务,使用了刚才创建的覆盖网络:
docker service create --name tomcat \
--network tomcat-net \
-p 8080:8080 \
--replicas 2 \
tomcat:7.0.96-jdk8-openjdk
#3、执行命令docker service ls查看当前所有服务:
#4、执行命令docker service ps tomcat查看名为tomcat的服务,可见三个容器分别部署在m0、m2、w1机器上:
#5、执行命令docker service inspect --pretty tomcat查看名为tomcat的服务的详细信息(去掉--pretty可以看到更完整的):
#6、访问三个节点的tomcat,都能访问
#7、扩缩容
docker service scale tomcat=5
#8、滚动更新
docker service update \
--image tomcat:9.0.24-jdk11-openjdk \
--update-parallelism 1 \
--update-delay 10s tomcat
#update-parallelism:每次更新的容器数量,这里设置为1,表示每一个容器升级成功后才去升级下一个;
#update-delay:每一批升级成功后,升级下一批之前的等待时间,这里表示升级一个容器后等10秒再升级下一个;
#在升级过程中执行命令docker service ps tomcat查看服务,可以看到新版本容器逐个启动的过程:
#9、移除服务
docker service rm tomcat
服务模式
服务模式一共有两种:Ingress和Host,如果不指定,则默认的是Ingress;
- Ingress模式下,到达Swarm任何节点的8080端口的流量,都会映射到任何服务副本的内部80端口,就算该节点上没有tomcat服务副本也会映射;
- Host模式下,仅在运行有容器副本的机器上开放端口,使用Host模式的命令如下:
docker service create --name tomcat \
--network tomcat-net \
--publish published=8080,target=8080,mode=host \
--replicas 3 \
tomcat:7.0.96-jdk8-openjdk
默认swarm集群的所有部署,(3副本)。
manager节点负责调度,真正会在其他节点执行(创建副本)【默认worker优先,基本随机】。我们不知道我们的容器最终会发配给那个服务器。指定服务器,给他部署上去(label)。
1、ssd硬盘 ,数据存储,mysql。合适作为数据节点,存储节点
2、cpu厉害,适合作为计算,大数据,数据分析框架,就应该优先调度到cpu厉害的。hadoop存储之类的,就应该调度到ssd磁盘。
Drain a node:排空节点。把节点里面的容器驱逐出去。
In earlier steps of the tutorial, all the nodes have been running with ACTIVE availability. The swarm manager can assign tasks to any ACTIVE node, so up to now all nodes have been available to receive tasks. ACTIVE的节点,manager就可以分配任务进行部署。
docker node update --availability drain worker1
#这台机器用service部署产生的所有容器,都被驱逐出去了。当前docker就没有service的容器。但是集群为了保证副本数量会在其他机器拉起。
docker node update --availability pause worker1 #暂停接受给我的任务。
--availability active
#100 最好的状态,20台计算型的 。40台存储型的。30台冗余备份的
docker service hadoop --->调度到 40台存储型的;Label选择
# routing mesh;路由网
docker service create --name nginx -p 8080:80 --replicas 3 nginx
只要service是暴露端口的方式,全服务器都能访问。
#真正的nginx容器的ip
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP
link/ether 02:42:0a:00:00:12 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.18/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
34: eth1@if35: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth1
valid_lft forever preferred_lft forever
#集群状态下,每个主机都会多两个网络
43c75b51441f docker_gwbridge bridge local
o7b9pfkdt2ti ingress overlay swarm
ingress: "Subnet": "10.0.0.0/24", "Gateway": "10.0.0.1"
docker_gwbridge:"Subnet": "172.18.0.0/16"
集群状态下,service创建的容器默认加入两个网络。 docker_gwbridge 、 ingress
4、Docker Stack和Docker Compose区别
- Docker stack会忽略了“构建”指令,无法使用stack命令构建新镜像,它是需要镜像是预先已经构建好的。 所以docker-compose更适合于开发场景;
- Docker Compose是一个Python项目,在内部,它使用Docker API规范来操作容器。所以需要安装Docker -compose,以便与Docker一起在您的计算机上使用;
- Docker Stack功能包含在Docker引擎中。你不需要安装额外的包来使用它,docker stacks 只是swarm mode的一部分。
- Docker stack不支持基于第2版写的docker-compose.yml ,也就是version版本至少为3。然而Docker Compose对版本为2和3的 文件仍然可以处理;
- docker stack把docker compose的所有工作都做完了,因此docker stack将占主导地位。同时,对于大多数用户来说,切换到使用docker stack既不困难,也不需要太多的开销。如果您是Docker新手,或正在选择用于新项目的技术,请使用docker stack。
5、Docker Stack常用命令
命令 | 描述 |
---|---|
docker stack deploy | 部署新的堆栈或更新现有堆栈 |
docker stack ls | 列出现有堆栈 |
docker stack ps | 列出堆栈中的任务 |
docker stack rm | 删除一个或多个堆栈 |
docker stack services | 列出堆栈中的服务 |
推荐实验: https://blog.csdn.net/huangjun0210/article/details/86502021
6、swarm网络细节
在 Swarm Service 中有三个重要的网络概念:
- Overlay networks 管理 Swarm 中 Docker 守护进程间的通信。你可以将服务附加到一个或多个已存在的
overlay
网络上,使得服务与服务之间能够通信。 - ingress network 是一个特殊的
overlay
网络,用于服务节点间的负载均衡。当任何 Swarm 节点在发布的端口上接收到请求时,它将该请求交给一个名为IPVS
的模块。IPVS
跟踪参与该服务的所有IP地址,选择其中的一个,并通过ingress
网络将请求路由到它。
初始化或加入 Swarm 集群时会自动创建ingress
网络,大多数情况下,用户不需要自定义配置,但是 docker 17.05 和更高版本允许你自定义。 - docker_gwbridge是一种桥接网络,将
overlay
网络(包括ingress
网络)连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地 Docker 守护进程主机的docker_gwbridge
网络。docker_gwbridge
网络在初始化或加入 Swarm 时自动创建。大多数情况下,用户不需要自定义配置,但是 Docker 允许自定义。
名称 | 类型 | 注释 |
---|---|---|
docker_gwbridge | bridge | none |
ingress | overlay | none |
custom-network | overlay | none |
- docker_gwbridge和ingress是swarm自动创建的,当用户执行了docker swarm init/connect之后。
- docker_gwbridge是bridge类型的负责本机container和主机直接的连接
- ingress负责service在多个主机container之间的路由。
- custom-network是用户自己创建的overlay网络,通常我们都需要创建自己的network并把service挂在上面。
ingress网络。vip(虚拟ip模式)
https://docs.docker.com/engine/swarm/ingress/
查看网络的基本环境
yum install bridge-utils -y ##以后就可以brctl show 查看网关
iptables -nL -t nat ##查看转发规则
ln -s /var/run/docker/netns /var/run/netns ## 看容器创建的两个Net Namespace
ip netns ##查看Net Namespace
ip netns exec xxx ip add ##查看mynet网络命名空间下的网卡情况。
ip netns exec xxx brctl show ##查看mynet网络空间下网桥挂载情况可以看出veth0挂到了br0网桥上。
Docker Compose安装ES集群实战:
https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docker.html
Docker swarm 中的LB分为两种情况:
- Ingress Load Balancing:暴露端口方式的负载均衡。产生虚拟ip。转发链。
- Internal Load Balancing:内部的负载均衡。通过service的名字也可以访问吗?
自定义Service
the port where the swarm makes the service available outside the swarm
- docker service -p 8080:80
an overlay network for the service to connect to other services in the swarm
- docker service --network ?;同一个网络的跨机通讯
CPU and memory limits and reservations
docker service create
--limit-cpu decimal Limit CPUs --limit-memory bytes Limit Memory
a rolling update policy
- docker service create --update-delay 10s --update-parllelism 2
the number of replicas of the image to run in the swarm
- docker service create --replicas 3 --name nginx nginx:1.19
Replicated and global services
调整service以什么方式运行
--mode string
Service mode (replicated or global) (default "replicated")
docker service create --mode replicated --name mytom tomcat:7 默认的
docker service create --mode global --name haha alpine ping baidu.com
#场景?日志收集
每一个节点有自己的日志收集器,过滤。把所有日志最终再传给日志中心
服务监控,状态性能。
docker service create --name myredis --network myswarm-net redis
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
93: eth0@if94: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP
link/ether 02:42:0a:00:01:03 brd ff:ff:ff:ff:ff:ff
inet 10.0.1.3/24 brd 10.0.1.255 scope global eth0
valid_lft forever preferred_lft forever
95: eth1@if96: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.4/16 brd 172.18.255.255 scope global eth1;都是本机的
valid_lft forever preferred_lft forever
"Endpoint": {
"Spec": {
"Mode": "vip"
},
"VirtualIPs": [
{
"NetworkID": "xm5bv9m1yb5q5kfwl5sgbed0j",
"Addr": "10.0.1.2/24" #集群访问redis拿这个可以用
}
]
}
ping 容器的集群ip(10.0.1.3),service的集群vip(10.0.1.2),serviceName都通
3redis副本以后;容器ip 10.0.1.8、10.0.1.3、10.0.1.9。
无论多少个副本。一个service虚拟ip是固定的。负载均衡的方式。
建立redis集群。一个虚拟ip。sb应用和redis集群只要在同一个网络。直接写10.0.1.2,serviceName
docker service create --name mynettomcat --network myswarm-net tomcat
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
93: eth0@if94: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 02:42:0a:00:01:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.0.1.6/24 brd 10.0.1.255 scope global eth0
valid_lft forever preferred_lft forever
95: eth1@if96: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 172.18.0.4/16 brd 172.18.255.255 scope global eth1
valid_lft forever preferred_lft forever
docker service inspect mynettomcat
"Endpoint": {
"Spec": {
"Mode": "vip"
},
"VirtualIPs": [
{
"NetworkID": "xm5bv9m1yb5q5kfwl5sgbed0j",
"Addr": "10.0.1.5/24"
}
]
}
10.0.1.0/24
#1、他们两个能互相访问吗?有哪些方式。ip?serviceName?
#2、vip,dnsrr
docker service update --endpoint-mode dnsrr myredis
# docker inspect service就没vip了想要负载均衡。只能serviceName;
外部端口暴露负载均衡ingress。内部集群负载。vip。dnsrr
1、给docker集群部署服务的两种方式
docker service create xxxxx
2、使用compose文件
docker-compose up -d -c wordpress-compose.yaml;
效果:单机部署。自己产生默认的网络
docker stack deploy wordpress-compose.yaml;#集群部署,compose里面的所有服务会被发配到集群的各个地方
#写好docker-compose文件。运维人员部署即可。
version: '3.1'
services:
wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
volumes:
wordpress:
db:
#扩展。
集群下的数据一致。
redis,mysql等这些集群。数据本身挂载到本机(没有任何问题)。高可用,就是做mysql的集群。设置好集群内的数据同步,这是mysql集群技术解决的问题。而不是数据卷挂载解决的问题。
应用的资源文件。才应该考虑数据卷的集群情况下,如果本机挂载就不一致了。自己文件系统。
nfs;/abc ---> 远程的:/haha
Dockerfile
VOLUME ["/sss"] -->映射到docker /var/lib/docker/volumes
Docker Secret与Config
Secret
生产环境下,为了安全,我们不能把各项目的配置密码写入到配置文件
我们可以引入docker的secret方式保护密码。
场景
- 用户名密码
- SSH Key
- TLS认证
- 任何别人不想看到的数据
1、创建一个密码secret
2、用完就删
3、哪个服务想要使用只要暴露给他即可。
1、如何声明
#文本模式
printf 123456 | docker secret create my_secret -
echo "adminadmin" | docker secret create my-pwd -
#文件模式
docker secret create my_secret ./pwd
#Secret会基于raft在master主机之间同步。
2、如何使用
secret可以分配给一个service,就可以使用,secret在容器内部看起来是个文件,实际上在内存中
#1、普通情况
docker service create --name mysql --secret mysql_pwd -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pwd -p 3306:3306 mysql:5.7
#2、compose文件
version: "3"
services:
mysql:
image: mysql:5.7
ports:
- 3306:3306
secrets:
- mysql_pwd
enviroment:
- MYSQL_ROOT_PASSWORD_FILE: /run/secrets/mysql_pwd
原理:我们使用--secret mysql_pwd以后,secret密码文件就会被解码保存到容器内部的/run/secrets/secretname中。这样我们就可以在容器中任意使用。但是外部无感知。
不管怎么使用,secret最好提前创建好。到时候声明使用就行。其实是在内存中的。整个集群manager是利用raft同步的
config
1、如何声明
docker config create [OPTIONS] CONFIG file|-
docker config create redis.conf redis.conf
# 使用文件方式创建
docker service create --config redis.conf --name redis redis
#最终会被映射到容器的根目录。以后修改容器的启动命令即可
#配置中心
#部署100个redis副本。到100个服务器。他们配置文件都一样
#config内容base64编码,是可以inspect出来的。
secret文件是在容器中 /run/secrets/xxxx 暴露的
config默认是在根目录暴露的。
2、如何使用
#指定位置
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:
- mysql_pwd
enviroment:
- MYSQL_ROOT_PASSWORD_FILE: /
https://docs.docker.com/compose/compose-file/#configs
3、补充Label的使用
# 我们讨论了 Service 部署的两种模式:global mode 和 replicated mode。无论采用 global mode 还是 replicated mode,副本运行在哪些节点都是由 Swarm 决定的,作为用户我们有没有可能精细控制 Service 的运行位置呢?
答:能,使用 label
逻辑分两步:
1、为每个 node 定义 label。
2、设置 service 运行在指定 label 的 node 上。
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
8、扩展阅读
1、vxlan https://blog.csdn.net/tony_vip/article/details/100097245
2、lvs https://blog.csdn.net/tony_vip/article/details/104224374
其他填坑
Service Mode:服务模式。 Endpoint Mode:端点模式
1、集群的所有操作必须在manager节点执行
2、机器数量决定的业务体量
3、service就是一个业务,真正是以容器的方式运行在docker机器。服务副本指容器数量
打日志的时候,加上机器名就行。
Reference
- 《Docker 即学即用》/ (美)马迪亚斯(Matthias,K.),(美)凯恩(Kane,S.P.) 著;安道译. —— 北京:中国电力出版社,2015.12