Docker swarm中的LB和服务发现详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker swarm中的LB和服务发现详解相关的知识,希望对你有一定的参考价值。

参考技术A

Docker 提供了 overlay driver,使用户可以创建基于 VxLAN 的 overlay 网络。VxLAN 可将二层数据封装到 UDP 进行传输,VxLAN 提供与 VLAN 相同的以太网二层服务,但是拥有更强的扩展性和灵活性。linux下是使用了net namespace来隔离docker创建的overlay网络。

Docker 网络模型如下:

一个Sandbox包含了一个容器网络栈的配置。其中包括了对容器的网卡,路由表以及对DNS设置的管理。通常,一个Sandbox的实现可以是一个Linux Network Namespace,一个FreeBSD Jail或者其他类似的东西。一个Sandbox可以包含多个处于不同Network的Endpoint。

Endpoint将一个Sandbox加入一个Network。Endpoint的实现可以是一个veth对,一个Open vSwitch internal port或者其他类似的东西。一个Endpoint只能属于一个Network和一个Sandbox。

Network是一个能够互相通信的Endpoint的集合。Network的实现可以是一个Linux网桥,一个VLAN等等。

上图展示了task1.client请求两个不同资源dns返回的不同结果

环境:
swarm-a(manager node):10.10.8.92

swarm-b(work node):10.10.8.93

swarm-c(work node):10.10.8.94

在docker swarm集群创建的开始,docker 会给每台host创建除了docker0以外的两个网络,分是bridge类型(docker_gwbridge网桥)和overlay类型(ingress)的网络,以及一个过度的命名空间ingress_sbox,我们可以使用如下命令自建overlay网络,结果如下:

docker network create --driver overlay mynet (后续会有用到)

注意1:要是想看到容器创建的两个Net Namespace需要执行
ln -s /var/run/docker/netns /var/run/netns

1)、部署一个service使用默认的ingress网络:

docker service create --name web_ingress_lb --replicas=2 --publish 8090:80 httpd

2)、Ingress Load Balancing实现方式:

这样一来即使容器的副本没有落到host上我们仍可以通过这种转发方式来访问到服务。这应该就是routing mesh吧!

1)、部署一个service使用我们自己创建的mynet网络:

docker service create --name web_mynet --replicas=2 --network=mynet --publish 8080:80 httpd
部署的两个容器分别处在a和c节点上:

结合例子如下:

2)、查看web_mynet.1容器和mynet网络命名空间的网卡情况:

3)、查看web_mynet.1容器和ingress\\ingress_sbox网络命名空间的网卡对应情况:

可以看mynet网络下vlan-id 为4097,ingress网络空间同样操作可以得到vlan-id为4096

swarm-c节点上的情况也是差不多就不操作了,好了我们来画下网络连接的大致图:

可以看到这里ingress_sbox和创建容器的ns共用一个ingress网络空间。

4)、 Internal Load Balancing实现方式:

有两种实现方式dns rr和vip形式,在dns rr 的情况下可能会存在一定是的问题,当容器重启后dns的解析会存在一定时间的延迟。vip则是由vip+内核ipvs来实现。docker swarm默认使用的是vip,这里就以vip的形式来解析。(想要了解dns rr的可以看文章后面的参考链接都是大牛写的)

VIP形式下的流量路径:

操作流程如下:
通过busybox服务做dns解析,可以发现该服务后端挂载的容器和该服务对应的
VIP地址。web_mynet服务对应的VIP为10.0.0.6。

在Internal Load Balancing也就是文中我们自建的mynet overlay网络中,我们会看到创
建的service会同时应用到两个网络环境里面去,为何要这样呢?

原因是swarm自带ingress不具备有服务发现的功能,而容器的生命周期又是不固定的,
service每次的消亡和启用都会改变容器内部的ip地址以及vip地址,那么集群中服务之间
的通信势必会造成问题,这里有人会说,要使多个service之间能够互相通信可以将所有
的service都publish出去,然后通过routing mesh 访问,这样是没错也能行得通,但是存
在一个缺点,那就是不安全,我们仅仅只需要的是将最终提供服务的端口publish即可。
那么不publish所有的service需要做到以下几点:

这里我理解的是ingress是单单提供LB实现routing mesh而mynet是服务发现和LB的结合

所以上文中Internal Load Balancing中的数据流应该分成两种情景如下:

1、当一个外部请求到主机端口8080之后, 数据包的流向如下所示:
主机端口8080 => Ingress-sbox-VIP:8080 => 容器Ingress-sbox => IPVS分发到containers。

2、处于 同mynet网络的service内部通信时:
处于 同mynet网络的test service(busybox容器)发起访问web_mynet域名的请求=>请求转发到docker engine内置的DNS解析web_mynet的vip=>web_mynet(容器)在其ns中将
VIP数据包打上标签,并通过ipvs来负载到后端对应的容器=>数据包通过vip地址路由到
mynet的ns,由mynet中的fdb来做转发走tunnel出去。

https://zhuanlan.zhihu.com/p/25954203

https://www.jianshu.com/p/4433f4c70cf0

https://docs.docker.com/network/overlay/

http://julyerr.club/2018/03/20/docker-swarm/

docker深入2-基于 swarm mode 的服务发现和注册

docker深入2-基于 swarm mode 的服务发现和注册

2017/9/4


注:【未完待续】标签,表明现在没空继续研究,后续再补上,现在先分享出来,或许有朋友正需要思路和帮助。

一、前言
1、目的
1)研究基于 swarm mode 的服务发现和注册
2)熟悉使用 go 和 python 来写 agent 调用 docker api/sdk 来达到上述目的。
3)docker api/sdk 参考
 * docker api and sdk exp
 * api ref: https://docs.docker.com/engine/api/v1.3
 * sdk go: https://godoc.org/github.com/moby/moby/client

 * [howto]
 * # curl -s --unix-socket /var/run/docker.sock http:/v1.30/nodes |jq . |more
 * # curl -s --unix-socket /var/run/docker.sock http:/v1.30/services |jq . |more
 * # curl -s --unix-socket /var/run/docker.sock http:/v1.30/tasks |jq . |more

4)示例参考
https://github.com/opera443399/ops/blob/master/doc/Go/src/abc.com/demo/docker_api_exp/app.go
https://github.com/sergkh/docker-etcd-registrator/blob/master/register.py



2、数据流
docker service -> swarm mode manager -> my_test_etcd_registrator -> net_etcd -> LB+confd


3、示例 sergkh 的解决方案
4、参考示例后,自己的解决方案



二、示例 sergkh 的解决方案
1、创建独立的网络
docker network create --driver overlay net_etcd

注1:使用默认的 overlay 网络时,通过服务名无法互相ping通
注2:但通过 docker compose 创建 service 时,默认会创建一个独立的 overlay 网络


2、启动一个 etcd 服务
docker service create --name my_test_etcd     --network net_etcd     --publish 2379:2379     --publish 2380:2380     --detach=true     --constraint ‘node.role == manager‘     quay.io/coreos/etcd:latest etcd      --advertise-client-urls http://my_test_etcd:2379      --listen-client-urls http://0.0.0.0:2379

    
    
3、测试 etcd 服务是否工作
curl 127.0.0.1:2379/v2/keys/
curl -X PUT 127.0.0.1:2379/v2/keys/services -d key1=‘value1‘
curl 127.0.0.1:2379/v2/keys/services


4、服务注册
docker service create --name my_test_etcd_registrator     --network net_etcd     --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock     --env ETCD_HOST="my_test_etcd"     --env ETCD_PORT="2379"     --env BASE_DIR="/service"     --env UPDATE_INTERVAL="30"     --env RUN_ONCE="False"     --detach=true     --constraint ‘node.role == manager‘     sergkh/docker-etcd-registrator
    
    
5、服务发现
(未完待续,后续有空实现后再更新)


6、问题
1)sergkh 的 docker-etcd-registrator 服务中 python 脚本提取的内容可能不符合我的需求,后续将 fork 后改成自己需要的版本。
https://github.com/sergkh/docker-etcd-registrator/blob/c294b60cfb49a5213d9942b2ef4f99827435c182/register.py#L30
                descr[‘address‘] = ‘{0}:{1}‘.format(service.name, ports[0][‘TargetPort‘])
                
这里使用的是 TargetPort 而我需要的是 PublishedPort




三、参考示例后,自己的解决方案
(有时间实现后再补充)
1、TODO
实现一个服务注册的 agent 
实现一个服务发现的 agent








    
    
ZYXW、参考
1、https://github.com/sergkh
https://github.com/sergkh/docker-etcd-registrator
https://hub.docker.com/r/sergkh/nginx-autoproxy/
2、docker api
https://docs.docker.com/engine/api/v1.3
3、docker sdk go
https://godoc.org/github.com/moby/moby/client


以上是关于Docker swarm中的LB和服务发现详解的主要内容,如果未能解决你的问题,请参考以下文章

docker深入2-基于 swarm mode 的服务发现和注册

【docker swarm】docker swarm 中的网段冲突问题

如何使用未部署在 swarm 中的 docker 容器从 docker swarm 访问服务?

Docker集群实验环境布署--swarm3 注册服务监控与自动发现组件--consul

Docker Swarm

【swarm】Docker swarm 的负载均衡