架构师小组交流会:每期选一个时下最热门的技术话题进行实践经验分享。nginx
第一期主题:容器实践。Docker 做为当前最具颠覆性的开源技术之一,其轻量虚拟化、可移植性是CI/CD,DevOps,微服务的重要实现技术。但目前技术还不够成熟,在生产实践中会遇到很多坑。本期参与小组交流的是国内较早采用 Docker 实践的公司。docker
参与嘉宾:沪江架构师黄凯、滴滴架构师田智伟、蘑菇街架构师张振华、蘑菇街运维架构师向靖、七牛技术总监袁晓沛、扇贝技术总监丁彦安全
第一轮:自由交流服务器
沪江黄凯:你们好,我是来自沪江的 Java 架构师,我叫黄凯。在加入沪江以前,曾在 HP 和 IBM 的云计算部门担任核心开发和架构职位。对 IaaS、Paas、SaaS,尤为是云存储有较深刻的了解。2015 年加入沪江,担任架构师职位,主导的产品有:课件云存储,云转码等等。在这些项目中,咱们使用 Mesos 和 Marathon 作 Docker 的编排工具,并开发了一个 Mesos Framework 作云转码的核心框架。网络
那么咱们为何要使用 Docker,也是机缘巧合。因为咱们的服务开始的时候不是特别多,采用的就是一种普通的架构,后来随着服务的增多,发现部署和运维花的时间太长,咱们想使用一些新的方式。开始的时候研究过 Openstack,后来以为 Openstack 慢慢没落,因而咱们就选中如今使用的 Docker。咱们并不把 Docker 当成 VM 在用,而是使用它的原生的,在 Baremetal 上直接安装 Docker,这样运行效率比在 VM 运行 Docker 要来的快。课件云是由不少微服务组成,不光是一些存储,这种微服务是使用 Docker 部署,就至关于编排,把这些微服务部署上去。转码这一块是使用了 Mesos 框架,和 Docker 没有特别大的关系,可是转码的应用程序,好比说咱们如今应用 FFmpeg,这个程序是运行在 Docker 里面的。架构
为何要选择 Marathon?第一,我以为 Mesos+Marathon 很是的容易理解。咱们也研究过 Kubernetes 和其余的一些方法,发现从运维和研究的方面来讲的话,Kubernetes 实在是过重并且太复杂,后来选择了Marathon。咱们如今是内部服务使用,两个部门在使用转码集群,大概是 Baremetal 有 20 台的物理机。除去咱们 API 的一些服务,还有一些第三方组件的服务的话,大概是有 400 多个 Docker 容器在跑。并发
滴滴田智伟:你们好,我是滴滴代驾事业部架构师,代驾事业部是公司最先尝试 Docker 虚拟化的事业部。目前主要方向是业务系统及部分中间件的 Docker 化,咱们作的时间也不太长,半年多的时间。线上是由于咱们有老的一套发布系统,集成涉及的部门比较多,因此咱们基于原来的发布系统完成了预发布环境 Docker 的部署。线下环境基于 Docker+K8s 开发内部的自动化持续交付系统及开发测试环境管理。咱们在作开发和测试环境的自动化,另外一方面也是作环境管理的,两套环境。对于项目并行的时候发现原来不少不够用,原来不少配置是基于端口绑死的状况。如今基于开发 Kubernetes 的话,网络隔离用了一部分,而后主要是用环境变量这一部分,主要考虑是解决一个配置能够应用到在多个环境的状况,基于这个需求才用它。开发 Kubernetes 基于 Namespace,同一个服务在不一样的 Namespace 下,它其实环境变量名能够是相同的,可是IP不一样,而这一部分 IP 实际上是由开发 Kubernetes 本身去管理的。基于环境变量获取一些配置的话,好比 IP 地址这种,就能够作到拿一份配置能够打出多套环境。app
考虑业务的安全性和稳定性,线上基于纯 Docker 的方式在作。咱们是基于裸的 Docker 来工做,主要是用资源隔离,没有借助调度框架,也没有自动伸缩。咱们是两步走,一步是验证 Docker,其次是作开发 Kubernetes 线下使用和预研。为何没有考虑 Mesos?刚才跟沪江的同窗,咱们的考虑是相反的。Mesos 侧重点更专注一点,首先不会有模块的划分,好比 Kubernetes 有 Replication controller ,Namespace 这种概念,而 Mesos 下几乎没有这种概念。咱们拿 Kubernetes 主要是作一些编排的功能,而正好开发 Kubernetes 在整个发布和编排上,体系更全面一点。Mesos 最先是作资源管理,基于 Docker 作一个 Framework 接进来的话,它不是专门为编排而生。Kubernetes 首先解决咱们的问题是,咱们可能不须要加多份配置就能够搭多套不一样的环境,它就是基于 Namespace 作一个多租户的概念,会对 Service 作一层隔离,对于动态配置,扩容这一部分暂时咱们没用到,确实用到的一些场景比较少。主要是作不一样环境的隔离,并无太多使用编排细节上的东西,动态伸缩之类的目前线下没有太大必要,线上可能会用到。框架
蘑菇街向靖:你们好,我是子骞,来自蘑菇街的运维架构师。咱们接下来会作一个 Paas 平台,想作 Docker 和结合虚拟机以及咱们用到公有云产品,作成一个混合云的架构平台。咱们如今 Docker 也在用,更多的是当虚拟机用,后面咱们想基于 Docker 原生的方式去用,可能会涉及资源调度,服务发现的问题。除了 Docker,咱们还会用到公有云,公有云更可能是虚拟机的方式提供。出于混合云,想在资源层作一个抽象,对于上层业务来说它没有关系,它是跑在 Docker 上,仍是云主机上,仍是 KVM 虚拟机上,那么我想在这上面作一个抽象。另外还有,刚才我也是提问滴滴架构师的问题,配置怎样和代码作隔离,这个也是我考虑的问题。由于我看 Docker 用了环境变量,经过环境变量作一些配置的参数的传递,可是在虚拟机上,特别是在物理机上,经过环境变量的方式,我还在考虑有没有安全的风险,Docker 多是一个只读的,不会被修改的,可是对于虚拟机以及物理机来讲,可能会存在被修改的风险。运维
蘑菇街张振华:你们好,我叫张振华,花名郭嘉,我是 14 年从思科加入蘑菇街。咱们算是国内用 Docker 比较早的,咱们一开始用 Docker 是 1.3.2 的版本,当时咱们采用集群管理工具仍是Openstack,由于当时 Kubernetes 还不是很成熟。当时也走了一些弯路,好比咱们把 Docker 当成虚拟机来用,曾经在线上的规模也达到几百台虚拟机几千个容器,可是咱们逐步发现不能把 Docker 当成虚拟机来使用,所以咱们作了一个转型,从去年开始研究 Kubernetes,如今 Kubernetes 加 Docker 的版本开发完成了,准备逐步上线。
咱们为何选用 Kubernetes?编排工具的选择咱们也是作过一番调研的,它们没有谁好谁很差这一说,只能说谁更贴切你的需求。对于咱们蘑菇街来讲,咱们须要解决是资源利用率的问题,和运维的对接,咱们须要有预发和线上环境的持续集成持续部署的过程,还有咱们须要有对资源的隔离,对部署的快速迭代,包括集群管理,这些方面,咱们以为 Kubernetes 更加适合于咱们。
在网络方面,咱们研究过如今在开源界比较经常使用的一些方案,可是咱们都以为不太适合,比较 Fannel,Caico 等等,他们通常用的技术都是 Vxlan,或者是用 BGP。由于咱们以前对 Openstack 的网络是比较有经验的,而后咱们发现有一个项目,具体名字不记得,Neutron 和 Kubernetes 作一个对接,咱们在这个项目的基础上作了 Vlan 的方案,咱们的网络没有用 Vxlan 来作,而是选择 Vlan 来作,这样的话一个 Docker 它能够得到跟一个物理理同一个网络平面的 IP,咱们的应用程序能够直接对外访问,由于咱们内部业务有这个需求选择这个方案。虽然 Docker 内部网络和外部网络是通的,但 Docker 仍是独立的一个网段,不须要一层 NAT 的转换。咱们直接走二层的,是在交换机走 Chunk,原本物理机交换机的 Access 口,这样的话,一台物理机上面容许跑多个vlan的容器,好比说 A业务和 B业务要走隔离的话,经过网络的 Vlan 走隔离,它们的数据之间不会有干扰。
Load Balance 咱们尚未涉及到这一块,Load Balance 咱们应该会在 nginx 上作一层。由于据我了解,如今 Kubernetes 这一块 Proxy 还不是很成熟,这上面还存在一些问题,所以还不敢用 Kubernetes 现有提供的服务。服务发现和注册这一块咱们还在作开发,这块会和配置管理中心打通。咱们内部也有其余团队在作这些功能,因此咱们会和内部的中间件团队合做。
七牛云袁晓沛:你们好,我是七牛云数据处理技术总监袁晓沛。咱们的数据处理业务包括了图片和视频的实时在线及异步处理。数据处理的业务量比较大,日均请求量达到百亿级。平台采用容器技术的缘由是借助容器技术快速部署,启动的特性,数据处理程序能够根据数据处理量快速地弹性伸缩。借助容器技术内核级别的资源隔离和访问控制,每一个数据处理程序能够运行在一个私有的环境,不被其它程序所干扰,保证其上运行数据是安全可靠的。并且容器技术是轻量的,它以最小的资源损耗提供资源隔离和访问控制,而资源特别是计算资源在数据处理中是很是宝贵的。
咱们在资源调度上采用的是 Mesos,而二层的业务调度框架则是本身自研的。七牛自身拥有近千台的物理机,容器是直接运行的物理机上,能够减小虚拟层对资源的消耗,提升资源的利用率。
在网络上,对于七牛的自定义数据处理服务直接使用的是 Host 模式,而对第三方数据处理服务则使用的是 Bridge 模式,由于这些程序是用户本身部署运行的,并不知道用户是否有开启其余的端口使用,因此使用的是 Bridge 模式,须要对外使用端口的都须要经过 NAT 进行暴露,这样服务内部使用了什么端口并不会对外界环境形成影响,对平台环境作了很是好的安全隔离。咱们是使用 Consul 作注册中心,支持跨数据中心的服务发现。咱们为何自研的调度框架,而不用 Marathon。由于 Marathon 不支持跨数据中心的内部服务或外部服务的发现,而七牛有多个数据中心,影响总体的调度,其次若是选用 Marathon 的话,根据咱们业务的特色,仍是要再作一层对 Marathon 的包装才能做为 Dora 的调度服务,这样模块就会变多,部署运维会复杂。
扇贝丁彦:你们好,我是扇贝的技术总监丁彦,以前在暴走漫画,前后在暴走漫画和扇贝设计和主导了基于 Docker 的微服务架构系统,以及数据收集和分析系统。去年来到扇贝,这里是 Python 的开发环境。后来发现业务增加快,水平扩展一些机器,出现问题须要换个机器等等,都须要很是熟悉业务的少数开发去作。另外公司对预算控制严格,机器基本都是满负荷运做,平时也不可能多开空置的机器,已有的机器还要根据负载状况调整服务分布状况,因此这种切换服务,增删服务的操做仍是比较频繁的。所以,咱们用了2-3个月的时间将全部的运行环境都切换到 Docker上,这大大提升了咱们的运维能力。
Docker 包装有几个好处。
第一个好处是,环境升级很是方便。由于只要pull 一下最新的镜像,启动一个 Container,环境就升级了。而若是直接基于公有云的镜像升级的话就很难,由于一台机器上跑哪些服务其实不必定是固定的,而且以前作的镜像只要有一台机器是还基于它的话,就删除不掉的,镜像数量又有上限。因此docker 很是好地解决了咱们的问题。
其次是环境的颗粒度会更小,一台机器上配好几个应用的话,每每配着配着,到最后你就不太能精确地记得上面装的程序或者库是给哪一个应用服务的,应用之间若是依赖有版本的冲突也很难调和。你想作些服务的迁移,把负载比较小的放一块儿,把负载比较大的抽出来,这个时候就很是痛苦,但你若是用 Docker 包装后就很是简单,只要在不一样的机器上起不一样的 Container,就能够实现这一点。
第三,咱们不光用了 Docker,还加入了服务发现,刚刚讨论配置管理这些,咱们一并作了。Docker 启动时候,咱们本身写了一些工具,能够自定义Docker启动参数,包括配置参数,好比说,一些程序要运行的参数,咱们主要用两种方式,一种方式是经过环境变量灌进去,还有一种方式让程序的启动脚本支持参数,而后拼接不一样的参数灌进去,最终都是落实到Docker的启动命令上。服务发现是基于 Consul,Docker 的启动命令是从 Consul 里取的。首先 Consul有 HTTP 的 API,咱们是本身写的 pip 包,只要 Include 一下这个包就能够了,Docker 的服务启动后会自动注册到 Consul。好比要在负载后加一个服务,只须要找到一台机器,启动对应的container,剩下的事情它本身会到 Consul,注册它的参数地址一系列东西,自动把它加进去。因此这些都是自动化的,若是检测那台机器/服务挂了,Health Check 也会到 Consul 里面更新。该增长机器就增长机器,该下线就下线。整体来讲,咱们的生产环境所有跑在 Docker 上面的,而后区分有状态和无状态两种,有状态的定死在机器上,无状态的灵活的自由切换。还有一点,若是是有状态的容器要定死在机器上的时候,咱们通常来讲都会采起冗余的结构,至少保证有两个在运行,一个挂了,保证总体的服务在运行。其次基于 Docker,咱们还作了一套数据搜集以及分析的机制。数据搜集是基于日志来搜集的,利用 Docker 的 Log driver,把日志打到 Filter,把结果存在存储服务上。同时监控也是基于日志作的。第三部分非生产环境,好比开发环境跟测试环境都是 Docker 作的,由于咱们每个服务都作了 Image、镜像,用容器方式跑的。经过参数来决定启动方式的,咱们能够在开发环境以及测试环境采用不一样的参数来启动容器。 经过 Consul 来隔离的,由于 Consul 的服务发现,开发、生产、测试环境在不一样的自动发现框架里不会相互影响到。目前机器在 120 台左右,基于云服务。有些基础的东西不须要依赖于 Docker,好比说申请云主机,申请的时候就能够指定它的 CPU 和内存这些服务器资源的配置。因此这部分东西仍是属于 Human schedule,不是彻底让编排的系统本身决定该怎么样。
编排工具咱们如今在研究进一步,我刚来这工做的时候,全部的服务没有一个跑在 Docker 上面的,我如今把它迁进来。如今数据增加,已经有一些编排的瓶颈,如今在作调研,可能基于 Swarm,作自动编排的设计。
第二轮话题交流
主持人:容器多的状况下 Kubernetes 存在性能问题,各位在这方面有没有好的经验?
扇贝丁彦:咱们其实也遇到了这个问题,找不到办法因此放弃了 Kubernetes。咱们也是用公有云,网络直接依赖公有云的网络,有多是由于公有云形成的,我没有试过在祼机上试过。
沪江黄凯:Kuberneters 的 Fannel 有一种模式是 Vxlan,它的封装折包是作内核里作的,效率会高一点。容器多就会效率会低是由于,在 Kubernetes 1.2 的时候,走这样的一种模式,数据先到内核态中,而后把数据拉回到用户态,用 Proxy的方式分发给各个容器当中的。其实在Kubernetes 1.3之后,它直接在iptables里设规则,至关于用户数据不用跑到用户态,在内核直接分发出去了,这种效率会很是高。因此能够研究一下Kubernetes新版本。
扇贝丁彦:咱们碰到过网络方面的问题。默认的Docker engine的启动参数里面有个iptables,不知道你们有没有定制化过,若是不定制化这个参数,它默认会帮你建iptables的转发规则,并会开启内核的网络追踪的模块。一开始咱们没有注意这件事情,当咱们的Nginx迁到Docker的时候,Nginx服务瞬间会挂。后来查缘由,是由于这些参数会开启网络追踪模块。由于咱们的Nginx流量很是大,当时只有3台Linux云主机,分发Http请求的,而后会致使3台Linux宿主机,内存会被刷破,网络会出现堵塞。因此咱们关掉了 iptables 参数,并采用Host的网络模型。因此它的容器拿到的IP就是Host的IP。咱们一开始也想上一些Kubernetes这些东西,而后发现简单跑个模型根本跑不起来,因此一开始就放弃了这一套东西,直接搞了个裸的Docker。
主持人:关于跨数据中心容器集群的使用,你们有经验么?
沪江黄凯:咱们跨数据中心主要是IP分配上的问题,咱们如今也在尝试使用Calico,若是Host网络是通的话,那么它的内部网络也就通了,能够自由划Vlan,这样你就能够解决跨Data center的问题。还有一个问题就在跨Data center时,服务注册与发现的问题。这个问题也困扰咱们好久了,咱们如今使用Consul作服务注册与发现。虽然Consul它是官方支持跨Data center,可是咱们在使用当中的话会发现注册的IP,在另一个注册中心,它会发现的比较慢,甚至有时候出现IP冲突的时候。
咱们的作法是把 Host 的 IP 地址直接用 Environment 的形式注到 Docker 镜像内部,接下 来 Docker 镜像要注册,它就会读取 app 的 IP,而后发送给 Consul,只要保证 Host 的 IP 和 Docker内部容器的 IP 可以互通的就好了。若是不能通的话,好比说彻底和 Host IP 隔离,那么起码有几台机器要暴露出去,又好比说,Consul 它自己本身要暴露出去才能访问到。Host 的 IP 是容器启动以后注进去的,启动命令中把 Host 的 IP 地址加在 -e 的后面,容器在启动以后,它的环境就会有这么一个 IP。咱们用 Mesos 就没这个问题,可是用 Kubernetes 就有这个问题。Mesos 会自动帮你把这些东西注入容器中去。
滴滴田智伟:其实 Kubernetes 自己也是能够解决这个问题,咱们如今在作线下持续交付的时候。定义完 Service 以后,容器会同一个 Namespace 默认加一个系统环境变量。
沪江黄凯:咱们试过,在 Pod 启动以后,Pod 里容器想访问 host 的 IP 地址,是没有办法作到的。
蘑菇街张振华:由于咱们以前也遇到这个问题,而后咱们业务方,他们可能有一些程序会获取本机 IP 地址,若是是内部的 IP 地址,他们程序可能会出现问题,因而咱们当时没有用 Docker 默认的网络,而是采用 Vlan。
主持人:咱们提到好多 Mesos、Kubernetes、网络,发现没有提自动伸缩,有没有项目涉及到容器的自动伸缩?
沪江黄凯:咱们沪江是基于 Mesos+Marathon 作了本身的一个服务,它这个服务是干吗的呢,就是监测,不停的监测每个 Docker 的 CPU 和内存的利用率,一旦超过百分之多少之后,就向Marathon发一个命令,说我要扩容,它还能够支持时间点,好比 15 分钟监测一次,若是在 15 分钟发现它超过阈值了,就立刻扩容出来,可是缩的话,不是适用于频繁监控,若是小于 20% 的话就会缩,一旦缩的话会影响线上用户的请求。怎么办呢?咱们在缩的时候能够规定它的时间点,好比半夜里2-3点,访问量少于多少点时候把它缩掉。咱们监测的是 Docker 内部的 CPU 的使用率。就是监测一个服务,它能够监控全部同一服务的 Container,好比一个服务有100个容器,那么这一百多个 CPU 利用率加起来除于一百,至关于平均的利用率。若是平均利用率超过 80%了,那说明这个集群到了扩展程度了,它会以一种比例来扩展。针对单个容器,能够设置内存的限制。咱们给每个容器呢,好比它只能用 4 个 CPU,只能用 8G 的内存,或者更小一点的内存,这些都设好,设好以后它自动扩展相同规格的容器。这么作是由于 Cgroup 有个问题,当利用率到达了启动的限制,Cgroup 会把这个容器 kill 掉。这个是不可理喻的问题,因此咱们想到用 Load scale 来扩容,不让他直接死掉。
滴滴田志伟:关于自动扩容,咱们线下的时候遇到一个问题,咱们最先的时候是用腾讯的公有云,它限制了 NET 的模块,致使咱们最初用 Cgroup 的方案去作,绑定端口。内部使用全部应用,端口是要作分配的,要否则出现端口冲突。而后遇到问题是,在这种状况下,若是要作动态扩容的话,它每次先建立一个,再杀掉一个,致使每次起来的时候就起不来了,由于端口的问题。服务启动的时候端口是随机,会出现冲突问题,由于用的是 Host 的模式。
主持人:关于自动伸缩为何没有考虑到请求数?由于若是内存占用率若是超过必定预支,那么请求数也可能超过必定预支了。把单个容器所处理的请求数给限定了,那么它内存天然不会超,而后也不会被干掉。
沪江黄凯:我我的认为,第一,请求数很难测,你不知道请求数到多少时要扩容,还不如根据 CPU 到 80%,或者 90% 来的直观。咱们的 API 也是根据 CPU 来算的。你真正是高并发的 API 的话,我也测过,最后咱们可以监测到的,其实仍是 CPU 和内存。
扇贝丁彦:咱们扩容是根据响应时间,跟请求数相似,请求数定指标不太好定,咱们是根据响应时间,好比平时的响应时间是 50 毫秒,当响应时间是 300 毫秒的时候就要扩容了。
主持人:你们对于容器有状态无状态有没有遇到什么问题?你们通常用容器的本地磁盘仍是共享磁盘呢?
沪江黄凯:关于存储,咱们是有一些研究的。如今容器存储问题分为两种,Kubernetes 官方支持一种理念,任何一种存储都是一个 Volume。Volume 先于 Docker 存在的,而不是 Docker 启动以后再挂载 Volume。无论是网络存储仍是本地存储,所有以卷的形式,挂载在 Pod 里面或者是宿主机上,以 Driver mapper 来驱动这个 Volume,来读到你所要的内容。
还有一种状况,就是 Docker 公司主导的存储模型,任何的存储都是一种驱动。若是你想用 NFS 或者如 Ceph 这样分布式存储的话,让 Ceph 开发 Docker 的驱动,Docker run 的时候指定存储的驱动,Docker storage driver这种方式,外部的存储在容器内部它展示形式能够是目录,也能够是挂载卷、块的形式。若是用块挂载到容器中,这个容器本身格式化它,或直接读取它都是能够的。它只不过它是至关于用了一个 Driver 的形式,把你的容器和分布式存储创建一个链接而已。对于容器,若是本来绑定块或 Volume,容器出现故障的话,直接把容器杀掉,再启动挂在一样一个 块或Volume就解决了。优势是直接读取,而不是经过再转一层,效率比较高一点。全部存储都是Volume 的形式理解度比较高一点,因此咱们仍是赞同于用 Volume 的形式。
有状态的容器。我知道k8s的新的计划,若是你没有用 Kubernetes 最新版本的话,通常来讲咱们都是容器启动在固定Host 上,下次启动仍是在这台 Host 上,它的存储它的内存,包括一些 log,所有是在这台 Host 上。还有一种是用最新的版本,有个 PetSet的新kind,Kubernetes 它本身会记录 Pod 在什么 Host 上启动过,不用本身去指定必定要在某一台 Host 上启动,这种方法比较智能化,可是不是特别稳定的一种方法,由于它是刚刚开发出来的新功能。
主持人:数据多副本,假设有一个节点故障的话,是建议它直接把原来的副本从新绑定仍是从新起一个新的实例,经过分布式数据的迁移呢?
沪江黄凯:我我的认为仍是在同一台机器上起一个新的实例,不要让它作数据迁移,由于数据迁移会占用不少资源。并且若是你的想法是说,全部的分布式的存储只是以 Volume 的形式挂载在宿主同上,这也就没什么问题了。由于存储和 Docker 是彻底分开来的。若是只有一个 Volume,存储的可靠性会得不到保障,因此在 Kubernetes 新版本当中,它会创建一个Volume的kind,也至关于创建 RC kind同样,是一个 Pod,那这样由 Kubernetes 来保障这个 Volume 的高可用。