通过前面的介绍,我们已经可以管理docker了,但是如果把docker用于生产,一两个机器还好,如果是多台,甚至是一个集群环境,我们不可能一台机器一台机器的部署,就算可以也没办做到“高可用”,这时docker-swarm就诞生了,他可以把多个docker engin做成一个集群环境来管理。
docker-swarm在docker1.12之前是一个独立的项目,需要单独下载,在1.12之后就和docker合并做为docker的一个子命令。同时docker-swarm也是唯一的docker原生支持集群的管理工具。
我们看一下下面的图
filter和Strategy都是调度模块(过滤选择最优的模块来部署)
1、Constraints(约束过滤器):根据当前系统版本、内容版本,进行一些指标上的过滤。当然也可以自定义,在deamon启动的时候可以通过lab来制定当前机器所具有的特性,然后通过Constraints把他们过滤出来。
比如我们创建了一个registry,重新部署的时候我不希望这个镜像让swarm随机分配,还要安装在以前的节点上,可是这么使用:
docker service create --name registry --publish 5000:5000 --constraint 'node.hostname==node01' registry
除了 hostname
也可以使用其他节点属性来创建约束表达式写法参见下表:
节点属性 | 匹配 | 示例 |
---|---|---|
node.id | 节点 ID | node.id == 2ivku8v2gvtg4 |
node.hostname | 节点 hostname | node.hostname != node02 |
node.role | 节点 role: manager | node.role == manager |
node.labels | 用户自定义 node labels | node.labels.security == high |
engine.labels | Docker Engine labels | engine.labels.operatingsystem == ubuntu 14.04 |
用户自定义labels可以使用 docker node update
命令添加, 例如:
# docker node update --label-add security=high node01
查看自定义labels
# docker node inspect node01
[
{
"ID": "0nhjsflo3tbd0b7hv2cyrjpin",
...
"Spec": {
"Labels": {
"security": "high"
},
"Role": "manager",
"Availability": "active"
},
"Description": {
"Hostname": "node01",
"Platform": {
"Architecture": "x86_64",
"OS": "linux"
},
...
}
]
对于已有service, 可以通过 docker service update
,添加 constraint
配置, 例如:
docker service update registry --constraint-add 'node.labels.security==high'
2、affinity(亲和过滤器):比如说一个web服务我想把它和数据库放在一起,就可以使用这个。
3、dependency(依赖过滤器):比如说,容器有link、from这些依赖关系,dependency就会把他们放在一个节点上
4、Health filter:根据健康状态来过滤,会过滤掉一些有问题的节点
5、Ports filter:根据端口的使用来选用,比如说8080端口已经被一个机器使用,他会分配到没有使用的节点。
Binpack:同等条件下他会选择资源使用最多的做为选择
Spread:同等条件下他会选择资源使用最少的做为选择
Random:随机选择一个节点
docker内置overlay网络,overlay是什么呢?我们要做到跨主机的网络通信,其思路无非分为两种: 二层VLAN网络和Overlay网络
VLAN就不介绍了,我们主要说overlay
容器在两个跨主机进行通信的时候,是使用overlay network这个网络模式进行通信;如果使用host也可以实现跨主机进行通信,直接使用这个物理的ip地址就可以进行通信。overlay它会虚拟出一个网络比如10.0.2.3这个ip地址。在这个overlay网络模式里面,有一个类似于服务网关的地址,然后把这个包转发到物理服务器这个地址,最终通过路由和交换,到达另一个服务器的ip地址。
要实现overlay网络,我们会有一个服务发现。比如说consul,会定义一个ip地址池,比如10.0.2.0/24之类的。上面会有容器,容器的ip地址会从上面去获取。获取完了后,会通过ens33来进行通信,这样就实现跨主机的通信。
下面是慕课网的解释:
Docker 使用了 Linux 内核 iptables 和 IPVS 的功能来实现服务发现和负载均衡。
iptables 是 Linux 内核中可用的包过滤技术,它可用于根据数据包的内容进行分类、修改和转发决策。
IPVS 是 Linux 内核中可用的传输级负载均衡器。
作者:www说
链接:https://www.imooc.com/article/49017
来源:慕课网
我们先看一下docker默认的网络环境:
然后我们使用swarm创建一个集群环境
docker swarm init --advertise-addr 192.168.1.120
如果我们机器上有多个网卡要使用--advertise-addr传入本地的ip
在看一下环境:
可以看到我们多出来一个name为ingress的网络,我们知道overlay是做什么的,那igress是什么意思呢?
我们在用两个node来加入到这个集群中
docker swarm join --token SWMTKN-1-2khwrs5e07m54r83644qbdmmn38q7cvo591k0u016jfb3t9yrs-emnr9fi6eiokpmozoa623qkvh 192.168.1.120:2377
在看一下现在的node
docker node ls
在运行nginx服务
docker service create --name mynginx --publish 8080:80 --detach=false nginx
docker service scale mynginx=4
docker service ls
启动了四个副本
看一下是否负载,我们别分把这些副本的nginx欢迎页面改了
docker service ps vhufcpae3jid
我到node1、node3、master三台宿主机分别修改页面
我们到node3上修改这个容器里的页面,命令如下:
修改就按编号修改就可以了
echo 'mynginx.4' > /usr/share/nginx/html/index.html
剩下的同理
可以看到负载成功了,那么每个容器之间是否能ping通呢?
因为nginx镜像中是没有ping的,我们在创建一个服务
docker service create --name myalpine --detach=false alpine ping 192.168.1.1
一定要带着ping 192.168.1.1要不这个容器没有前台进程是起不来的!
我们看一下这个容器在哪使用
docker service ls
docker service ps t2smto1g7uma
这个容器是在docker3上,我们在docker3中进入这个容器
看看wget能不能下载到这个页面
可以看到内层网络我们是ping不通的,那我们如何能在内容使用服务名来互相通信呢?
下面介绍两种方法
1、自定义网络
因为在自定义的网络上,swarm mode会分配给每个容器一个dns engin,这个网络必须是自定义overlay的,当访问的时候就会经过节点的dns server然后rourt 到每个容器上
下面我们创建一个网络
docker network create -d overlay overlaytest
查看
然后我们把刚才的实现步骤重新来一遍,先停下现在所有的服务,然后启动服务到overlaytest网络上
停止服务
创建服务
ping外部网络
ping服务名
ping内部网络
下面在介绍第二种方法
2、DNSRR模式
我们先看一下上面的容器
可以看到有一个Endpoint-Mode,他们都是vip,那这个VIP是什么意思呢?
他的作用指定swarm服务发现的模式
上面红字不就是我们需要的模式么?下面配置一下,这次试用docker stack
docker stack是什么?如果你知道docker 和docker compose的关系就知道了,他就好像是docker service的打包版,他和compose都一样需要一个yml文件,下面我们去编写这个文件
version: "3.4" #版本号用最新就可以
services:
alpine: #服务的名字
image: alpine #下载的镜像
command: #执行命令
- "ping"
- "192.168.1.1"
networks: #采用哪个网络,不写则是默认
- "overlaytest"
deploy:
endpoint_mode: dnsrr #mode的模式
replicas: 2 #创建的副本数
restart_policy: #重启的机制
condition: on-failure #失败就重启
resources: #资源
limits:
cpus: "0.1" #cpu
memory: 50M #内存
depends_on:
- nginx #依赖关系
nginx:
image: nginx
networks:
- "overlaytest"
ports:
- "8080:80"
networks:
overlaytest:
external: true #他是一个外部定义好的
我们停止当前所有服务
docker service rm `docker service ls -q`
执行创建服务
docker stack deploy -c service.yml test
我们可以看到他会在所有服务前加上“test_”
我们测试一下
ping 服务名
内部网络
但是这里要注意:
dnsrr模式是不开放端口的,因为dnsrr是只是供内部间使用名字调用的
我们总结一下这三种形式
一、ingress默认网络(VIP模式):我们可以通过外端ip+端口进行通信,不能通过服务名进行通信。
二、ingress自定义网络(VIP模式):这个比较宽泛可以使用服务名,可以使用内部网路,也可以使用宿主的网络。
三、dnsrr模式:这个我们最好应用在一些只使用内部服务名的容器通信间进行使用。
到底决定使用哪个网路应该还是要看具体的环境和业务需求吧。
https://blog.csdn.net/wanglei_storage/article/details/77508620
这里写的比较全
https://www.jianshu.com/p/25c529e3a3e6