(转) Docker - Docker1.12服务发现,负载均衡和Routing Mesh

 

看到一篇介绍 Docker swarm以及如何编排的好文章,挪放到这里,自己学习的同时也分享出来。

 

原文链接: http://wwwbuild.net/dockerone/414200.html

-----

Docker社区目前最热的话题莫过于Docker 1.12的发布, 明显的感觉就是大家都在讨论Docker 1.12的新功能,各种关于1.12的使用手册,文章,深度教程层出不穷, 一句话总结来说, 不知道Docker 1.12都不好意思跟人打招呼了。

个人理解Docker 1.12最大的功能莫过于SwarmKit的引入,这应该算是Docker发展里程碑式的一个Release(上一个里程碑应该是runC和Containerd的剥离,标志着Docker公司自己孤独地玩到容器标准化概念引入),自此再也不要说Docker是主机容器管理了, Docker已经能够管理一群主机上的容器了。概念上Docker引入了node、service、task甚至更高于service一层的stack, 自此大家会发现容器和网络已经不是Docker的first-class概念, 取而代之的是service、 stack和跨主机网络。Docker SwarmKit的引入给容器编排投入了一颗重磅炸弹, 给我的感觉是原来容器编排还可以这么玩,终于不要某某sos和某8s的全家桶了, 在容器编排的远古时代(其实也不远,就是观念陈旧)不装个五六七八个组件都不好意思跟人说是编排, 真的有这个必要么? 当然了, Docker Swarm主要功能还是是借鉴了“远古时代”的几款产品, 吸收了前人的优秀经验。 让我列几个牛哄哄的功能给大家吧:

  1. 内置Raft, 妈妈再也不用担心我还要依赖Zookeeper、Etcd、Consul了, 光部署这些东西就浪费我一整天外加三台机器。

  2. 不区分管理节点和Worker节点,想让谁上就让谁上, 猜想是参考了人家Nomad吧, 关键还能运行时Promote、Demote, 太方便了。

  3. Service,Stack外加DAB, 用过都说好, 方便。

  4. Rolling Update, Scale一个Service,灰度发布分分钟搞定(虽然有点鸡肋),这个不用说也是借鉴了Kubernetes。

一张图展示一下Docker1.12的和老版本的功能对比。

当然当前Docker 1.12的功能还很初级,还没有听说过有人大规模生产级的应用(据说能管理2000个节点,10W个容器),不过看的出来SwarmKit team新功能推出的速度还是相当快的。 个人很看好这一趋势。

下面分享一下Docker的一个服务是如何被外部访问的。

在没有Docker的时代我们更喜欢的两种办法来部署一个服务 1, 单个机器上的单个进程,绑定到固定IP上的固定端口, 这种方式的优点是简单明了,程序员同学们需要做的事情最大化的优化单个进程的处理能力, 保障这个进程不会因为各种问题退出, 因为一旦退出就没得玩了。 2, 单个机器上的多个进程绑定到固定端口, 前面放一个代理工具。

容器化后大家发现以前的做法或多或少需要做些调整, 第一,由于主机概念被弱化,集群概念被突出, 应用程序不再依赖某个主机或者某个端口; 第二, 容器生命周期不固定, 容器可以随时被启动被停止, 容器的数量可多可少(这就是我们常说的弹性)。由于上面提到的两个容器化的特性,一些新的问题被引入,聪明的工程师们想到了一些解决办法来应对这些问题, 第一个解决办法就是我们要谈到的服务发现,针对的问题是服务对外地址不定和服务随时被启动停止。 服务被发现以后要解决是如何把任务按照一定规则负载到容器中, 这就是第二个我们要谈的负载均衡。 负载均衡解决了单一入口负载到多个容器上问题, 但是由于容器调度之后可能落到多个机器上, 假如某些主机上面没有工作的容器,而对外服务时候又希望服务可以被访问, Routing Mesh概念引入是解决多个入口点负载到单个容器的问题。

服务发现

单纯的服务发现很好实现, 无非就是监测Container的启动、停止, 根据这些变动记录下服务到底可以通过哪些IP+端口可以被访问, 理论上实现一个初级的可用的服务发现不会超过十行代码。成熟的服务发现还需要额外的工作比如健康检查, 注意到我们之前是假设了容器启动就可以对外服务, 实际中情况可能远非如此, 一个应用启动之后可能要准备环境, 加载数据之后才可以对外服务,健康检查是保证服务可用之后再对外服务。 另外一个成熟的服务发现必备条件是高可用, 明眼人可能已经发现之前的简单版本不具备高可用和状态一致性, 这也是为什么Docker引入了Raft协议。

负载均衡

传统理解的负载均衡根据协议不同可以分为7层的和4层的, 7层负载均衡特点是可以支持很复杂的用户规则,比如HTTP header、Cookie等应用逻辑, 而4层只能支持到IP地址负载不同服务。

Docker1.12的服务发现和负载均衡是结合到一起的, 实现办法有两种,DNS轮询和IPVS。 理解这两种策略之前需要知道的一个前提是Docker为每个服务都分配了一个虚拟IP, 这个IP对应的不是具体的一个Task或者一个具体的Container,而是专门为一个服务保留。

下面我们举例子分别说明一下两种负载均衡实现:

首先准备一下环境。

第一步如下图所示用Go写一段小代码, 编译成二进制放在一个ubuntu基础镜像里, 同时我的ubuntu里面安装了一些基础的网络工具, 比如dig、curl、 ping等, 保存成镜像ubuntu-base。


第二步, 根据Docker官方安装文档 我们在虚拟机环境里启动两个虚拟机, 构造一个Docker Swarm集群。

第三步, 创建一个Overlay网络, 取名overlay-test。

下面我们试一下DNS轮训模式的服务发现和负载均衡, 设置一个服务使用DNS轮询还是VIP, 只要设置好endpoint-mode这个参数就好, 如下图所示:

使用下面命令启动我们的服务:

docker service create –network overlay-test –name demo –replicas=4 –endpoint-mode=dnsrr ubuntu-base

—network overlay-test是指定使用刚刚创建的Overlay网络, –replicas=4 指定task数量, –endpoint-mode=dnsrr使用dnsrr方式做负载均衡。

启动成功后如下图所示:

当前机器上运行docker ps会发现有只有两个容器生成, 原因是另外两个task被调度到另外一台主机上。

下一步我们考虑进入容器中看一下虚拟出来的网络情况。

我们之前明明指定了使用overlay-test网络, 按理应该只有两块网卡, 实际上Docker却为我们生成了4块, 多出来的两块是Docker为容器做的手脚, 让我来一一讲解为什么会有4块网卡的出现。

  1. lo网卡不用多说, 是本地网卡, 也叫回环网卡;

  2. eth2属于之前创建的overlay-test网络;

  3. eth1和docker_gwbridge网桥构成的网络可以使容器内的服务可以在主机上访问, 主机上telnet 172.18.0.4可以访问到我们的服务,如下图:

  4. eth0是ingress网络中的一块网卡, 是为了Routing Mesh而设,稍后我们会详细说明。

继续回到容器里面看我们查看一下服务情况, 执行命令:


大家会发现通过服务名或者容器ID都能找到IP地址, 区别是服务名发现了本机上所有提供服务的容器IP, 至此同时实现了服务发现和内部负载均衡。

以上就是通过DNS轮询实现的服务发现和负载均衡, 这样的负载均衡是有一些缺点的, 比如:

  1. 一些应用可能缓存DNS请求, 导致容器变化之后DNS不能实时更新;

  2. DNS生效时间也导致不能实时反映服务变化情况;

  3. 由于以上原因导致的负载均衡不够准确。

下面我来演示一下VIP和IPVS模式的服务发现和负载均衡。 VIP和IPVS原理上比较容易理解, 就是Docker为每个服务分配了一个VIP, DNS解析服务名称或者自定义的别名到这个VIP上。

由于VIP本身没有容器提供服务,Docker把到VIP的请求通过IPVS技术负载到后面的容器上。

Docker发布一个服务时候默认会选择VIP模式, 下面我们用同样的镜像演示一下。

docker service create –network overlay-test –name demo –replicas=4 –endpoint-mode=vip —publish 8080:8080 ubuntu-base

启动服务之后我们inspect一下, 会发现Virtual IPs有两个入口, 期中10.0.0.2就是overlay-test网络下面的一个Endpoint, 这个Endpoint是服务而非容器的。

我们进入容器中执行dig命令会发现:

此时DNS解析出来的是一个虚拟地址, 虚拟地址通过IPVS和一系列的iptables规则动态转发到容器中。 这样的负载均衡屏蔽了DNS轮询的时效性问题,同时可以支持UDP等协议, 性能也非常好。 缺点是不能做比如回话保持, 基于URL等应用层协议的规则的转发。

下面聊聊Routing Mesh, Routing Mesh的目的是每个主机上都为服务预留端口, 保证每台机器上都可以访问到服务。实现的办法就是Ingress网络, 之前我们提到容器中会多出一块网络,我们Inspect ingress网络,同时会发现网络对应的容器上多出一个容器 ingress-sbox

一个请求到主机端口8080之后, 数据包的流向如下所示:

主机端口8080 => Ingress-sbox-VIP:8080 => 容器Ingress-sbox => IPVS分发到containers。

大家可以看到访问主机之后数据包流到了一个特殊的Sandbox容器里, 这个容器和我们的容器共享一个Ingress网络,通过Iptables和IPVS等重定向到了最终容器之上。 达到了服务在任何一台主机的8080端口都可达的目的。

已上就是我理解的Docker SwarmKit的几种功能, 一些新的网络技术大家也在讨论,比如Macvlan和Ipvlan等, 通过这些技术Docker的应用场景越来越丰富, 越来越成熟, 让我们拭目以待。

 

国内首个基于Docker SwarmKit的容器管理面板——数人云Crane第一版最新出炉,欢迎点击“阅读原文”申请体验,点赞or吐槽都可以。

posted @ 2017-01-11 09:13  TonyZhang24  阅读(2884)  评论(0编辑  收藏  举报