Mesos

Mesos

【腾讯云】#容器团队#高级容器研发#招聘

Shirleyee 发表了文章 • 1 个评论 • 235 次浏览 • 2019-05-24 10:33 • 来自相关话题

高级容器研发工程师 工作职责 负责公有云/私有云中 Kubernetes/Devops 等产品技术方案设计与研发工作;负责 Kubernetes 相关前沿技术规划和调研工作,从技术上保证产品的竞争力;负责与产品及客户沟通,判定需求的合理 ...查看全部
高级容器研发工程师
工作职责
  1. 负责公有云/私有云中 Kubernetes/Devops 等产品技术方案设计与研发工作;
  2. 负责 Kubernetes 相关前沿技术规划和调研工作,从技术上保证产品的竞争力;
  3. 负责与产品及客户沟通,判定需求的合理性,找出最合适的方式解决客户问题。
工作要求
  1. 3 年以上后端开发经验,Coding、Debug 能力强, 有丰富的架构设计经验;
  2. 熟悉 C/C++/Go/Java/Python/Ruby 等至少二种编程语言;
  3. 熟悉 Docker/Kubernetes/Swarm/Mesos 等技术;
  4. 熟悉 Jenkins/ELK/Prometheus 等技术优先;
  5. 熟悉 AWS/Google Cloud 等云计算厂商产品优先。


有意请戳:
Wechat:13723737494
Email:Shirleyeee@foxmail.com

集群调度系统的演进

JetLee 发表了文章 • 0 个评论 • 836 次浏览 • 2019-04-03 13:01 • 来自相关话题

Kubernetes 已经成为容器编排领域的事实标准,将来所有应用都会在 Kubernetes 上开发和运行,这个系列文章的目的是深入浅出的介绍 Kubernetes 底层实现的原理。 Kubernetes 是一个集群调度系统,今 ...查看全部
Kubernetes 已经成为容器编排领域的事实标准,将来所有应用都会在 Kubernetes 上开发和运行,这个系列文章的目的是深入浅出的介绍 Kubernetes 底层实现的原理。

Kubernetes 是一个集群调度系统,今天这篇文章主要是介绍 Kubernetes 之前一些集群调度系统的架构,通过梳理他们的设计思路和架构特点,我们能够学习到集群调度系统的架构的演进过程,以及在架构设计时需要考虑的主要问题,对理解 Kubernetes 的架构会非常有帮助。
#基本概念

我们需要先了解集群调度系统里面的一些基本的概念,为了方便大家理解,我通过一个例子来解释这些概念,假设我们要实现一个分布式的定时任务系统(分布式的 Cron),这个系统管理了一组 Linux 主机,用户通过系统提供的的 API / UI 定义定时任务(就类似在 Linux 里面定义 Crontab) ,系统会根据任务的定义,来定时来执行相应的任务,在这个例子里面有如下基本概念:

* 集群(Cluster):这个系统管理的 Linux 主机组成一个资源池,用来运行任务,这个资源池就是集群。
* 作业(Job):就是定义集群如何去执行任务,在例子里面 Crontab 就是一个简单的作业,里面明确的告诉了集群需要在什么时间(时间间隔) ,做什么事情(执行的脚本)。一些作业的定义会复杂很多,比如还会定义一个作业分几个任务做完,以及任务之间的依赖关系,还包括每一个任务对资源的需求。
* 任务(Task):作业需要被调度成具体的执行任务,如果我们定义了一个作业是每天晚上凌晨 1 点执行一个脚本,那么在每天凌晨 1点被执行的这个脚本进程就是任务。

在设计集群调度系统的时候,这个调度系统的核心任务也就是 2 个:

* 任务调度。作业提交给集群调度系统之后,需要对提交的作业拆分成具体的执行任务,并且跟踪和监控任务的执行结果。在分布式 Cron 的例子中,调度系统需要按照作业的要求定时启动进程,如果进程执行失败,需要重试等,一些复杂的场景,比如 Hadoop 的 Map Reduce ,调度系统需要把 Map Reduce 任务拆分成相应的多个 Map 和 Reduce 任务,并且最终拿到任务执行结果的数据。
* 资源调度:本质上是对任务和资源做匹配,根据集群中主机的资源使用情况,分配合适的资源来运行任务。和操作系统的进程调度算法比较类似,资源调度的主要目标是,在固定的资源供给的情况下,尽可能提高资源使用率,减少任务等待的时间(任务等待资源去执行的时间),减少任务运行的延迟或者响应时间(如果是批量任务的话,就是任务从开始执行到结束的时间,如果在线响应式任务的话,比如 Web 应用,就是每一次响应请求的时间),尽可能公平(资源公平的被分配到所有任务)的同时,还需要考虑任务的优先级。这些目标里面有一些是有冲突的,需要平衡,比如资源利用率和响应时间,公平和优先级。

#Hadoop MRv1

Map Reduce 是一种并行计算模型,Hadoop 是可以运行这种并行计算的集群管理平台,其中 MRv1 是 Hadoop 平台的 Map Reduce 任务调度引擎的第一代版本,简单来说,用户定义了 一个 Map Reduce 计算,提交给 Hadoop 之后,由 MRv1 负责在集群上调度和执行这个作业,并且返回计算结果。 MRv1 的架构看起来是这样的:
1.png

架构还是比较简单的,标准的 Master/Slave 的架构,有 2 个核心组件:

* Job Tracker 是集群主要的管理组件,同时承担了资源调度和任务调度的责任。
* Task Tracker 运行在集群的每一台机器上,负责在主机上运行具体的任务,并且汇报状态。

随着 Hadoop 的流行和各种需求的增加,MRv1 有如下问题需要改进:

  1. 性能有一定瓶颈:支持管理的最大节点数是 5千个节点,支持运行的任务最大数量 4万,还有一定的提高空间。
  2. 不够灵活,无法扩展支持其他任务类型。Hadoop 生态里面除了 Map Reduce 类型任务,还有其他很多任务类型需要调度,比如 Spark,Hive,HBase,Storm,Oozie 等,所以需要一个更加通用的调度系统,能够支持和扩展更多的任务类型。
  3. 资源利用率比较低。MRv1 给每个节点静态配置了固定数目的 Slot ,每个 Slot 也只能够运行的特定的任务的类型(Map or Reduce),这就导致资源利用率的问题,比如大量 Map 任务在排队等待空闲资源,但实际上机器有大量 Reduce 的 Slot 被闲置。
  4. 多租户和多版本的问题。比如不同部门在同一个集群里面运行任务,但是彼此是逻辑上隔离的,或者在同一个集群里面运行不同版本的 Hadoop。

#YARN

YARN(Yet Another Resource Negotiator)是 Hadoop 的第二代调度系统,主要目的就是为了解决 MRv1 中的各种问题。YARN 的架构看起来是这样的:
2.png

YARN 简单的理解就是,相对于 MRv1 的主要改进就是,把原来的 JobTrack 的职责,拆分给两个不同的组件来完成:Resource Manager 和 Application Master:

* Resource Manager:承担资源调度的职责,管理所有资源,将资源分配给不同类型的任务,并且通过“可插拔”的架构来很容易的扩展资源调度算法。
* Application Master:承担任务调度的职责,每一个作业(在 YARN 里面叫做 Application)都会启动一个对应的 Application Master,它来负责把作业拆分成具体的任务、向 Resource Manager 申请资源、启动任务、跟踪任务的状态并且汇报结果。

我们看看这种架构改变是如何解决 MRv1 的各种问题的:

* 将原来的 Job Tracker 的任务调度职责拆分出来,大幅度提高了性能。原来的 Job Tracker 的任务调度的职责拆分出来由 Application Master 承担,并且 Application Master 是分布式的,每一个实例只处理一个作业的请求,将原来能够支撑的集群节点最大数量,从原来的5千节点提升到1万节点。
* 任务调度的组件,Application Master,和资源调度解耦,而且是根据作业的请求而动态创建的,一个 Application Master 实例只负责一个作业的调度,也就更加容易支持不同类型的作业。
* 引入了容器隔离技术,每一个任务都是在一个隔离的容器里面运行,根据任务对资源的需求来动态分配资源,大幅提高了资源利用率。不过有一个缺点是,YARN 的资源管理和分配,只有内存一个维度。

#Mesos 的架构

YARN 的设计目标依然是服务于 Hadoop 生态的调度,Mesos 的目标更近一步,被设计成一个通用的调度系统,能够管理整个数据中心的作业,看的出来 Mesos 的架构设计很多借鉴了 YARN,将作业调度和资源调度分别由不同的模块承担,不过 Mesos 和 YARN 很大不同的地方是对资源的调度方式,设计了一个叫非常独特的 Resource Offer 的机制,进一步释放了资源调度的压力,增加了作业调度的扩展性。
3.png

Mesos 的主要组件是:

* Mesos Master ,单纯是承担资源分配和管理的组件,的对应到 YARN 里面就是那个 Resource Manager,不过工作方式会稍微有些不太一样,后面会讲到。
* Framework,承担作业调度,不同的作业类型都会有一个对应的 Framework,比如负责 Spark 作业的 Spark Framework。

##Mesos 的 Resource Offer

看起来 Mesos 和 YARN 架构非常类似,不过实际上在资源管理的方面, Mesos 的 Master 有非常独特(甚至有些奇怪)的 Resource Offer 机制:

* YARN 中 Resource Manager 提供资源的方式是被动的,当资源的消费者(Application Master) 需要资源的时候,会调用 Resource Manager 的接口来获取到资源,Resource Manager 只是被动的响应 Application Master 的需求。
* Mesos 的 Master 提供资源的方式是主动的。Mesos 中的 Master 会定期的主动推送当前的所有可用的资源(就是所谓的 Resource Offer,后面统一都叫 Offer)给 Framework,Framework 如果有任务需要被执行,不能主动申请资源,只有当接收到 Offer 的时候,从 Offer 里面挑选满足要求的资源来接受(在 Mesos 里面这个动作叫做 Accept),剩余的 Offer 就都拒绝掉(这个动作叫做 Reject),如果这一轮 Offer 里面没有足够能够满足要求的资源,只能等待下一轮 Master 提供 Offer。

相信大家看到这个主动的 Offer 机制的时候,会和我有同样的感觉,就是效率比较低,会产生如下问题:

* 任何一个 Framework 的决策效率会影响整体的效率。为了一致性,Master 一次只能给一个 Framework 提供 Offer,等待这个 Framework 挑选完 Offer 之后,再把剩余的提供给下一个 Framework,这样的话,任何一个 Framework 做决策的效率就会影响整体的效率;
* “浪费”很多时间在不需要资源的 Framework 上。 Mesos 并不知道哪个 Framework 需要资源,所以会出现有资源需求的 Framework 在排队等待 Offer,但是没有资源需求的 Framework 却频繁收到 Offer 的情况。

针对上面的问题,Mesos 提供了一些机制来做一定程度的缓解,比如给 Framework 设置一个做决策的超时时间,或者允许 Framework 可以通过设置成 Suppress 状态来表示不需要接受 Offer等,因为不是本次讨论的重点,所以细节就不展开了。

实际上,Mesos 采用这种主动 Offer 的机制,也是有一些明显的优点的:

* 性能明显提高。根据模拟测试一个集群最大可以支撑 10 万个节点,Twitter 的生产环境最大集群支撑 8 万个节点,主要原因是 Mesos Master主动 Offer 的机制,进一步简化了 Mesos Master 的工作职责,Mesos 中将资源调度的过程(资源 —> 任务的匹配)分成了 2 个阶段:资源 —> Offer —> 任务 。Mesos Master 只负责完成第一个阶段,第二个阶段的匹配交给 Framework 来完成。
* 更加灵活,能够满足更加负责的任务调度的策略。举个例子,All Or Nothings 的资源使用策略。

##Mesos 的调度算法 DRF(Dominant Resource Fairness)

关于 DRF 算法,其实对我们理解 Mesos 架构并没有什么关系,但是在 Mesos 中却非常核心和重要,所以多啰嗦几句。

上面说了,Mesos 是轮流给 Framework 提供 Offer 的,那么每次该挑选哪个 Framework 提供 Offer 呢?这就是 DRF 算法要解决核心的问题, 基本原则就是要兼顾公平和效率,在经量满足所有 Framework 对资源需求的同时,也要应该尽可能公平,避免某一个 Framework 占用太多资源而把其他 Framework 给“饿死”。

DRF 是 min-max fairness 算法的一个变形,简单来说就是每次都挑选支配资源占用率(Dominant Resource Usage)最低的那个 Framework 提供 Offer。如何计算 Framework 的“支配资源占用率”呢?就是从 Framework 占用的所有资源类型里面,挑选资源占用率最小的那个资源类型最为支配资源(Dominant Resource),它的资源占用率就是这个 Framework 的支配资源占用率( Dominant Resource Usage),举个例子,一个 Framework X 的 CPU 占用了整体资源的 20%,内存是 30%,磁盘是 10%,那么这个 Framework 的支配资源占用率就是 10%,官方术语把磁盘叫做支配资源, 这个 10% 叫做支配资源占用率。

DRF 的最终目的是把资源平均的分配给所有 Framework,如果一个 Framework X 在这一轮 Offer 中接受(Accept Offer)了过多的资源,那么就要等更长的时间才能获得下一轮 Offer 的机会。不过仔细的读者会发现,这个算法里面有一个假设,就是 Framework 接受了资源之后,会很快释放掉,否则就会有 2 个后果:

  1. 其他 Framework 被“饿死“。某个 Framework A 一次性的接受了集群中大部分资源,并且任务一直运行不退出,这样大部分资源就被 Framework A 一直霸占了,其他 Framework 就没法获得资源了。
  2. 自己被饿死。因为这个 Framework 的支配资源占用率一直很高,所以长期无法获得 Offer 的机会,也就没法运行更多的任务。

所以实际上,Mesos 只适合调度短任务,Mesos 在设计之初就是为数据中心中的段任务而设计的。
#总结一下

从大的架构上,所有调度系统的架构都是 Master / Slave 的架构,Slave 端安装在每一台需要管理的机器上,用来收集主机信息,在主机上执行任务。Master 主要负责做资源调度和任务调度,资源调度对性能要求比较高,任务调度对可扩展性要求较高,总体趋势是讲这两类职责解耦,分别由不同的组件来完成。
4.png


原文链接:集群调度系统的演进(作者:邵明岐)

Makisu:Uber开源的快速Docker镜像生成工具

hokingyang 发表了文章 • 0 个评论 • 1785 次浏览 • 2018-12-16 15:59 • 来自相关话题

为了保证业务平稳发展,我们引入了一种使得工程师们可以动态高效快速部署上千台服务的微服务架构,这种服务大大提高了我们平台上的乘客司机的使用体验。 尽管这种模式支撑了我们快速增长的应用环境,但是由于业务规模太大也带来了痛点。为了容易维护和 ...查看全部
为了保证业务平稳发展,我们引入了一种使得工程师们可以动态高效快速部署上千台服务的微服务架构,这种服务大大提高了我们平台上的乘客司机的使用体验。

尽管这种模式支撑了我们快速增长的应用环境,但是由于业务规模太大也带来了痛点。为了容易维护和升级微服务,2015年采用了Docker技术,确保资源和服务被打包成一个单元。

随着Docker的发展,核心架构团队开发了一套快速高效为Apache Mesos和基于Kubernetes的容器生态产生Dockerfiles配置文件并将应用代码打包在Docker image中的技术。考虑到微服务技术的快速发展,我们开源了核心模块,Makisu,以便其它用户能够收到同样的效果。
# Uber的Docker之路
2015年早期,我们在裸服务器上部署了大约400个服务,他们共享主机上的依赖包和配置文件,仅有很少资源限制。随着工程师规模扩大,依赖管理和资源隔离成为一个问题。为了解决这个问题,核心架构团队开始将服务移植到Docker中,随之建立了标准化和流程化的容器创建流程自动化机制。

新容器化运行环境在服务生命周期管理的运行速度和可靠性方面带来很大提高。然而,访问服务依赖的密钥被打包进image,带来了潜在的安全隐患。简单说,一旦一个文件被放入Docker image中,就会永久存在。尽管可以通过其他这种手段隐藏这些密钥,但是Docker并不提供真正将他们从image中移除的功能。

其中一个解决方案是docker-squash,一个删除Docker image中间步骤所需文件的开源工具,但是带来的问题就是创建image的时间翻倍,这个问题基本抵消了采用微服务架构带来的好处。

为了解决这个问题,我们决定分叉Docker自研我们需要的功能。如果在创建image时候,把所需的密钥以volume方式挂载,这样最终的Docker image中就不留任何密钥的痕迹。因为没有额外延迟,而且代码更改也很少,因此这方法很有效。架构团队和服务团队都满意了,容器架构被更好地利用起来。
# 大规模编译容器image
到了2017年,这种架构不再能满足需求。随着Uber的增长,平台规模也同样受到很大挑战。每次创建超过3000个服务,每天有若干次,大大增加了消耗时间。有些需要2个小时,大小超过10GB,消耗大量存储空间和带宽,严重影响开发者生产率。

此时,我们认识到创建可以扩展的容器image是很重要的。为此提出了三个需求:无特殊权限创建,支持分布式cache,image大小优化。
## 无特殊权限创建
2017年,核心架构团队开始将Uber的计算负载迁移到提供自动化、可扩展和更加弹性化的统一平台上。随之而来,Dockerfile也需要能够运行在共享集群上的容器中。

不幸的是,Docker创建逻辑依赖于一种通过对比创建时间来决定不同层次之间不同的copy-on-write文件系统。这个逻辑需要特权挂载或者卸载容器内部的目录,以便给新系统提供安全机制。也就意味着,Docker无法做到无root权限创建。
## 支持分布式缓存(cache)
通过分层缓存(cache)技术,用户可以复用之前的创建版本和层级,可以减少执行时候的冗余。Docker为每个创建提供分布式缓存,但是并不支持不同分支和服务。需要依靠Docker本地缓存层,但是因为集群内的生成新版本要求不断清空缓存,造成缓存命中率大大降低。

过去,Uber采用指定机器创建指定服务的方式提高命中率,然而,这种方法对于多种服务构成的系统来说显然是不够的。考虑到我们每天会使用上千种服务,这个过程也增加了调度复杂性。

显然一个好的缓存策略对我们的方案更加重要,最终分布式缓存方案既可以解决性能问题,也能够解决创建系统时的调度问题。
## 优化image大小
小images节省空间,并且可以节省转换、压缩和启动时间。

为了优化image大小,我们计划采用多阶段步骤。在众多方案中并不很特别:通过中间态image,将运行时所需文件拷入瘦身的最终image。尽管需要比较复杂的Dockerfiles,但可以减小image大小,因此可以很好地弹性部署。

另外,通过减少image中的层数也可以减少image大小,image比较大有可能是某些文件被中间层创建,删除或者更新的结果。如前所述,即使后续步骤删除了临时文件,但是在开始层中仍然存在,占据相应空间。减少层数可以大大减少删除或更新的文件在之前层中依然存在的可能性,因此可以减小image大小。
# 介绍Makisu
为了实现以上想法,我们开发了自己的image工具,Makisu,实现更加动态,更快容器创建,更加弹性等功能。其特点包括:

* 不需要特殊权限,开发过程更加容易移植;
* 开发集群内部使用分布式层间缓存提高性能;
* 提供灵活层间管理,减少images中不必要文件;
* 与容器Docker兼容;支持标准和多阶段开发命令。

下面详细介绍这些特性。
## 不需要特殊权限
与其它虚机相比Docker image更加轻量是因为中间层只包括运行开发步骤前后文件系统的差别。Docker计算差别,并使用需要特权的CoW文件系统生成中间层。

为了实现不需要特权生成中间层,Makisu在内存中进行文件系统扫描。运行开发步骤后,在此扫描文件系统,更新内存视图,将变化文件添加到新一层。

Makisu也对压缩速度进行了优化,这对弹性部署非常重要。Docker使用Go中默认gzip库压缩层级,当遇到带有大量text文件的image层来说性能很慢。文件扫描阶段后,即使没有缓存,Makisu在很多方面比Docker要快,其中P90开发时间将近节省50%。
## 分布式缓存
Makisu用key-value数据库映射Dockerfiles中操作行到存放在Docker镜像仓库中的层数。key-value数据库可以用Redis或者文件系统。Makisu也用缓存TTL确保缓存内容不会存放太久。

缓存key用当前开发命令和前一条命令的key一起生成。缓存值是生成层内容的哈希值,也用来定位当前层在Docker镜像仓库中的位置。

在Dockerfile的初始化阶段,层生成并且异步推到Docker镜像仓库和key-value库中。后续同样步骤可以从缓存层中获取并解压获取,避免冗余操作。
## 灵活层间操作
为开发过程对iamge层进行控制,Makisu映入了新的操作注释:#!COMMIT,指代Dockerfile中可以生成新层的行。这一简单机制对减少容器image大小很关键( 后续操作要删除或者更新文件 ),解决了密钥跨层存取的问题。每个commit层在分布式缓存中得以体现,集群中其它开发者也可以使用这一更新结果。

以下是一个Dockerfile的实例,其中使用了Makisu的操作注释:
FROM debian:8 AS build_phase
RUN apt-get install wget #!COMMIT
RUN apt-get install go1.10 #!COMMIT
COPY git-repo git-repo
RUN cd git-repo && make

FROM debian:8 AS run_phase
RUN apt-get install wget #!COMMIT
LABEL service-name=test
COPY –from=build_phase git-repo/binary /binary
ENTRYPOINT /binary

本例中,安装了运行时需求包(wget和go1.10),并在相应层内commit,后续创建服务代码。当这些committed层创建后,在分布式缓存中得以更新,其它开发这可以使用,大大提高了开发工作冗余操作的速度。

第二阶段,开发再次安装wget,这次Makisu重用了之前生成的代码。最后,服务代码从开发阶段拷贝到最终image,并生成最终image。这一示例生成一个瘦身的最终image,具体结构如图一所示:
image1.png

图一 Docker为每一步启动一个新容器并生成三层,Makisu在一个容器中编排所有步骤并跳过不必要的层生成
## Docker兼容
Docker image一般是由一些明文按顺序展开的tar文件和两个配置文件构成,Makisu生成的image跟Docker Daemon和镜像仓库完全兼容。

Makisu也支持多阶段开发,通过#!COMMIT的引入,可以实现不必要步骤跳过,并节省空间。

另外,因为#!COMMIT格式化为注释,Makisu使用的Dockerfiles可以被Docker完全兼容。
# 如何使用Makisu
如果想使用Makisu,用户可以直接下载二进制代码,并且不带RUN地运行简单Dockerfiles。用户可以下载Makisu,运行在Docker容器内部,或者作为Kubernetes/Apache Mesos持续集成的工作流。

- 本地使用Makisu二进制代码
- 本地使用Makisu image
- 作为Kubernetes工作流运行Makisu

原文链接:Introducing Makisu: Uber’s Fast, Reliable Docker Image Builder for Apache Mesos and Kubernetes(翻译:杨峰)

DockOne微信分享(一八一):小米弹性调度平台Ocean

李颖杰 发表了文章 • 0 个评论 • 2402 次浏览 • 2018-07-20 23:50 • 来自相关话题

小米弹性调度平台在公司内的项目名称为Ocean(以下简称Ocean)。 Ocean目前覆盖了公司各种场景的无状态服务,同时对于一些基础服务组件,比如:MySQL、Redis、Memcache、Grafana等等抽象为了PaaS平台 ...查看全部
小米弹性调度平台在公司内的项目名称为Ocean(以下简称Ocean)。

Ocean目前覆盖了公司各种场景的无状态服务,同时对于一些基础服务组件,比如:MySQL、Redis、Memcache、Grafana等等抽象为了PaaS平台Ocean的服务组件。

Ocean平台作为小米公司级PaaS平台,目前正在做的事情和后续的一些规划,这里简单列几个:CI/CD、故障注入、故障自愈、容量测试等等。

目前Ocean平台已支持IDC和多云环境,此次分享只介绍IDC内的实践。

Ocean平台因启动的比较早,当时Kubernetes还没有release版本,所以早起的选型是Marathon + Mesos的架构,此次的分享底层也是Marathon + Mesos架构(目前已在做Marathon + Mesos/Kubernetes双引擎支持,本次分享不涉及Kubernetes底层引擎相关内容)。

先分享一张Ocean平台的整体架构图:
1.png

关于容器的存储、日志收集、其他PaaS组件(RDS、Redis等等)、动态授权、服务发现等等本次分享不做介绍。
#容器网络的前世今生

做容器或者说弹性调度平台,网络是一个避不开的话题,小米在做弹性调度的时候网络有以下几方面的考虑:

1. 要有独立、真实的内网IP,便于识别和定位,无缝对接现有的基础设施;
2. 要与现有的物理机网络打通;
3. 要能保证最小化的网络性能损耗(这一点基本上使我们放弃了overlay的网络方式);

因小米弹性调度平台启动的很早,而早期容器网络开源方案还不是很成熟,还不具备大规模在生产环境中使用的条件。所以综合考虑,我们选择了DHCP的方案。

DHCP方案的实现:

1. 网络组规划好网段;
2. 划分专属Ocean的vlan,并做tag;
3. 搭建DHCP server,配置规划好的网段;
4. 容器内启动DHCP client,获取IP地址。
5. 物理机上配置虚拟网卡,比如eth0.100,注:这个100就是vlan ID,和tag做关联的,用于区分网络流量。

此方案中有几个细节需要注意:

1. DHCP server需要做高可用:我们采用了 ospf+vip的方式;
2. 启动的容器需要给重启网卡的能力,以获取IP地址,即启动容器时需要增加NET_ADMIN能力;
3. 需要配置arp_ignore,关闭arp响应,net.ipv4.conf.docker0.arp_ignore=8。

DHCP网络模式,在Ocean平台运行了很长一段时间。

DHCP网络从性能上、独立IP、物理网络互通等方面都已满足需求。既然DHCP已满足需求,那么我们后来为什么更换了网络模型。

因为DHCP的方式有几个问题:

1. IP地址不好管理,我们需要再做个旁路对IP地址的使用情况做监控,这就增加了Ocean同学维护成本;
2. 每次资源扩容需要网络组同学帮我们手动规划和划分网段,也增加了网络同学的管理成本。

针对以上2个痛点,我们重新对网络进行了选型。重新选型时社区用的比较多的是Calico和Flannel。那我们最后为什么选择了Flannel?还是基于:要有独立IP、和现有物理网络互通、最小化网络性能损耗这3点来考虑的。

Calico在这3点都能满足,但是侵入性和复杂度比较大:

1. Calico的路由数目与容器数目相同,非常容易超过路由器、三层交换、甚至节点的处理能力,从而限制了整个网络的扩张。
2. Calico的每个节点上会设置大量的iptables规则、路由,对于运维和排查问题难道加大。
3. 和现有物理网络互联,每个物理机也需要安装Felix。

而Flannel + hostgw方式对于我们现有的网络结构改动最小,成本最低,也满足我们选型需求,同时也能为我们多云环境提供统一的网络方案,因此我们最终选择了Flannel+hostgw方式。

下面简单介绍下Ocean在Flannel+hostgw上的实践。

1. Ocean和网络组协商,规划了一个Ocean专用的大网段;
2. 网络组同学为Ocean平台提供了动态路由添加、删除的接口,即提供了路由、三层交换简单OpenAPI能力;
3. Ocean平台规范每台宿主机的网段(主要是根据宿主机配置,看一台宿主机上启动多少实例,根据这个规划子网掩码位数);
4. 每台容器宿主机上启动Flanneld,Flanneld从etcd拿宿主机的子网网段信息,并调用网络组提供的动态路由接口添加路由信息(下线宿主机删除路由信息);
5. Dockerd用Flanneld拿到的网段信息启动Docker daemon。
6. 容器启动是根据bip自动分配IP。

这样容器的每个IP就分配好了。容器的入网和出网流量,都依赖于宿主机的主机路由,所以没有overlay额外封包解包的相关网络消耗,只有docker0网桥层的转发损耗,再可接受范围内。

以上为小米ocean平台改造后的网络情况。

网络相关的实践,我们简单介绍到这里,下面介绍发布流。
#发布流

对于一个服务或者任务(以下统称job)的发布流程,涉及如下几个方面:

1. 需要创建要发布job的相关信息。
2. 基于基础镜像制作相关job的部署镜像。
3. 调用Marathon做job部署。
4. job启动后对接小米运维平台体系。
5. 健康检查

发布流程的统一管理系统(以下统称deploy)做发布流整个Pipeline的管理、底层各个组件的调用、维护了各个stage的状态。

下面针对这几点展开详细介绍下:

job的相关信息:job我们可以理解为业务需要部署的项目模板,是Ocean平台发布的最小粒度单元。因其为业务项目模板,所以需要填写的信息都是和业务项目相关的内容,需要填写job名称、选择集群(在哪个机房部署)、给定产品库地址(业务代码的Git或SVN地址)、选择容器模板(启动的容器需要多大的资源,比如1CPU 2G内存 100G磁盘等)、选择基础镜像版本(比如CentOS:7.3,Ubuntu:16.04等)、选择依赖的组件(比如JDK、Resin、Nginx、Golang、PHP等等业务需要根据自己的代码语言和环境需求选择)、填写启动命令(服务如何启动)、监听端口(服务监听的端口是多少,该端口有几个作用:1. 提供服务;2. 健康检查;3. 创建ELB关联;4. 会和job名字一起上报到zk,便于一些还没有服务发现的新项目平滑使用Ocean平台提供的服务发现机制)。

以上是最基本的job信息,还有一些其他的个性化设置,比如环境变量、共享内存、是否关联数据库等等,这里不展开介绍了。

制作job镜像:上面的job信息创建好后,便可以进入真正的发布流程了。发布的时候会根据用户设置的job信息、基于Ocean提供的基础镜像来制作job镜像。这里面主要有2个流程,一个是docker build 制作镜像,一个是业务代码的编译、打包。

Docker build 基于上面填写的job信息解析成的Dockerfile进行。我们为什么不直接提供Dockerfile的支持,而做了一层页面的封装:

* 对于开发接入成本比较高,需要单独了解Dockerfile文件格式和规范。
* 开发人员越多,写错Dockerfile的几率越大,对于Ocean同学来说排错的成本就会越高。
* 此封装可以规范Dockerfile,业务只需要关心和job相关的最基本信息即可,不需要了解Dockerfile具体长什么样子。

Docker build会在镜像里拿业务代码,然后进行业务代码的编译、打包;关于业务编译、打包Ocean内做了一些针对原部署系统(服务部署到物理机)的兼容处理,可以使业务直接或很少改动的进行迁移,大大降低了迁移的成本。

job镜像build成功后,会push到Ocean私有的Registry。

调用marathon做job部署:镜像build成功后,deploy会调用Marathon的接口,做job的部署动作(底层Marathon + Mesos之间调度这里也不展开讲,主要说下我们的Ocean上做的事情)。

job部署分2种情况:

* 新job的部署:这个比较简单,deploy直接调用Marathon创建新的job即可。
* job版本更新:更新我们需要考虑一个问题,如何使job在更新过程中暂停,即支持版本滚动更新和业务上的灰度策略。

Marathon原生是不支持滚动更新的,所以我们采用了一个折中的办法。
在做job更新的时候,不做job的更新,是创建一个新的job,除版本号外新job名字和旧job名字相同,然后做旧job缩减操作,新job扩容操作,这个流程在deploy上就比较好控制了。

更新期间第一个新job启动成功后默认暂停,便于业务做灰度和相关的回归测试等。

对接运维平台体系:基础镜像内打包了docker init,容器在启动的时候docker init作为1号进程启动,然后我们在docker init中做了和目前运维平台体系打通的事情,以及容器内一些初始化相关的事情。

包括将job关联到业务的产品线下、启动监控Agent、日志收集、对接数据流平台、注册/删除ELB、启动日志试试返回给deploy等等。

健康检查:我们做健康检查的时候偷了些懒,是基于超时机制做的。
job编译成功后,deploy调用Marathon开始部署job,此时Marathon便开始对job做健康检查,再设置的超时时间(这个超时时间是可配置的,在job信息内配置)内一直做健康检查,直到健康检查成功,便认为job发布成功。发布成功后,整个发布流结束。
#弹性ELB

job部署成功后,就是接入流量了。在Ocean平台流量入口被封装为了ELB基础服务。

在ELB模块入口创建ELB:选择集群(即入口机房,需要根据job部署的机房进行选择,为了规范化禁止了elb、job之间的夸机房选择);选择内、外网(该服务是直接对外提供服务,还是对内网提供服务);填写监听端口(job对外暴露的端口);选择调度算法(比如权重轮询、hash等);选择线路(如果是对外提供服务,是选择BGP、还是单线等)。

ELB创建好后,会提供一个ELB的中间域名,然后业务域名就可以cname到这个中间域名,对外提供服务了。

大家可以看到,ELB的创建是直接和job名字关联的,那么job目前的容器实例、之后自动扩缩的容器实例都是怎么关联到ELB下的呢?

这里也分2种情况:

1. job已经启动,然后绑定ELB:这种情况下,我们做了一个旁路服务,
已轮询的方式从Marathon获取实例信息,和创建的ELB后端信息进行比较,并以Marathon的信息为准,更新ELB的后端。
2. 绑定ELB后,job扩缩:上面在发布流中提到,docker init会做ELB的注册、删除动作。

job在扩容的时候会在docker init初始化中将job注册到ELB后端;job在缩容的时候会接收终止信息,在接收终止信号后,docker init做回收处理,然后job实例退出。在回收处理的过程中会操作该实例从ELB摘除。

到此ELB的基本流程就分享完了,下面说下自动扩缩。
#自动扩缩

自动扩缩目前包括定时扩缩和基于Falcons的动态扩缩。
##定时扩缩

比如一些服务会有明显的固定时间点的高峰和低谷,这个时候定时扩缩就很适合这个场景。

定时扩缩的实践:定时扩缩我们采用了Chronos。

在deploy内封装了Chronos任务下发的接口,实际下发的只是定时回调任务。到任务时间点后触发任务,该任务会回调deploy 发布服务的接口,进行job的扩缩。这里我们为什么没有直接调用Marathon的接口,是因为在deploy中,我们可以自行控制启动的步长、是否添加报警等更多灵活的控制。
##基于Falcon动态扩缩

Falcon是小米内部的监控平台(和开源的Open-Falcon差别并不大,但是Ocean平台job内的Falcon Agent 基于容器做过了些改造)。Ocean平台是基于Falcon做的动态调度。用户自行在Ocean上配置根据什么指标进行动态调度,目前支持CPU、内存、thirft cps。这些metric通过Falcon Agent 上报到Falcon平台。用于做单容器本身的监控和集群聚合监控的基础数据。

然后我们基于聚合监控来做动态扩缩。例如,我们在Ocean平台上配置了基于CPU的扩缩,配置后,deploy会调用Falcon的接口添加集群聚合的监控和回调配置,如果实例平均CPU使用率达到阈值,Falcon会回调deploy做扩缩,扩缩实例的过程和定时扩缩是一样的。
#遇到的一些特例问题

Ocean从启动开始遇到了很多问题,比如早起的Docker版本有bug会导致docker daemon hang住的问题,使用Device Mapper卷空间管理的问题等等。

下面针对本次的分享,简单列5个我们遇到的问题,然后是怎么解决的。

1、ELB更新为什么没有采用Marathon事件的机制,而是使用了旁路服务做轮询?

* 我们发现marathon的事件并不是实时上报,所以这个实时性达不到业务的要求;
* 在我们的环境中也碰到了事件丢失的问题。

所以我们采用了旁路服务轮询的方式。

2、虽然Ocean平台已经做了很多降低迁移成本的工作,但是对于一些新同学或者新业务,总还是会有job部署失败的情况。针对这种情况,我们增加了job的调试模式,可以做到让开发同学在实例里手动启动服务,查看服务是否可以正常启动。

3、ELB的后端数目不符合预期。

主要是由于slave重启导致实例应该飘到其他的机器时,Marathon低版本的bug导致启动的实例数与预期不一致。解决该问题是通过登录到Marathon,通过扩缩实例然后使实例数达到预期,但是这又引进了另外一个问题,ELB的后端存在了残留的IP地址没有被清理,虽然这个因为健康检查而不影响流量,但是暂用了额外的IP资源,所以我们又做了个旁路服务,用于清理这些遗留IP。

4、容器内crontab不生效。业务在容器内使用了crontab,但是在相同的宿主机上,个别容器crontab不生效问题。

我们解决的方式是为启动的容器增加相应的能力,即启动的时候mesos executor增加 AUDIT_CONTROL 选项。

5、容器内看到的Nginx worker进程数没有隔离的问题。

我们在物理机上配置Nginx时通常会将Nginx的worker进程数配置为CPU核心数并且会将每个worker绑定到特定CPU上,这可以有效提升进程的Cache命中率,从而减少内存访问损耗。然后Nginx配置中一般指定worker_processes指令的参数为auto,来自动检测系统的CPU核心数从而启动相应个数的worker进程。在Linux系统上Nginx获取CPU核心数是通过系统调用 sysconf(_SC_NPROCESSORS_ONLN) 来获取的,对于容器来说目前还只是一个轻量级的隔离环境,它并不是一个真正的操作系统,所以容器内也是通过系统调用sysconf(_SC_NPROCESSORS_ONLN)来获取的,这就导致在容器内,使用Nginx如果worker_processes配置为auto,看到的也是宿主机的CPU核心数。

我们解决的方式是:劫持系统调用sysconf,在类Unix系统上可以通过LD_PRELOAD这种机制预先加载个人编写的的动态链接库,在动态链接库中劫持系统调用sysconf并根据cgroup信息动态计算出可用的CPU核心数。
#Q&A

Q:请教下你们ELB用的什么代理软件,HAProxy、Nginx?是否遇到过缩容时出现部分请求失败的问题,有解决方案吗?

A:IDC ELB底层封装的是公司的LVS,LVS管理平台提供了完事的API支持,ELB这边调用LVS管理平台的API进行的相关操作。缩容目前没有遇到流量丢失问题,这个是在docker init内接收信号,然后做的回收处理。

Q:hostgw如何访问外网?
>A:是通过路由出网的,容器的IP是路由上真实存在的IP网段,由网络组提供的API进行的动态配置。

Q:都劫持了,为啥不用 LXCFS?
>A:LXCFS目前仅支持改变容器的CPU视图(/proc/cpuinfo文件内容)并且只有--cpuset-cpus参数可以生效,对于系统调用sysconf(_SC_NPROCESSORS_ONLN)返回的同样还是物理机的CPU核数。另:我们采用的劫持方案已开源,欢迎围观:https://github.com/agile6v/container_cpu_detection

以上内容根据2018年7月17日晚微信群分享内容整理。分享人赵云,小米云平台运维部SRE,负责小米有品产品线运维工作。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

DockOne微信分享(一八十):Hulu大规模容器调度系统Capos

Andy_Lee 发表了文章 • 0 个评论 • 1341 次浏览 • 2018-07-13 15:24 • 来自相关话题

Hulu是美国领先的互联网专业视频服务平台,目前在美国拥有超过2000万付费用户。Hulu总部位于美国洛杉矶,北京办公室是仅次于总部的第二大研发中心,也是从Hulu成立伊始就具有重要战略地位的分支办公室,独立负责播放器开发,搜索和推荐,广告精准投放,大规模用户 ...查看全部
Hulu是美国领先的互联网专业视频服务平台,目前在美国拥有超过2000万付费用户。Hulu总部位于美国洛杉矶,北京办公室是仅次于总部的第二大研发中心,也是从Hulu成立伊始就具有重要战略地位的分支办公室,独立负责播放器开发,搜索和推荐,广告精准投放,大规模用户数据处理,视频内容基因分析,人脸识别,视频编解码等核心项目。

在视频领域我们有大量的视频转码任务;在广告领域当我们需要验证一个投放算法的效果时,我们需要为每种新的算法运行一个模拟的广告系统来产出投放效果对比验证;在AI领域我们需要对视频提取帧,利用一些训练框架产出模型用于线上服务。这一切都需要运行在一个计算平台上,Capos是Hulu内部的一个大规模分布式任务调度和运行平台。

Capos是一个容器运行平台,包含镜像构建,任务提交管理,任务调度运行,日志收集查看,Metrics收集,监控报警,垃圾清理各个组件。整个平台包含的各个模块,如下图所示:
1.png

用户可以在界面上创建镜像描述符,绑定GitHub的repo,生成镜像。之后在界面上创建作业描述符,填上镜像地址,启动参数,资源需求,选择资源池,就可以运行作业,看作业运行日志等。这些所有操作也可以通过REST API来调用,对于一些高级的需求,Capos提供Golang和Python的SDK,可以让用户申请资源,然后启动作业,广告系统就是利用SDK,在Capos上面申请多个资源,灵活的控制这些资源的生命周期,一键启动一个分布式的广告系统来做模拟测试。

Capos大部分组件都是用Golang实现的,Capos的核心组件,任务调度运行CapScheduler是今天主要和大家分享和探讨的模块。CapScheduler是一个基于Mesos的Scheduler,负责任务的接收,元数据的管理,任务调度。CapExecutor是Mesos的一个customized executor,实现Pod-like的逻辑,以及pure container resource的功能,在设计上允许Capos用户利用Capos SDK复用计算资源做自定义调度。

Capos Scheduler的架构图如下所示:
2.png

上图浅蓝色部分是Mesos的组件,包括Mesos master,Mesos agent,Mesos zookeeper。Mesos作用是把所有单体的主机的资源管理起来,抽象成一个CPU、Memory、Port、GPU等的资源池,供之上的Capos scheduler使用。

其中Capos scheduler是一个active-standy的HA模型,在scheduler中我们实现了一个raft based的k-v用来存储Metadata,active的scheduler注册成为Mesos之上的一个framework,可以收到资源,根据调度策略来启动作业。

Capbox是一个定制实现的Mesos的executor,作为Mesos agent的资源的占位符,接收请求与Mesos agent上的Docker daemon通信启动容器。其中也实现了POD-like的功能,同时可以启动多个容器共享network,磁盘等。

Capos scheduler提供两类作业运行,一个是简单作业直接在Capbox运行,另一个是复杂带有编程语义的作业,我们称之为AppMaster,其本身运行占用一个CapBox,然后通过编程语义二次申请CapBox运行作业。
首先说明下简单作业运行流程,这里的简单作业,提交的作业通过json描述,可以包含多个Container,然后scheduler收到请求之后,命中某个offer,向Mesos发送offer启动请求,在请求中同时夹带着作业json信息,把作业启动起来,scheduler根据Mesos状态同步信息来控制作业的生命周期。

如果是AppMaster Programmatically二次调度的作业,首先需要把AppMaster启动,这部分和简单作业运行是一致的,然后AppMaster再申请一个到多个资源来启动CapBox,运行作业。此时AppMaster申请的CapBox的生命周期完全由AppMaster决定,所以这里AppMaster可以复用CapBox,或者批量申请CapBox完成自己特定的调度效果。多说一句,AppMaster可以支持client-mode和cluster-mode,client-mode是指AppMaster运行在集群之外,这种情况适用于把AppMaster嵌入在用户原先的程序之中,在某些场景更符合用户的使用习惯。

说完Capos的使用方式后,我们可以聊下在Capos系统中一些设计的思考:

1、Scheduler的调度job和offer match策略,如下图所示:
3.png


  1. 缓存offer。当scheduler从Mesos中获取offer时候,Capos scheduler会把offer放入到cache,offer在TTL后,offer会被launch或者归还给Mesos,这样可以和作业和offer的置放策略解耦。
  2. 插件化的调度策略。Capos scheduler会提供一系列的可插拔的过滤函数和优先级函数,这些优先级函数对offer进行打分,作用于调度策略。用户在提交作业的时候,可以组合过滤函数和优先级函数,来满足不同workload的调度需求。
  3. 延迟调度。当一个作业选定好一个offer后,这个offer不会马上被launch,scheduler会延迟调度,以期在一个offer中match更多作业后,再launch offer。获取更高的作业调度吞吐。

2、Metadata的raft-base key value store

1. 多个scheduler之间需要有一个分布式的kv store,来存储作业的Metadata以及同步作业的状态机。在scheduler downtime切换的时候,新的scheduler可以接管,做一些recovery工作后,继续工作。
2. 基于Raft实现的分布式一致性存储。Raft是目前业界最流行的分布式一致性算法之一,Raft依靠leader和WAL(write ahead log)保证数据一致性,利用Snapshot防止日志无限的增长,目前Raft各种语言均有开源实现,很多新兴的数据库都采用Raft作为其底层一致性算法。Capos利用了etcd提供的raft lib, 实现了分布式的一致性数据存储方案。etcd为了增强lib的通用性,仅实现了Raft的核心算法,网络及磁盘io需要由使用者自行实现。Capos中利用etcd提供的rafthttp包来完成网络io,数据持久化方面利用channel并行化leader的本地数据写入以及follower log同步过程,提高了吞吐率。
3. Capos大部分的模块都是Golang开发,所以目前的实现是基于etcd的raft lib,底层的kv存储可以用BoltDB,Badger和LevelDB。有些经验可以分享下,在调度方面我们应该关注关键路径上的消耗,我们起初有引入StormDB来自动的做一些key-value的index,来加速某些带filter的查询。后来benchmark之后发现,index特别在大规模meta存储之后,性能下降明显,所以目前用的纯kv引擎。在追求高性能调度时候,写会比读更容器达到瓶颈,BoltDB这种b+ tree的实现是对读友好的,所以调度系统中对于kv的选型应该着重考虑想LevelDB这种lsm tree的实现。如果更近一步,在lsm tree基础上,考虑kv分离存储,达到更高的性能,可以考虑用badger。不过最终选型,需要综合考虑,所以我们底层存储目前实现了BoltDB、Badger和LevelDB这三种引擎。

3、编程方式的AppMaster

1. 简单的作业可以直接把json描述通过REST API提交运行,我们这边讨论的是,比较复杂场景的SaaS,可能用户的workload是一种分布式小系统,需要多个Container资源的运行和配合。这样需要Capos提供一种编程方式,申请资源,按照用户需要先后在资源上运行子任务,最终完成复杂作业的运行。
2. 我们提供的编程原语如下:

1. Capbox.go capbox是Capos中资源的描述:
4.png

AppMaster可以用这些API申请资源,释放资源,获取资源的状态更新,在此基础上可以实现灵活的调度。
2. Task.go task也就是可以在Capbox上运行的task,如下图所示:
5.png

在资源基础上,appmaster可以用api启动/停止作业,appmaster也可以复用资源不断的启动新的作业。基于以上的api,我们可以把广告模拟系统,AI框架tensorflow,xgboost等分布式系统运行在Capos之上。

4、Capos对比下Netflix开源的Titus和Kubernetes

1. Netflix在今年开源了容器调度框架Titus,Titus是一个Mesos framework,titus-master是基于fenso lib的Java based scheduler,meta存储在cassandra中。titus-executor是Golang的Mesos customized executor。因为是Netflix的系统,所以和AWS的一些设施是绑定的,基本上在私有云中不太适用。
2. Kubernetes是编排服务方面很出色,在扩展性方面有Operator,Multiple Scheduler,CRI等,把一切可以开放实现的都接口化,是众人拾柴的好思路,但是在大规模调度短作业方面还是有提升空间。
3. Capos是基于Mesos之上的调度,主要focus在大规模集群中达到作业的高吞吐调度运行。

在分布式调度编排领域,有诸多工业界和学术界的作品,比如开源产品Mesos,Kubernetes,YARN,调度算法Flow based的Quincy,Firmament。在long run service,short term workload以及function call需求方面有Service Mesh,微服务,CaaS,FaaS等解决思路,私有云和公有云的百家争鸣的解决方案和角度,整个生态还是很有意思的。绝技源于江湖、将军发于卒伍,希望这次分享可以给大家带来一些启发,最后感谢Capos的individual contributor(字母序):chenyu.zheng、fei.liu、guiyong.wu、huahui.yang、shangyan.zhou、wei.shao。
#Q&A
Q:Capos如何处理健康检查?之前了解到,Mesos内置的健康检查不是特别完善。

A:目前Capos focus的作业大部分都是短作业类型,所以我们目前就是通过容器的退出码来判断success或者fail,如果你说的健康检查是针对服务的,一般实现是支持多种健康检查的方式,bash,http等,然后为了大规模容器运行情况下的可用性,建议这种健康检查的发起client和服务instance是在一台机器上,或者是一个Pod中,发现不健康通过某种机制上报,或者退出Container,但是需要控制Threshold以免整个服务downtime。这样可以探测instance的健康,整个服务的健康,可以在通过外部的一些子系统去check。



Q:关于调度方面,分享中只提到了使用了一系列的可插拔的过滤函数和优先级函数,我想问下能否具体描述下如何被调度的?和yarn里使用的Fair Schedule或者DRF算法的异同有哪些?因为对于多种资源维度的调度是一个很复杂的问题,希望知道Hulu这方面有什么心得和思考?

A:目前实现是,会针对一个请求,首先根据过滤函数比如一些constraints进行offer过滤,然后剩下的offer apply所有的优先级打分函数,进行打分,打分的时候,会根据一个请求和offer的资源,算CPU和mem的比例,选取出dominate的resource进行主要评分,然后选取最优的offer进行bind,bind之后不会马上调度,而是会delay scheduler,这样一般在比较繁忙的情况下,一次offer launch可以启动多个tasks,这是对于大规模吞吐的考虑。 以上这些实现还是queue-base的调度,借鉴了一些Fair Schedule和drf的思路,具体差别你了解了Capos scheduler策略后,应该就会有自己的想法了。多种资源维度,目前我们是根据dominate resource作为主要评分标准的,当然你也可以看下我最后分享提到的一些flow-base的scheduler算法,比如firmament。希望可以回答你的问题。



Q:Capos是否支持,数据中心之间的备份/切换。比如Zone - A的数据中心出现网络故障,把服务迁移到另一个指定的区域 Zone - B(仍然考虑恢复以后优先部署到 Zone - A)。之前考虑是类似一个Mask的机制,如果故障就加一定的Mask值(比如Opcacity)在某个集群上,然后调度的时候去参考这个Mask值,不知道Hulu有没有类似的需求或者考虑过这样的机制?

A:Capos是on Mesos,Mesos是根据zk做选主,而且Capos scheduler中还有一个raft base key value store,所以这些条件,使得Capos是一个datacenter的解决方案。目前Hulu是有多个DataCenter的,所以看架构组件图,你可以看到,我们有一个Capos portal,在这个组件下,是可以选择不同DataCenter去run workload。所以我们目前对于数据中心的备份和切换,主要是依赖Capos portal这个组件,在Gateway的位置做的控制。



Q:想请问下Capos的鉴权是怎么做的,有没有用户权限认证系统?此外,针对每个用户有没有容器资源使用量的限制?

A:可以翻到之前share的架构组件图,我们有一个Capos portal组件,这个组件是提供Restful API和Portal,我们在这边集成Hulu SSO,然后关联Hulu yellowpages(Hulu的服务权限控制系统),做的用户的认证,我们分成自己的Capos APP, team的APP,别的组无法操作不属于自己的Capos APP。对于Quota的管理,我们做了Queue/Label机制,每个服务会建一个标识,然后在标识底下配置总的资源使用量,以及可以用的机器列表(通配符),用这样的机制控制Capos的用户资源使用。



以上内容根据2018年7月10日晚微信群分享内容整理。分享人杨华辉,Hulu senior software developer,目前在Hulu beijing cloud infrastructure组,主要从事分布式容器调度,分布式存储方面的研发。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

Mesos上搭建hadoop遇到的问题

回复

Miss刘 发起了问题 • 1 人关注 • 0 个回复 • 1405 次浏览 • 2018-06-26 11:59 • 来自相关话题

Mesos container在360广告系统的应用

尼古拉斯 发表了文章 • 0 个评论 • 1238 次浏览 • 2018-05-12 18:16 • 来自相关话题

【编者的话】本文作者将技术与业务相结合,讲解Mesos与Container的技术架构,面对当前的业务痛点,可以解决哪些问题,并且如何应用到360商业广告系统中。 #背景简介 我是一名SRE工程师,我们负责管理与维护360商业广告平台 ...查看全部
【编者的话】本文作者将技术与业务相结合,讲解Mesos与Container的技术架构,面对当前的业务痛点,可以解决哪些问题,并且如何应用到360商业广告系统中。
#背景简介

我是一名SRE工程师,我们负责管理与维护360商业广告平台,说起SRE工程师大家可能会想到谷歌公司,因为SRE毕竟是谷歌提出的概念。

作为SRE工程师我想说一下我们的自我修养。我们的主要工作是减少琐事,不断的扩大服务规模,同时我们还要保证整个系统的高可靠性和可维护性,不能随着业务规模的不断增大,招揽越来越多的人来维护业务是不合理的。

我们广告通过360搜索或者360手机端的应用进行展示,比如在360搜索输入“鲜花”会有广告展示,每天有数百亿次的投放与展示,手机端主要通过360的手机安全卫士,手机助手等等的一些应用进行广告的投放与展示。
01.jpg

#Why Container?

说一下为什么要使用容器解决我们的问题,还有演讲的主题为什么不写Why Docker?

说到容器大家第一时间会想到Docker,它实现了一个容器引擎(Docker engine)。除了Docker,在容器生态圈还有一些公司他们实现了自己的容器引擎,比如CoreOS的RKT,比如我们使用的Mesos的容器引擎(Mesos containerizer),这些引擎不依赖于Docker本身,可以解决稳定性和扩展性的问题。
##业务痛点

我先不说我们为什么用容器解决这些问题,说一下业务上我们有哪些痛点,并且这些问题可能大家都会碰到。

  1. 数据中心迁移,这个问题大家多数都会遇到,在迁移过程中要把之前的业务熟悉一遍,需要重新部署,测试还会遇到一些环境配置不一致的问题。

  1. 故障恢复,服务器宕机之后,传统业务都部署在物理服务器上,这样也需要重新部署,这样会带来很多麻烦。

  1. 操作系统不一致,现在我们很多不同的操作系统,比如CentOS 5、6、7都在用,迁移的时候很麻烦,还有一些系统内核的Bug需要去解决。

  1. 生产环境配置不一致,生产环境有一些服务器工程师都可以登录,如果改了一些配置导致线上出现问题的情况也是可能发生的。

  1. 测试环境不一致,可能每个人申请一台虚拟机专门做测试,导致测试结果也不一致。

  1. 服务的扩展性较低,传统业务扩容一般需要一台中控机或者有一套部署环境,每一次都需要重新添加一批服务器进行扩容。

  1. 服务器资源利用率问题,使用物理机部署服务,每一天都有服务的高峰低谷,由于采用静态资源划分的方式,资源利用率非常低会给公司造成很多资源上的浪费。

下面我来说一下我们为什么要用Docker来解决我们的问题。

Docker有一个隐喻叫“集装箱”。其实Docker的英文翻译是“码头工人”,这个隐喻给使用者很多暗示,告诉大家快来使用Docker吧,使用Docker就像使用集装箱一样,能够随时随地的,无拘无束的启动你的应用。像Docker官方的口号一样“build、ship、and Run Any APP Anywhere”,Docker为什么可以解决我们遇到的这些业务痛点呢?因为集装箱是有固定的标准,它的大小一致,这样货物在公路、铁路、海洋运输就不用考虑货物的尺寸等问题了,并且依赖大型机械化进行转运,等于是实现了一套标准的运输体系,可以给整个世界带来很大的商业潜力。
##Docker的标准化怎么实现?

正如我上面说到的,Docker的实质化就是标准,Docker的标准化是怎么实现的呢?

首先,Docker有自己标准化的文档管理方式,它的标准化文档方式就是有自己的Dockerfile,可以定义一系列的软件系统版本。

第二点,Docker有对应用的统一操作方法,在物理环境不同的应用有不同的启动方法,如果你用Docker启动程序,可以通过docker run的方式来启动。在服务迁移过程中只要使用docker run命令来启动你的程序就可以了。

第三点,为了维护生产环境的一致性和配置变更的幂等性,Docker创造性的使用了类似Git管理代码的方式对环境镜像进行管理。每次都需要docker pull下载镜像,Docker container本身只有container layer这一层可写,你每次重新部署的时候这一层是会被删掉的,这样可以保证Docker实际环境每次都是幂等的。
##在服务容器化过程中可能遇到的问题

在服务容器化过程当中,我们可能会遇到哪些问题?当大家使用物理机的时候,为了SSH登陆服务器,每台服务器都会开通SSH服务并且添加对应的账号。如果你使用Docker服务还要开通SSH服务的22端口,你需要考虑一下你的服务是否真的需要登录到容器中,或者你容器化的方式是否正确或者它是否适合你的业务。还有一些人这样使用Docker:在容器中开放rsync服务端口,甚至还有在Docker container里面部署puppet agent同步工具,这样做我觉得是完全没有必要的。我们都是不支持SSH或者类似的服务连接到Docker内部的。
2.jpg

如果你不让我登录到物理机上,不让我连到Docker内部,我怎么看我的日志呢?

我们有一套日志系统,后端对接的服务是Elasticsearch,会使用Docker的syslog模块通过UDP的方式写入Graylog里,Graylog或者Grafana都可以进行展示、查询,这样我们就可以及时的发现线上的问题。
3.jpg

##Docker的网络性能

4.jpg

使用了Docker,大家可能会考虑,它的网络性能会怎么样,我们其实也做过一些调研。我们主要用的是Hostonly和Bridge这两种模式,如果用Hostonly基本和直接在物理服务器上运行程序的性能是差不多的,现在我们也有团队专门做Calico服务方面的研究,比如你有一些爬虫服务,可能希望有一些独立的外网IP,可以考虑使用Calico为一个container单独分配外网IP。

或者有网络隔离的需求的话,也可以使用Calico服务。由于我们主要针对是私有云,直接用hostonly模式多一些。
##存储镜像

关于Docker仓库,大家可能会问服务容器化之后,主要用什么仓库存储镜像呢?哪种镜像仓库比较好?之前我们搭建过Docker官方的仓库,只有单节点不是高可用的,数据可靠性也不是非常好,我们是用的无认证模式。

现在我们使用了Harbor,用这个系统做了二次开发,后端存储用的S3存储系统,数据可靠性是非常高的,多机房之间可以进行数据同步,支持用户认证,大家根据自己的用户密码进行登录上传镜像等操作。之后我们还会做一个Docker仓库的CDN化,多机房直接访问CDN服务下载镜像。
5.jpg

##怎样把数据写到本地

大家使用Docker可能会考虑数据怎么写到本地,我们使用Mesos+Docker之后,是不是所有服务都要需要无状态的呢?我们推荐无状态服务运行在Mesos+Docker之上。但是如果你有把日志落到本地的需求,我们现在也是可以支持的。
6.jpg

我列出的这些产品,比如CephFS、MySQL、Kafka、HDFS、Aerospike、Redis都是数据持久化的一种方式,比如流式数据一般用Kafka多一些,数据直接通过Kafka消费出来,通过一些计算模型后再重新写入Kafka,或者如果想数据落到本地的需求直接在Container中挂载CephFS也是可以的。
##服务的注册和发现

关于服务的注册和发现,大家可能会有一些问题。比如我用了Mesos+Docker之后,我们的一些服务是在mesos-slave节点之间飘逸的,有可能因为一台物理机宕机了,你的服务会在另外一台mesos-slave节点上启动,我怎么知道我的服务启动到具体哪台IP或者具体哪台机器上呢?
7.jpg

我们服务发现主要用的是Mesos-DNS还有Marathon,底层数据依赖于ZooKeeper。还有一些公司可能用etcd或者Consul,我们也有在用不过比较少。

关于使用了Docker,服务如何进行调度?还有Docker服务如果对于本地数据有依赖的话需要如何加载?希望大家可以带着问题思考一下,一会儿我会详细说明。
#Why Mesos?

为什么要用Mesos?

当前遇到的一个背景就是在当前互联网环境下,越来越多的分布式计算系统产生。
8.jpg

如果说维护一个大型业务团队需要部署的框架或者分布式系统非常多,但是市面上又没有一种系统能够把所有的应用框架都部署到一个集群里,这样就会导致我之前说的比如资源利用率会很低,可维护性很低。因为不同的集群有不同的配置,所以我们就想把这些多个应用布到一个大型的资源池里,这样可以更好的共享硬件资源。因为我们的服务都是支持动态扩缩容的,这样也可以简化一些部署上的逻辑,并且最大化的利用资源,最终实现服务可调度,数据可以共享。
##使用Mesos的优点


1、资源利用率非常高

因为之前大家用物理服务器的时候,是静态资源划分的方式,这种方式资源浪费得比较多。因为服务每天都有高峰和低谷时段,如果你用Mesos的话,使用了动态服务扩缩容,比如白天广告展示的量会非常大,最高的时候每秒已经超过一百万,但是在晚上访问量非常低,你就可以把这批机器资源释放出来,供一些离线业务运行,比如Hadoop。可以达到最大化的资源利用率。
9.jpg

2、便捷性

Mesos本身支持对所有资源打标签,大家可以打固定的标签。这样在提交资源的时候,可以根据你想要的资源提出申请。比如你想要一个GPU的资源,比如你要1核的我就会分配给你一核的,像乘坐飞机一样,你想坐头等舱只要有资源就可以分配给你,Mesos也是这样,我们支持端口、CPU、内存、硬盘等等的划分。
10.jpg

3、可扩展性非常好

因为它本身的设计原理是两极调度框架,这样带来的好处是它非常的简单。因为Mesos本身只负责资源调度,把任务调度交给了运行在它之上的具体框架进行调度。所以如果你要横向扩展Mesos的话,非常方便。
11.jpg

4、模块化

因为Mesos支持在Mesos API之上定义各种各样的framework,大家可以自由添加framework,我们主要用的Marathon、Flink等官方与自定义framework,具体使用哪种框架,大家可以根据需要去设计。
12.jpg


Mesos的目标

Mesos的目标,其实主要就是给我们带来资源的高利用率,支持多种多样的自定义框架,包括当前支持的还有以后新产生的分布式计算框架等,都可以建立在Mesos之上。

* 可扩展性。现在全球节点最大的是Twitter有45000个mesos-slave。

* 可靠性。因为Mesos采用的是热备的方式,存在一个master节点,如果遇到主从节点切换的时候非常快,大概10秒钟就能完成。

Mesos的架构
13.jpg

Mesos的主要组成是由ZooKeeper实现master的高可用,还可以保证数据的一致性,保存所有的Mesos sleve节点和信息。Mesos master主要用于接收agent上报给Mesos master的资源,Mesos master会分配offer给具体给它之上运行的framework。

Framework是基于Mesos API定义的调度器,会根据调度需求分配具体的offer。

最底层是Mesos agent,用来接受和执行Mesos master发给它的命令,通过Mesos agent之上的executor启动task。

Mesos的实现

Mesos是用的两万行的C++代码编写而成,故障恢复使用的是ZooKeeper,框架都是可拓展的、可以自定义的,并且是模块化的。是Apache顶级的孵化项目,同时还是开源的,项目成立于2009年。

Mesos的结果

Mesos给我们带来的是更高的资源利用率与可靠性。
##Mesos master的故障恢复机制

接下来说一下Mesos master的故障恢复机制。
14.jpg

因为Mesos master只有一个软体状态,只会列出它之上的framework以及mesos-slave的信息,在Mesos master需要进行切换的时候,通过ZooKeeper进行leader的重新选取,选取好新的leader后,只需要所有的framework和mesos-slave节点重新注册到新的Mesos master之上,时间就10秒钟左右。如有你有上万台机器,可能会同时连Mesos master会不会造成大量的链接导致master服务不可用,官方有这样的设置可以设定链接的比例来进行控制。
##Mesos的生态圈有哪些框架

Marthon framework
15.jpg


* 运行长任务。从应用框架字面的意思,任务就像跑长跑一样,这个框架其实就是运行长任务(long running job)的。

* 服务发现。Marathon还可以实现服务发现,有比较好的API接口,比如我有一个APP id对应具体机器的IP是什么。

* 健康检测&事件通知机制。Marathon支持对你所启动的任务进行健康检测,比如端口或者你自定义命令都可以,有事件通知机制,正因为有了事件通知机制才可以在马拉松之上建立一些实时的服务发现,知道哪些服务宕掉了,在哪些新节点启动了,可以保证我们的实时发现服务,重新指向新的服务器。

* WebUI。Marathon有自己的Web UI,可以通过界面直接操作,非常方便。

* 限定条件。你可以设定一大堆的限定条件,比如我之前说的像你选飞机的舱位一样,你设定了网卡必须是万兆的,Marathon会根据你设定的限定条件,帮你选择对应资源。

* Labels。Labels标签也是我们常用的,随着资源利用率越来越大,可能有各种应用,大家可以加上各种的标签,方便的查询。

* 数据持久化。数据持久化也是支持的,可以支持挂载本地卷。

* 服务的预热。这个功能用得不是特别多,比如你在服务启动的时候会需要启动时间,这个时间健康检测是失败的,你可能需要设定一个预热时间,保证服务启动之后正常的健康检测才生效。

* 优雅退出。优雅退出这个问题,大家可能都会遇到,比如像C++不涉及内存自动回收可能需要程序上设计优雅退出的问题,你可以通过Marathon设置一个退出时间,保证你的服务正常退出之后,才把以前的服务都退掉,新的服务启动。

* 支持自定义的containerizer和GPU资源的调度。

Marathon-LB
16.jpg

Marathon-LB是我们用的一个实时发现的服务,Marathon-LB是基于Haproxy和Marathon eventbus机制设计的。其实除了Marathon-LB还有一些其他的服务实时发现,但是都是基于Marathon的事件通知机制设计的。因为Marathon有事件总线的实时更新,可以实时的改变服务后端的IP。如果有宕机或者有服务自动扩缩容的话,Marathon-LB可以实时改变Haproxy的配置,Marathon-LB主要是通过第四层IP加端口的方式进行服务代理,Marathon-LB支持TCP或者HTTP的代理方式。

Mesos-DNS
17.jpg

我们还使用了Mesos官方的Mesos-DNS服务,用于一些对实时性要求不高的服务,比如我们把STORM容器化以后Nimbus和Supervisor之间的通信可能就不是那么频繁,如果有Nimbus宕机的情况,只需要通过Mesos-DNS就可以重新发现AppID对应的新的Nimbus IP。你可以使用Mesos-DNS发现AppID对应的所有后端节点的IP,可以保证你的服务节点随时都可以访问到你想访问到的IP。Mesos-DNS有一定的延迟性,我们测试大概有十几秒。
#Mesos VS YARN

我说一下在我们做技术选型的时候,我们也做过Mesos和YARN方面的调研。

Mesos主要是能调度各种样的资源,有CPU、内存、端口、硬盘;YARN主要是CPU和内存。

两者都是两极调度策略但是又有不同。

Mesos本身只做资源的调度,不负责具体任务的调度,把任务调度交给framework调度。

YARN全都是YARN本身进行资源调度,一个程序提交给它一个任务都由YARN来决定是否接受或者拒绝这个资源,而Mesos却不同。

Mesos因为是对物理资源进行管理与调度的,YARN主要基于Hadoop来做。

根据需要,我们最后还是选择了Mesos来作我们的分布资源管理框架。
#Mesos VS Kubernetes

说起Mesos可能很多同学觉得使用了Marathon提供了容器任务的管理能力,可能就需要跟Kubernetes系统进行比较一下。

本身来讲,Mesos和Kubernetes是两个东西,Mesos是一个分布式的资源管理框架,被称为分布式系统的内核。假如你有很多物理资源,你想把它整合成一个逻辑资源层面的物理资源池,那么你用Mesos是最合适不过的了。

Mesos解决问题的核心是如何把资源整合成一个大型的物理资源池,它上面运行什么,怎么跑它并不关注。

Kubernetes主要是一个自动化的容器操作平台,操作主要包括部署、调度还有节点集群间的扩容等等。

Kubernetes解决问题的核心主要是围绕容器来做的,这两个系统本身没有可比性。因为Mesos支持很多framework,比如Marathon可以实现容器的调度,所以大家就会把这两个平台进行比较。

如果你想搭建这样一个容器管理平台或者调度平台,从我个人来讲第一点从任务上来讲,Marathon只支持长任务型的,Kubernetes支持的比较广,比如支持长时间任务(long running job),节点后台支撑型(node-daemon)等等各种各样的任务。

说一下稳定性方面,Kubernetes是谷歌官方推出的,它的更新比较频繁,更新频繁可能带来的就不是特别稳定,大家可能理解我可以多做一些线下测试,但是事实确实是这样的,Kubernetes更新非常频繁。Mesos一般每半年更新一次,一年发布两个版本,会经过充分测试。Mesos产品设计因为是开源的,是Apache基金会下面的顶级项目,会在社区跟大家进行投票与沟通,决定未来我们的产品怎么做,我们会增加哪些功能。

第三种主要是从功能上来讲,Kubernetes是由谷歌做的,所以它的考虑会非常全面,它的生态非常全面,你想要的功能基本都有,包括网络Kubernetes其实也是有的,其实Kubernetes本身的网络做得不是特别好,很多用Kubernetes都是用Calico实现的。Mesos系统的设计思路则定义了任务调度和功能上整体依赖于调度器的设计,所以可以把Mesos看成一个大乐高底层的基础板。

对于这两个框架,选择哪一个都没有对与错,只有适合与否,选择一个适合你们的工具才是最重要的。
#Mesos/Container在360的一些应用

我说一下Mesos/Container在360的一些应用。
18.jpg

我们从2015年开始,就对分布式的调度系统或者容器调度平台进行了调研,最后选择使用Mesos,因为我们想构建一个大型的物理资源池。在2016年业务正式上线,包括之后说的一些服务的容器化,2016年我们也使用了Chronos,可以运行一些物理机上运行的crontab任务,长时间支持服务在线运行。2017年我们已经实现了两个机房各部署了一个大型的资源池,节点达到了单集群最大1000个以上,任务达到5000个以上,10个以上的自定义framework。
##解决的问题

部署,现在部署可能你只需要在Marathon上改变你的镜像(image)地址,或者只需要把instance数改大就可以扩容。

故障恢复,如果有一台mesos-slave宕掉了,会自动在其他的节点上启动。

服务降级,关于服务降级,我们的资源池服务器是有限的,1000台服务器如果资源快用满了,有些业务就需要做服务降级,不是所有业务都有动态扩缩容。我们主要处理广告业务,广告业务实时日志流比较多,在资源不够的时候,会让某些业务降级。平时每秒处理20万条,降级时让它每秒处理10万条或者5万条,有一定数据延迟也没有关系,因为数据不会丢只会慢慢处理完。

服务发现,关于服务发现,现在有了Mesos-DNS和Marathon-LB我们可以做到实时的服务发现,因为是动态资源划分,我们的任务就可能实时变化。
##Storm集群的容器化

19.jpg

上图是原来通过物理级部署的,所有的Supervisor节点都是一台台物理机还要单独部署一个Nimbus,如果Nimbus节点宕掉非常麻烦,比如有些同学说我可能会用Keepalived做高可用,这确实是一种方案,但是如果你的集群需要频繁的扩容或者缩容就会非常麻烦,你要是不对资源进行动态管理的话,势必带来的就是资源的浪费,因为不可能一天24小时都满负荷运行。

把服务容器化之后,所有的Supervisor都运行在container(mesos-slave)中,Supervisor节点会通过Mesos-DNS发现Nimbus(master)的IP。现在集群资源都是动态利用的。
20.jpg

##图片服务的容器化

重点说一下图片服务的容器化。
21.jpg

图片服务主要用的PHP 7来做的,我们也会面临像阿里一样在双十一的时候,因为广告展示与投放量非常大,每秒达到上百万次,因为给用户进行展示与投放的图片会根据用户的习惯去动态的缩放与拼接。如果我放着很多机器专门用来做图片服务,可能也可以达到你的需求,但是在空闲时间段比如夜里资源浪费得非常多,对资源的利用率不是非常好。

我们就制定了这样一套方案,首先把PHP服务容器化,之后我们根据亚马逊AWS的策略,做了自己的方案,跑一个long running job,根据Marathon的API获取你的图片服务具体是哪台机器,由于所有机器上的监控都用了二次开发,通过API接口能获取负载、CPU,内存等等信息。当图片服务器的负载上升了肯定是压力最大的时候,这样我们只需要设定一个阈值。

比如系统负载大于10超过10次,就进行一次扩容,扩容的倍数是1.5倍,原来我有10台机器,现在要扩容到15台。大家可能会问你这个最大能扩到多少?我一定要设定一个最大值不能无限的扩。比如我们设定一个36,最大扩到36台,在5分钟内可能判断10次,如果这个负载水平一直很高,就不进行缩容。

我肯定还会设定一个最低值,比如最低值是6台,可能到了夜里直接减为6台,每次都需要通过Marathon的API实时发现后端所有机器计算出一个平均值。服务的监控,我们对每台Mesos slave都有监控,具体的container我们做了异步,通过异步把日志写到Graylog中,监控日志传输通过UDP协议。如果发生网络中断的情况也不会有太大影响,因为UDP是可丢的不可靠的。
##其他

我们还有其他服务的一些容器化,有Web service相关的,Aerospike服务,通过组播实现集群之间的通信部署起来比较方便,Marathon-LB也是完全的Docker化的,毕竟是代理层像LVS一样,可能会有服务瓶颈。Kafka MirrorMaker我们用来进行多机房之间的数据传输,原来直接部署在物理机上,这样虽然不会有太大问题,如果宕掉之后数据不能在多个集群当中进行同步,对实时性不能要求那么高。如果做了容器化之后是可调度的,都是可高可用的,我们会保证服务的可靠性。Redis也有做容器化,支持数据的落地和持久化,因为我们有CephFS还有更多的一些无状态的服务也运行在Mesos之上。
22.jpg

最后我要说一下我们的服务CI/CD是怎么做的,CI/CD主要是通过GitLab runner。我们会定义一个Gitlab-CI,可以直接把你提交的代码进行Docker build,把镜像自动提交到对应的仓库,通过API修改Marathon上面对应的地址,最后实现上线自动化。
#未来计划

未来我们想做的,因为CephFS的量不是很大,CephFS之后想上一些写入量比较大的业务,看看效果如何。我们不是做公有云的对于Calico的需求不是那么急切,之前一直没有上这个服务。之后我们可能会做一些Calico相关的,比如一些爬虫的应用,如果用公司的Nat代理的话,可能遇到一些IP被封,导致整个代理IP都不能访问对应的网站就有一些问题了。

还有一些实时的机器学习,现在机器学习主要都基于离线业务来做,实时学习比较少,Marathon和Mesos本身是支持的。

原文链接:Mesos container在360广告系统的应用(作者:李冬)

Mesos 1.5发布,在存储、性能资源管理以及容器化方面有重大改进

大卫 发表了文章 • 0 个评论 • 2118 次浏览 • 2018-02-09 11:57 • 来自相关话题

今天,我很高兴向大家宣布,Apache Mesos 1.5.0版本已经正式与您见面! #新的功能与改进 Mesos 1.5当中包含资源管理、存储与容器化方面的多项重大改进。容器存储接口(简称CSI)支持正是Mesos 1.5当中全瓣 ...查看全部
今天,我很高兴向大家宣布,Apache Mesos 1.5.0版本已经正式与您见面!
#新的功能与改进

Mesos 1.5当中包含资源管理、存储与容器化方面的多项重大改进。容器存储接口(简称CSI)支持正是Mesos 1.5当中全瓣的实验性能力之一,此外亦有大量与之配合的新功能伴随1.5版本一道推出。对代理进行重新配置的新能力将使得操作人员拥有更出色的使用体验。性能提升使得主节点故障转移速度提升80%到85%,而v1 API性能也得到了显著改善。新版本中的资源管理机制更为灵活。此外,同样重要的是,镜像垃圾收集与更强大的Windows支持能力使得您能够更轻松地在不同基础设施类型之上运行Mesos,同时亦可在Mesos之上简单运行多种不同工作负载。

在接下来的文章中,我们将共同了解Mesos 1.5当中的各项卓越改进。
#容器存储接口支持

Mesos 1.5以实验性方式增加了对容器存储接口(简称CSI)[1]的支持能力,这项新规范为存储供应商与容器编排平台之间的全部交互活动定义了一个通用型API。这项功能的出现无疑是Mesos、Kubernetes、Cloud Foundry以及Docker技术社区之间密切合作的结果。CSI的主要作用在于允许存储供应商编写出适用于全部容器编排平台的插件。
对CSI的支持将帮助Mesos始终与规模更大的存储生态系统保持步调一致,从而确保Mesos一直具备更强大的存储支持能力。用户将能够在包含Mesos的任何存储系统当中使用一致的API选项。CSI的out-of-tree插件模式将Mesos的发布周期与存储系统的发布周期区分开来,使得集成系统本身更具可持续性与可维护性。
01.png

上图所示为Mesos所支持的CSI高层架构。若需了解更多细节信息,请参阅说明文档
#提升操作人员使用体验

##代理重新配置策略

在Mesos 1.5之前,用户无法对代理的配置作出任何变更——惟一的方法就是关闭该代理上运行的所有任务,并使用新的代理ID重新启动。任何变化,例如添加额外属性或者新接入磁盘驱动器,都将导致代理启动中止并引发令人头痛的错误:
EXIT with status 1: Failed to perform recovery: Incompatible agent info detected.
------------------------------------------------------------
[...]
------------------------------------------------------------
To remedy this do as follows:
Step 1: rm -f /path/to/work_dir/meta/slaves/latest
This ensures agent doesn't recover old live executors.
Step 2: Restart the agent.

从1.5版本开始,操作人员能够使用新的代理命令行标记--reconfiguration_policy 对代理上应当允许的操作类型进行配置。在将该标记的值设置为additive时,代理将能够接受一切对代理资源量的变更以及对其它属性或故障域的调整。

未来,我们还希望能够进一步添加--reconfiguration_policy=any 设置选项以允许对代理配置作出任意变更。
#性能改进

此版本还包括对主节点故障转移与v1操作状态查询API性能的改进。主节点故障转移完成时间的缩短,源自数据吞吐量高达450%到600%的显著提升,这意味着整体完成时间将缩短80%到85%。
02.png

除此之外,v1操作状态查询API的性能也得到了极大改进,这要归功于我们消除了过程中不必要的复制操作。具体来讲,目前v1 protobuf GetState调用速度较v0提高了36%。此外,v1 JSON Get Sstate性能亦提升了四倍以上。
03.png

更多详尽基准测试结果,请参阅此电子表格
#资源管理

##配额保障改进

此次发布的新版本当中引入了多项与配额机制相关的改进。如今,Mesos将能够更好地保证角色获取配额以及角色不致超额等等,例如:

* 此前,一个角色可收集未使用的预留配额以“愚弄”配额系统,但如今新版本会在分配资源时对预留配额进行核算,从而防止这种情况的发生。
* 资源如今会以细粒度方式进行分配,以防止角色出现超额状况。
* 无配额角色可能收到保留资源的bug已经得到修复。
* 角色的保留资源高于配额资源时,可能出现配额空间缺失的问题已经得到修复。
* 当把资源分配给某个具有资源配额的角色时,此前的版本亦会将部分超出该角色配额之外的资源移交给它。这意味着不同角色的资源配额可能无法得到正确执行。目前这个问题已经通过在分配资源时计算余量的方式得到解决。

##资源提供方抽象

为了将资源与代理生命周期加以拆毁,我们引入了资源提供方这一抽象机制。其作用在于支持代理资源的动态变化、外部资源供应方整合乃至集群范围内资源管理。作为资源责任分离思路的组成部分,我们引入了一项新的资源分配协议,旨在更明确地就成功或失败结果进行通信,同时实现各集群组件间的协调。我们使用新的资源供应方抽象将代理本地存储资源同CSI通过接口加以整合。
#容器化与多平台支持

##Windows 支持能力得到改善

随着Mesos 1.5版本的发布,Windows支持能力得到了极大改善。现在,您在利用Mesos容器运行任务时,可以通过作业对象(MEOS-6690)立足操作系统层级实现资源限制。在使用windows/cpu与windows/mem隔离器时,您可以对CPU周期与虚拟内存强制加以限制。此外,新版本现在也能够正确支持CPU与内存统计信息收集。Mesos fetcher已经被移植到Windows平台,支持通过TLS自动下载文件并释放ZIP压缩文件。在进行配置时,libprocess现在可配合Windows上的OpenSSL支持能力进行构建,这意味着TLS连接将可立足集群之内实现(请注意,由于Windows本身不提供OpenSSL,因此您需要在外部构建或安装OpenSSL)。第一种验证方法CRAM-MD5此次也正式登陆Windows,因此代理将可借此与主节点进行验证。HTTP与TCP状态检查机制也已经能够作用于Windows代理(可用于shell任务; Docker容器运行状态检查也即将推出)。Meos代理不再需要以管理员身份运行,因为其现在能够像普通用户一样创建符号链接,且此项功能已经被集成于代理当中。最后,虽然在上一版本中已经实现,但这里不妨再提一句——Windows本地长路径支持已经实现,意味着您将能够更轻松地立足Windows运行代理(无需进行注册表配置)。
##容器镜像垃圾收集

Mesos 1.5版本支持容器镜像垃圾收集。目前您可以通过两种方式对未使用的镜像层进行垃圾收集:自动与手动。这项功能允许用户轻松解决磁盘空间被docker镜像大量占用的难题。具体请参阅容器镜像垃圾收集说明文档以了解更多细节信息。
##独立容器

本次新版本包含一组新的操作程序API,用于启动并管理所谓“独立容器”这一新型原语。独立容器类似于由Mesos代理之上的框架所启动的容器,只是独立容器由操作程序在Mesos代理上直接启动。如此一来,这些容器将无需使用Mesos执行器,且具有其它一些限制特性(例如无法使用预留资源等)。与此同时,独立容器几乎与其它容器完全隔离,并与容器镜像类似——能够使用同样的容器化功能集。

此项功能的发布旨在支持CSI工作流,但各API并不限于此用例。未来,此项功能可能将被用于为各代理节点实现守护进程。具体请参阅MESOS-7302以了解更多细节信息。
#Mesos内部

##支持gRPC客户端

此次新版本包含一套gRPC客户端打包器。gRPC是一种PC机制,并作为RESST API的替代性方案在云原生领域愈发受到欢迎。作为将gRPC整合至Mesos的第一步,我们在libprocess当中添加了此客户端打包器以支持CSI。该功能在默认情况下处于禁用状态,您可以在安装有OpenSSL库的集群当中使用--enable-grpc (autotools)加以启用。该包装类负责在内部维护gRPC运行时数据结构,同时提供一个简单接口,以便实现与libprocess的基于actor模式相兼容的异步gRPC调用。我们还利用这项新功能连接CSI插件。除此之外,大家也可以使用这项新功能创建Mesos模块,用以同其基于gRPC的服务进行通信。
##复制日志改进

Mesos复制日志可帮助各类框架(例如Apache Aurora)将自身状态保存为多套副本,从而在故障转移及重新启动时实现状态保留。从1.5版本开始,大家将能够读取来自一套非主导VOTING复制日志副本处以最终一致化方式进行读取。如此一来,您将能够在非主导框架副本之上进行其它处理工作,例如将部分读取任务移交至待命副本,或者将高频复制日志副本 保留在内存内以缩短故障转移时间。
#升级

从Mesos 1.4.0升级至Mesos 1.5.0非常简单。请参阅升级指南以了解更多与升级至Mesos 1.5.0相关的细节信息。
#社区

您是否在本次发布的新版本中受到了启发?您是否希望参与其中?您对此有何见解?我们期待着听到您的声音!请立即加入工作组或在社区中开启对话!
#鸣谢!

感谢Mesos 1.5.0版本项目组的59位贡献者:

Aaron Wood, Adam B, Adam Dangoor, Akash Gupta, Alastair Montgomery, Alexander Rojas, Alexander Rukletsov, Anand Mazumdar, Andrei Budnik, Andrew Schwartzmeyer, Andrey Dudin, Andy Pang, Anindya Sinha, Armand Grillet, Avinash sridharan, Benjamin Bannier, Benjamin Hindman, Benjamin Mahler, Benno Evers, Bob Eckert, Chun-Hung Hsiao, Cynthia Thomas, Deepak Goel, Dmitry Zhuk, Gaston Kleiman, Gastón Kleiman, Gilbert Song, Greg Mann, Ilya Pronin, Jack Yang, James DeFelice, James Peach, Jan Schlicht, Jason Lai, Jeff Coffler, Jiang Yan Xu, Jie Yu, Joerg Schad, John Kordich, Joseph Wu, Julien Pepy, Kapil Arya, Kevin Klues, Megha Sharma, Meng Zhu, Michael Park, Nathan Jackson, Neil Conway, Packt, Pranay Kanwar, Qian Zhang, Quinn Leng, Richard Shaw, ThodorisZois, Till Toenshoff, Tomas Barton, Tomasz Janiszewski, Vinod Kone, Zhitao Li

希望Apache Mesos 1.5能够让您满意!

原文链接:Mesos 1.5: Storage, Performance, Resource Management, and Containerization improvements

如何在Redhat/Centos上部署marathon bamboo+haproxy开源软件

回复

self_flying 发起了问题 • 2 人关注 • 0 个回复 • 1827 次浏览 • 2017-12-20 15:22 • 来自相关话题

去哪儿网OPS基于Mesos/Docker构建的Elasticsearch容器化私有云

尼古拉斯 发表了文章 • 0 个评论 • 2913 次浏览 • 2017-11-16 15:42 • 来自相关话题

【编者的话】本次分享主要介绍一下去哪儿网 OPS 团队利用 Mesos 资源管理平台和 Docker 容器技术所构建的 Elasticsearch 容器化的私有云。主要有四个部分, 第一个部分主要介绍一个我们当初做这个平台的背景,和现在的规模和现状,第二个部分 ...查看全部
【编者的话】本次分享主要介绍一下去哪儿网 OPS 团队利用 Mesos 资源管理平台和 Docker 容器技术所构建的 Elasticsearch 容器化的私有云。主要有四个部分, 第一个部分主要介绍一个我们当初做这个平台的背景,和现在的规模和现状,第二个部分主要简单介绍一下整个平台的技术实现,最后分享是持续构建方面的工作以及监控和报警相关方面的工作。
#背景与现状

2015年底到2016年初的这段时间,公司业务线对 ES 的需求量暴增,传统的使用 ES 的方式逐渐显现出一些弊端,主要有一下几点的内容:
01.jpg

针对上述所列的几点弊端,我们最初制定的几点设计目标如下:
02.jpg

最终,为了达到这几点目标,我们就设计和开发了这个平台。
03.jpg

自从16年3、4月份这个平台上线以来,工作效率得到了很大改进,主要有以下三个方面:
04.jpg

下面这个图是统计的过去传统的使用方式与现在的平台的方式使用 ES 所带来的资源利用率的提升:
05.jpg

这个是我们目前的平台规模:
06.jpg

07.jpg

整个平台支持了很多重要系统后端的数据存储,比如:
08.jpg

#技术实现

刚开始做这个平台的时候,我们主要调研参考了以下三个系统和平台:
9.jpg

第一个 Elastic Cloud 是 Elastic 官方提供的一个公有云的服务,他能够提供快速集群构建的能力,也具备自助化配置,快速扩容能力,比较符合我们的预期功能。第二个 Amazon Elasticsearch Service 同样也是一个公有云服务,能够提供快速的集群构建能力,自助化配置等等,同样也为我们提供了极大的参考价值。第三个是一个开源的基于 Mesos 的一个调度框架,他的设计是一个 Framework 代表一个 ES 集群,Framework 的每一个 Executor 代表一个 ES 节点,但是也有许多不支持,包括不支持多种角色节点的配置,不支持自助化的配置,不支持插件的安装,这与我们的设计初衷是相违背的。结合了上述三个例子,我们设计指定了我们自己的技术方案。
10.jpg

整个平台基于 Mesos,所有组件以 Docker 容器的形式被 Marathon 调度跑起来,这个是一个整体的结构图:
11.jpg

我们底层所有的机器都是被同一个 Mesos 来进行统一管理的,Mesos 之上运行着 Marathon 调度框架,值得注意的是,我们有两层的 Marathon,底层比较大的 Marathon 我们称之为 Root Marathon,上层包含在 Root Marathon 之中的小的 Marathon 我们称之为 Sub Marathon,Root Marathon 只负责调度内层的Sub Marathon,内存的 Sub Marathon 才是真正承载着我们每一个 Es Saas 服务。我们所有的组件都是跑在 Docker 容器里面的。
12.jpg

那么我们平台的资源是怎么分配的呢,这个图是一个分配的结构图,可以看到资源是按照 Marathon 分层的这种方式来分配的,Root Marathon 拥有系统所有的资源,Sub Marathon 是资源分配的最小单位,每一个都有它既定的资源,资源结构如此,当然集群间的逻辑隔离也是如此。
13.jpg

Sub Marathon 不仅有他自己的资源,而且我们将它和业务线做了一一映射,也就是说一个Sub Marathon 唯一的代表一个业务线,同时它也是承载了业务线的所有集群。

下面这个图展示的是 Sub Marathon 内部细节的结构图:
14.jpg

一个 Sub Marathon 可以承载多个 ES 集群,每一个 ES 集群有4个重要的组件,分别是:Bamboo,es-master,es-datanode,es2graphite,这4个组件是组成 ES 集群的基础,他们分别对应着一个 Marathon 的 APP,APP 的 task 是真正的 ES 节点。 下面这个图展示了上述4种基础组件之间的关系:
15.jpg

默认的 ES 有3个 master 节点和3个 datanode 节点,他们分为两个 Marathon APP 独立运行,他们之间互相的服务发现是由 Bamboo + HAProxy 这个组件来完成的,这样他们才能连成一个集群,es2graphite 负责收集 ES 集群指标,它的原理就是调用 ES 内部的接口获取指标,然后聚合打到后端的 Graphite 上分析展示。pyadvisor 这个组件不是存在每一个集群中的,而是 run 在每一个 mesos slave 上的一个服务,他们负责收集容器维度的指标,聚合之后打到后端 Graphite 上实时展示,下面就是一个具体的 slave 机器上的快照:
16.jpg

每个机器上可以跑多个 ES 节点,不同的 ES 节点之间使用端口号来区别。

在每一个 ES 集群中,起着至关重要作用的就是服务发现,而这个服务发现是由 Bamboo + HAProxy 这个组件来完成的。
17.jpg

Bamboo 是一个开源的跑在 Marathon 之上服务发现的工具,它的原理就是注册了 Marathon 的 callback 接口接受 Marathon 事件消息时时解析并 reload haproxy。

ES 集群内部服务发现的配置其实只是用了一句图中的配置项,这个配置项是 ES 的单播地址,是告诉 ES 节点去哪个机器的哪个端口找 master 的,我们只是简单的把他替换成了 Haproxy 的 host 和 port。ES 节点在起来的时候,Bamboo 检测到启动事件,随即通过 Marathon API 获取到真实的 Master 的 host 和 port,然后 Reload Haproxy 建立端口转发关系,同时,ES Datanode 节点在起来的时候,就会通过 Haproxy 的前端 host 和 port 经转发到真实的 Master 地址上,由此实现了服务发现的过程。三个 Master 之间也是同样的道理,他们通过 Haproxy 再“回连”自己。

在数据持久化和可靠性方面我们做了一下几个方面的工作:
18.jpg

#配置和部署

接下来介绍一下我们做的自助配置和持续构建方面的工作,有关所有的 ES 的配置我们都存在了 GitLab 中,包括一个特殊的 pre-run 文件,这个文件定义了在我们启动 ES 节点实例之前我们该做些什么,这个文件是可以修改的,可以由业务线同学自定义。同时一些其他的配置文件也是存在 GitLab 上的,修改之后,只需要重启容器即可生效。
19.jpg

同时我们在自助管理方面也做了一些工作,下图是我们自己做的一个 Web 系统, 用来展示详细的集群信息和做一些自助化配置方面的工作。
20.jpg

21.jpg

22.jpg

在新集群交付的时候,我们也是直接交付这个 Web 页面,业务线同学可以很方便的查到信息,也可以很方便的做一些操作。说到交付,我们在持续构建方面也做了一些工作。
23.jpg

这个是新的 ES 集群从配置到部署到上线的整个过程,都是基于 Jenkins 来做的,一共有三步,第一步是配置的初始化,这一步中会生成部署过程中所有的配置文件,生成之后直接存储到 GitLab 中,到了第二步集群部署的时候,我们会按照顺序读取配置,一一的将各个组件提交到 Marathon,最后一步就是 Marathon 调度运行,等全部完成之后,我们一个完整的 ES 集群也就 work 了。
#监控与报警

最后一部分说一下监控和报警,监控指标的收集,主要有两个方式:
24.jpg

下面是指标聚合之后的一个示例:
25.jpg

26.jpg

关于报警,主要有一下几个方面:
27.jpg

最后,用一张图来总结一下所有的内容:
28.jpg

从 ES 的建立到销毁,我们做到了 ES 集群整个生命周期的管理,建立初我们会做容量预估和参数的配置,等到部署的时候,我们有持续构建部署的工具来做,服务上线之后我们提供了可以自助配置,自助插件的 web 工具,极大的方便了开发人员,同时也有完备的监控和报警。集群下线的时候,统一的回收资源,做一些清理拓补的工作。

原文链接:OPS基于Mesos/Docker构建的Elasticsearch容器化私有云&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=w4%2BKnbJeburqHxw1NITmvjD%2F0Yl2jglryfwheZBsvTHlPo4n1tH5rOO3wR0XQnJj)(作者:马文)

Makisu:Uber开源的快速Docker镜像生成工具

hokingyang 发表了文章 • 0 个评论 • 1785 次浏览 • 2018-12-16 15:59 • 来自相关话题

为了保证业务平稳发展,我们引入了一种使得工程师们可以动态高效快速部署上千台服务的微服务架构,这种服务大大提高了我们平台上的乘客司机的使用体验。 尽管这种模式支撑了我们快速增长的应用环境,但是由于业务规模太大也带来了痛点。为了容易维护和 ...查看全部
为了保证业务平稳发展,我们引入了一种使得工程师们可以动态高效快速部署上千台服务的微服务架构,这种服务大大提高了我们平台上的乘客司机的使用体验。

尽管这种模式支撑了我们快速增长的应用环境,但是由于业务规模太大也带来了痛点。为了容易维护和升级微服务,2015年采用了Docker技术,确保资源和服务被打包成一个单元。

随着Docker的发展,核心架构团队开发了一套快速高效为Apache Mesos和基于Kubernetes的容器生态产生Dockerfiles配置文件并将应用代码打包在Docker image中的技术。考虑到微服务技术的快速发展,我们开源了核心模块,Makisu,以便其它用户能够收到同样的效果。
# Uber的Docker之路
2015年早期,我们在裸服务器上部署了大约400个服务,他们共享主机上的依赖包和配置文件,仅有很少资源限制。随着工程师规模扩大,依赖管理和资源隔离成为一个问题。为了解决这个问题,核心架构团队开始将服务移植到Docker中,随之建立了标准化和流程化的容器创建流程自动化机制。

新容器化运行环境在服务生命周期管理的运行速度和可靠性方面带来很大提高。然而,访问服务依赖的密钥被打包进image,带来了潜在的安全隐患。简单说,一旦一个文件被放入Docker image中,就会永久存在。尽管可以通过其他这种手段隐藏这些密钥,但是Docker并不提供真正将他们从image中移除的功能。

其中一个解决方案是docker-squash,一个删除Docker image中间步骤所需文件的开源工具,但是带来的问题就是创建image的时间翻倍,这个问题基本抵消了采用微服务架构带来的好处。

为了解决这个问题,我们决定分叉Docker自研我们需要的功能。如果在创建image时候,把所需的密钥以volume方式挂载,这样最终的Docker image中就不留任何密钥的痕迹。因为没有额外延迟,而且代码更改也很少,因此这方法很有效。架构团队和服务团队都满意了,容器架构被更好地利用起来。
# 大规模编译容器image
到了2017年,这种架构不再能满足需求。随着Uber的增长,平台规模也同样受到很大挑战。每次创建超过3000个服务,每天有若干次,大大增加了消耗时间。有些需要2个小时,大小超过10GB,消耗大量存储空间和带宽,严重影响开发者生产率。

此时,我们认识到创建可以扩展的容器image是很重要的。为此提出了三个需求:无特殊权限创建,支持分布式cache,image大小优化。
## 无特殊权限创建
2017年,核心架构团队开始将Uber的计算负载迁移到提供自动化、可扩展和更加弹性化的统一平台上。随之而来,Dockerfile也需要能够运行在共享集群上的容器中。

不幸的是,Docker创建逻辑依赖于一种通过对比创建时间来决定不同层次之间不同的copy-on-write文件系统。这个逻辑需要特权挂载或者卸载容器内部的目录,以便给新系统提供安全机制。也就意味着,Docker无法做到无root权限创建。
## 支持分布式缓存(cache)
通过分层缓存(cache)技术,用户可以复用之前的创建版本和层级,可以减少执行时候的冗余。Docker为每个创建提供分布式缓存,但是并不支持不同分支和服务。需要依靠Docker本地缓存层,但是因为集群内的生成新版本要求不断清空缓存,造成缓存命中率大大降低。

过去,Uber采用指定机器创建指定服务的方式提高命中率,然而,这种方法对于多种服务构成的系统来说显然是不够的。考虑到我们每天会使用上千种服务,这个过程也增加了调度复杂性。

显然一个好的缓存策略对我们的方案更加重要,最终分布式缓存方案既可以解决性能问题,也能够解决创建系统时的调度问题。
## 优化image大小
小images节省空间,并且可以节省转换、压缩和启动时间。

为了优化image大小,我们计划采用多阶段步骤。在众多方案中并不很特别:通过中间态image,将运行时所需文件拷入瘦身的最终image。尽管需要比较复杂的Dockerfiles,但可以减小image大小,因此可以很好地弹性部署。

另外,通过减少image中的层数也可以减少image大小,image比较大有可能是某些文件被中间层创建,删除或者更新的结果。如前所述,即使后续步骤删除了临时文件,但是在开始层中仍然存在,占据相应空间。减少层数可以大大减少删除或更新的文件在之前层中依然存在的可能性,因此可以减小image大小。
# 介绍Makisu
为了实现以上想法,我们开发了自己的image工具,Makisu,实现更加动态,更快容器创建,更加弹性等功能。其特点包括:

* 不需要特殊权限,开发过程更加容易移植;
* 开发集群内部使用分布式层间缓存提高性能;
* 提供灵活层间管理,减少images中不必要文件;
* 与容器Docker兼容;支持标准和多阶段开发命令。

下面详细介绍这些特性。
## 不需要特殊权限
与其它虚机相比Docker image更加轻量是因为中间层只包括运行开发步骤前后文件系统的差别。Docker计算差别,并使用需要特权的CoW文件系统生成中间层。

为了实现不需要特权生成中间层,Makisu在内存中进行文件系统扫描。运行开发步骤后,在此扫描文件系统,更新内存视图,将变化文件添加到新一层。

Makisu也对压缩速度进行了优化,这对弹性部署非常重要。Docker使用Go中默认gzip库压缩层级,当遇到带有大量text文件的image层来说性能很慢。文件扫描阶段后,即使没有缓存,Makisu在很多方面比Docker要快,其中P90开发时间将近节省50%。
## 分布式缓存
Makisu用key-value数据库映射Dockerfiles中操作行到存放在Docker镜像仓库中的层数。key-value数据库可以用Redis或者文件系统。Makisu也用缓存TTL确保缓存内容不会存放太久。

缓存key用当前开发命令和前一条命令的key一起生成。缓存值是生成层内容的哈希值,也用来定位当前层在Docker镜像仓库中的位置。

在Dockerfile的初始化阶段,层生成并且异步推到Docker镜像仓库和key-value库中。后续同样步骤可以从缓存层中获取并解压获取,避免冗余操作。
## 灵活层间操作
为开发过程对iamge层进行控制,Makisu映入了新的操作注释:#!COMMIT,指代Dockerfile中可以生成新层的行。这一简单机制对减少容器image大小很关键( 后续操作要删除或者更新文件 ),解决了密钥跨层存取的问题。每个commit层在分布式缓存中得以体现,集群中其它开发者也可以使用这一更新结果。

以下是一个Dockerfile的实例,其中使用了Makisu的操作注释:
FROM debian:8 AS build_phase
RUN apt-get install wget #!COMMIT
RUN apt-get install go1.10 #!COMMIT
COPY git-repo git-repo
RUN cd git-repo && make

FROM debian:8 AS run_phase
RUN apt-get install wget #!COMMIT
LABEL service-name=test
COPY –from=build_phase git-repo/binary /binary
ENTRYPOINT /binary

本例中,安装了运行时需求包(wget和go1.10),并在相应层内commit,后续创建服务代码。当这些committed层创建后,在分布式缓存中得以更新,其它开发这可以使用,大大提高了开发工作冗余操作的速度。

第二阶段,开发再次安装wget,这次Makisu重用了之前生成的代码。最后,服务代码从开发阶段拷贝到最终image,并生成最终image。这一示例生成一个瘦身的最终image,具体结构如图一所示:
image1.png

图一 Docker为每一步启动一个新容器并生成三层,Makisu在一个容器中编排所有步骤并跳过不必要的层生成
## Docker兼容
Docker image一般是由一些明文按顺序展开的tar文件和两个配置文件构成,Makisu生成的image跟Docker Daemon和镜像仓库完全兼容。

Makisu也支持多阶段开发,通过#!COMMIT的引入,可以实现不必要步骤跳过,并节省空间。

另外,因为#!COMMIT格式化为注释,Makisu使用的Dockerfiles可以被Docker完全兼容。
# 如何使用Makisu
如果想使用Makisu,用户可以直接下载二进制代码,并且不带RUN地运行简单Dockerfiles。用户可以下载Makisu,运行在Docker容器内部,或者作为Kubernetes/Apache Mesos持续集成的工作流。

- 本地使用Makisu二进制代码
- 本地使用Makisu image
- 作为Kubernetes工作流运行Makisu

原文链接:Introducing Makisu: Uber’s Fast, Reliable Docker Image Builder for Apache Mesos and Kubernetes(翻译:杨峰)

DockOne微信分享(一八一):小米弹性调度平台Ocean

李颖杰 发表了文章 • 0 个评论 • 2402 次浏览 • 2018-07-20 23:50 • 来自相关话题

小米弹性调度平台在公司内的项目名称为Ocean(以下简称Ocean)。 Ocean目前覆盖了公司各种场景的无状态服务,同时对于一些基础服务组件,比如:MySQL、Redis、Memcache、Grafana等等抽象为了PaaS平台 ...查看全部
小米弹性调度平台在公司内的项目名称为Ocean(以下简称Ocean)。

Ocean目前覆盖了公司各种场景的无状态服务,同时对于一些基础服务组件,比如:MySQL、Redis、Memcache、Grafana等等抽象为了PaaS平台Ocean的服务组件。

Ocean平台作为小米公司级PaaS平台,目前正在做的事情和后续的一些规划,这里简单列几个:CI/CD、故障注入、故障自愈、容量测试等等。

目前Ocean平台已支持IDC和多云环境,此次分享只介绍IDC内的实践。

Ocean平台因启动的比较早,当时Kubernetes还没有release版本,所以早起的选型是Marathon + Mesos的架构,此次的分享底层也是Marathon + Mesos架构(目前已在做Marathon + Mesos/Kubernetes双引擎支持,本次分享不涉及Kubernetes底层引擎相关内容)。

先分享一张Ocean平台的整体架构图:
1.png

关于容器的存储、日志收集、其他PaaS组件(RDS、Redis等等)、动态授权、服务发现等等本次分享不做介绍。
#容器网络的前世今生

做容器或者说弹性调度平台,网络是一个避不开的话题,小米在做弹性调度的时候网络有以下几方面的考虑:

1. 要有独立、真实的内网IP,便于识别和定位,无缝对接现有的基础设施;
2. 要与现有的物理机网络打通;
3. 要能保证最小化的网络性能损耗(这一点基本上使我们放弃了overlay的网络方式);

因小米弹性调度平台启动的很早,而早期容器网络开源方案还不是很成熟,还不具备大规模在生产环境中使用的条件。所以综合考虑,我们选择了DHCP的方案。

DHCP方案的实现:

1. 网络组规划好网段;
2. 划分专属Ocean的vlan,并做tag;
3. 搭建DHCP server,配置规划好的网段;
4. 容器内启动DHCP client,获取IP地址。
5. 物理机上配置虚拟网卡,比如eth0.100,注:这个100就是vlan ID,和tag做关联的,用于区分网络流量。

此方案中有几个细节需要注意:

1. DHCP server需要做高可用:我们采用了 ospf+vip的方式;
2. 启动的容器需要给重启网卡的能力,以获取IP地址,即启动容器时需要增加NET_ADMIN能力;
3. 需要配置arp_ignore,关闭arp响应,net.ipv4.conf.docker0.arp_ignore=8。

DHCP网络模式,在Ocean平台运行了很长一段时间。

DHCP网络从性能上、独立IP、物理网络互通等方面都已满足需求。既然DHCP已满足需求,那么我们后来为什么更换了网络模型。

因为DHCP的方式有几个问题:

1. IP地址不好管理,我们需要再做个旁路对IP地址的使用情况做监控,这就增加了Ocean同学维护成本;
2. 每次资源扩容需要网络组同学帮我们手动规划和划分网段,也增加了网络同学的管理成本。

针对以上2个痛点,我们重新对网络进行了选型。重新选型时社区用的比较多的是Calico和Flannel。那我们最后为什么选择了Flannel?还是基于:要有独立IP、和现有物理网络互通、最小化网络性能损耗这3点来考虑的。

Calico在这3点都能满足,但是侵入性和复杂度比较大:

1. Calico的路由数目与容器数目相同,非常容易超过路由器、三层交换、甚至节点的处理能力,从而限制了整个网络的扩张。
2. Calico的每个节点上会设置大量的iptables规则、路由,对于运维和排查问题难道加大。
3. 和现有物理网络互联,每个物理机也需要安装Felix。

而Flannel + hostgw方式对于我们现有的网络结构改动最小,成本最低,也满足我们选型需求,同时也能为我们多云环境提供统一的网络方案,因此我们最终选择了Flannel+hostgw方式。

下面简单介绍下Ocean在Flannel+hostgw上的实践。

1. Ocean和网络组协商,规划了一个Ocean专用的大网段;
2. 网络组同学为Ocean平台提供了动态路由添加、删除的接口,即提供了路由、三层交换简单OpenAPI能力;
3. Ocean平台规范每台宿主机的网段(主要是根据宿主机配置,看一台宿主机上启动多少实例,根据这个规划子网掩码位数);
4. 每台容器宿主机上启动Flanneld,Flanneld从etcd拿宿主机的子网网段信息,并调用网络组提供的动态路由接口添加路由信息(下线宿主机删除路由信息);
5. Dockerd用Flanneld拿到的网段信息启动Docker daemon。
6. 容器启动是根据bip自动分配IP。

这样容器的每个IP就分配好了。容器的入网和出网流量,都依赖于宿主机的主机路由,所以没有overlay额外封包解包的相关网络消耗,只有docker0网桥层的转发损耗,再可接受范围内。

以上为小米ocean平台改造后的网络情况。

网络相关的实践,我们简单介绍到这里,下面介绍发布流。
#发布流

对于一个服务或者任务(以下统称job)的发布流程,涉及如下几个方面:

1. 需要创建要发布job的相关信息。
2. 基于基础镜像制作相关job的部署镜像。
3. 调用Marathon做job部署。
4. job启动后对接小米运维平台体系。
5. 健康检查

发布流程的统一管理系统(以下统称deploy)做发布流整个Pipeline的管理、底层各个组件的调用、维护了各个stage的状态。

下面针对这几点展开详细介绍下:

job的相关信息:job我们可以理解为业务需要部署的项目模板,是Ocean平台发布的最小粒度单元。因其为业务项目模板,所以需要填写的信息都是和业务项目相关的内容,需要填写job名称、选择集群(在哪个机房部署)、给定产品库地址(业务代码的Git或SVN地址)、选择容器模板(启动的容器需要多大的资源,比如1CPU 2G内存 100G磁盘等)、选择基础镜像版本(比如CentOS:7.3,Ubuntu:16.04等)、选择依赖的组件(比如JDK、Resin、Nginx、Golang、PHP等等业务需要根据自己的代码语言和环境需求选择)、填写启动命令(服务如何启动)、监听端口(服务监听的端口是多少,该端口有几个作用:1. 提供服务;2. 健康检查;3. 创建ELB关联;4. 会和job名字一起上报到zk,便于一些还没有服务发现的新项目平滑使用Ocean平台提供的服务发现机制)。

以上是最基本的job信息,还有一些其他的个性化设置,比如环境变量、共享内存、是否关联数据库等等,这里不展开介绍了。

制作job镜像:上面的job信息创建好后,便可以进入真正的发布流程了。发布的时候会根据用户设置的job信息、基于Ocean提供的基础镜像来制作job镜像。这里面主要有2个流程,一个是docker build 制作镜像,一个是业务代码的编译、打包。

Docker build 基于上面填写的job信息解析成的Dockerfile进行。我们为什么不直接提供Dockerfile的支持,而做了一层页面的封装:

* 对于开发接入成本比较高,需要单独了解Dockerfile文件格式和规范。
* 开发人员越多,写错Dockerfile的几率越大,对于Ocean同学来说排错的成本就会越高。
* 此封装可以规范Dockerfile,业务只需要关心和job相关的最基本信息即可,不需要了解Dockerfile具体长什么样子。

Docker build会在镜像里拿业务代码,然后进行业务代码的编译、打包;关于业务编译、打包Ocean内做了一些针对原部署系统(服务部署到物理机)的兼容处理,可以使业务直接或很少改动的进行迁移,大大降低了迁移的成本。

job镜像build成功后,会push到Ocean私有的Registry。

调用marathon做job部署:镜像build成功后,deploy会调用Marathon的接口,做job的部署动作(底层Marathon + Mesos之间调度这里也不展开讲,主要说下我们的Ocean上做的事情)。

job部署分2种情况:

* 新job的部署:这个比较简单,deploy直接调用Marathon创建新的job即可。
* job版本更新:更新我们需要考虑一个问题,如何使job在更新过程中暂停,即支持版本滚动更新和业务上的灰度策略。

Marathon原生是不支持滚动更新的,所以我们采用了一个折中的办法。
在做job更新的时候,不做job的更新,是创建一个新的job,除版本号外新job名字和旧job名字相同,然后做旧job缩减操作,新job扩容操作,这个流程在deploy上就比较好控制了。

更新期间第一个新job启动成功后默认暂停,便于业务做灰度和相关的回归测试等。

对接运维平台体系:基础镜像内打包了docker init,容器在启动的时候docker init作为1号进程启动,然后我们在docker init中做了和目前运维平台体系打通的事情,以及容器内一些初始化相关的事情。

包括将job关联到业务的产品线下、启动监控Agent、日志收集、对接数据流平台、注册/删除ELB、启动日志试试返回给deploy等等。

健康检查:我们做健康检查的时候偷了些懒,是基于超时机制做的。
job编译成功后,deploy调用Marathon开始部署job,此时Marathon便开始对job做健康检查,再设置的超时时间(这个超时时间是可配置的,在job信息内配置)内一直做健康检查,直到健康检查成功,便认为job发布成功。发布成功后,整个发布流结束。
#弹性ELB

job部署成功后,就是接入流量了。在Ocean平台流量入口被封装为了ELB基础服务。

在ELB模块入口创建ELB:选择集群(即入口机房,需要根据job部署的机房进行选择,为了规范化禁止了elb、job之间的夸机房选择);选择内、外网(该服务是直接对外提供服务,还是对内网提供服务);填写监听端口(job对外暴露的端口);选择调度算法(比如权重轮询、hash等);选择线路(如果是对外提供服务,是选择BGP、还是单线等)。

ELB创建好后,会提供一个ELB的中间域名,然后业务域名就可以cname到这个中间域名,对外提供服务了。

大家可以看到,ELB的创建是直接和job名字关联的,那么job目前的容器实例、之后自动扩缩的容器实例都是怎么关联到ELB下的呢?

这里也分2种情况:

1. job已经启动,然后绑定ELB:这种情况下,我们做了一个旁路服务,
已轮询的方式从Marathon获取实例信息,和创建的ELB后端信息进行比较,并以Marathon的信息为准,更新ELB的后端。
2. 绑定ELB后,job扩缩:上面在发布流中提到,docker init会做ELB的注册、删除动作。

job在扩容的时候会在docker init初始化中将job注册到ELB后端;job在缩容的时候会接收终止信息,在接收终止信号后,docker init做回收处理,然后job实例退出。在回收处理的过程中会操作该实例从ELB摘除。

到此ELB的基本流程就分享完了,下面说下自动扩缩。
#自动扩缩

自动扩缩目前包括定时扩缩和基于Falcons的动态扩缩。
##定时扩缩

比如一些服务会有明显的固定时间点的高峰和低谷,这个时候定时扩缩就很适合这个场景。

定时扩缩的实践:定时扩缩我们采用了Chronos。

在deploy内封装了Chronos任务下发的接口,实际下发的只是定时回调任务。到任务时间点后触发任务,该任务会回调deploy 发布服务的接口,进行job的扩缩。这里我们为什么没有直接调用Marathon的接口,是因为在deploy中,我们可以自行控制启动的步长、是否添加报警等更多灵活的控制。
##基于Falcon动态扩缩

Falcon是小米内部的监控平台(和开源的Open-Falcon差别并不大,但是Ocean平台job内的Falcon Agent 基于容器做过了些改造)。Ocean平台是基于Falcon做的动态调度。用户自行在Ocean上配置根据什么指标进行动态调度,目前支持CPU、内存、thirft cps。这些metric通过Falcon Agent 上报到Falcon平台。用于做单容器本身的监控和集群聚合监控的基础数据。

然后我们基于聚合监控来做动态扩缩。例如,我们在Ocean平台上配置了基于CPU的扩缩,配置后,deploy会调用Falcon的接口添加集群聚合的监控和回调配置,如果实例平均CPU使用率达到阈值,Falcon会回调deploy做扩缩,扩缩实例的过程和定时扩缩是一样的。
#遇到的一些特例问题

Ocean从启动开始遇到了很多问题,比如早起的Docker版本有bug会导致docker daemon hang住的问题,使用Device Mapper卷空间管理的问题等等。

下面针对本次的分享,简单列5个我们遇到的问题,然后是怎么解决的。

1、ELB更新为什么没有采用Marathon事件的机制,而是使用了旁路服务做轮询?

* 我们发现marathon的事件并不是实时上报,所以这个实时性达不到业务的要求;
* 在我们的环境中也碰到了事件丢失的问题。

所以我们采用了旁路服务轮询的方式。

2、虽然Ocean平台已经做了很多降低迁移成本的工作,但是对于一些新同学或者新业务,总还是会有job部署失败的情况。针对这种情况,我们增加了job的调试模式,可以做到让开发同学在实例里手动启动服务,查看服务是否可以正常启动。

3、ELB的后端数目不符合预期。

主要是由于slave重启导致实例应该飘到其他的机器时,Marathon低版本的bug导致启动的实例数与预期不一致。解决该问题是通过登录到Marathon,通过扩缩实例然后使实例数达到预期,但是这又引进了另外一个问题,ELB的后端存在了残留的IP地址没有被清理,虽然这个因为健康检查而不影响流量,但是暂用了额外的IP资源,所以我们又做了个旁路服务,用于清理这些遗留IP。

4、容器内crontab不生效。业务在容器内使用了crontab,但是在相同的宿主机上,个别容器crontab不生效问题。

我们解决的方式是为启动的容器增加相应的能力,即启动的时候mesos executor增加 AUDIT_CONTROL 选项。

5、容器内看到的Nginx worker进程数没有隔离的问题。

我们在物理机上配置Nginx时通常会将Nginx的worker进程数配置为CPU核心数并且会将每个worker绑定到特定CPU上,这可以有效提升进程的Cache命中率,从而减少内存访问损耗。然后Nginx配置中一般指定worker_processes指令的参数为auto,来自动检测系统的CPU核心数从而启动相应个数的worker进程。在Linux系统上Nginx获取CPU核心数是通过系统调用 sysconf(_SC_NPROCESSORS_ONLN) 来获取的,对于容器来说目前还只是一个轻量级的隔离环境,它并不是一个真正的操作系统,所以容器内也是通过系统调用sysconf(_SC_NPROCESSORS_ONLN)来获取的,这就导致在容器内,使用Nginx如果worker_processes配置为auto,看到的也是宿主机的CPU核心数。

我们解决的方式是:劫持系统调用sysconf,在类Unix系统上可以通过LD_PRELOAD这种机制预先加载个人编写的的动态链接库,在动态链接库中劫持系统调用sysconf并根据cgroup信息动态计算出可用的CPU核心数。
#Q&A

Q:请教下你们ELB用的什么代理软件,HAProxy、Nginx?是否遇到过缩容时出现部分请求失败的问题,有解决方案吗?

A:IDC ELB底层封装的是公司的LVS,LVS管理平台提供了完事的API支持,ELB这边调用LVS管理平台的API进行的相关操作。缩容目前没有遇到流量丢失问题,这个是在docker init内接收信号,然后做的回收处理。

Q:hostgw如何访问外网?
>A:是通过路由出网的,容器的IP是路由上真实存在的IP网段,由网络组提供的API进行的动态配置。

Q:都劫持了,为啥不用 LXCFS?
>A:LXCFS目前仅支持改变容器的CPU视图(/proc/cpuinfo文件内容)并且只有--cpuset-cpus参数可以生效,对于系统调用sysconf(_SC_NPROCESSORS_ONLN)返回的同样还是物理机的CPU核数。另:我们采用的劫持方案已开源,欢迎围观:https://github.com/agile6v/container_cpu_detection

以上内容根据2018年7月17日晚微信群分享内容整理。分享人赵云,小米云平台运维部SRE,负责小米有品产品线运维工作。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

DockOne微信分享(一八十):Hulu大规模容器调度系统Capos

Andy_Lee 发表了文章 • 0 个评论 • 1341 次浏览 • 2018-07-13 15:24 • 来自相关话题

Hulu是美国领先的互联网专业视频服务平台,目前在美国拥有超过2000万付费用户。Hulu总部位于美国洛杉矶,北京办公室是仅次于总部的第二大研发中心,也是从Hulu成立伊始就具有重要战略地位的分支办公室,独立负责播放器开发,搜索和推荐,广告精准投放,大规模用户 ...查看全部
Hulu是美国领先的互联网专业视频服务平台,目前在美国拥有超过2000万付费用户。Hulu总部位于美国洛杉矶,北京办公室是仅次于总部的第二大研发中心,也是从Hulu成立伊始就具有重要战略地位的分支办公室,独立负责播放器开发,搜索和推荐,广告精准投放,大规模用户数据处理,视频内容基因分析,人脸识别,视频编解码等核心项目。

在视频领域我们有大量的视频转码任务;在广告领域当我们需要验证一个投放算法的效果时,我们需要为每种新的算法运行一个模拟的广告系统来产出投放效果对比验证;在AI领域我们需要对视频提取帧,利用一些训练框架产出模型用于线上服务。这一切都需要运行在一个计算平台上,Capos是Hulu内部的一个大规模分布式任务调度和运行平台。

Capos是一个容器运行平台,包含镜像构建,任务提交管理,任务调度运行,日志收集查看,Metrics收集,监控报警,垃圾清理各个组件。整个平台包含的各个模块,如下图所示:
1.png

用户可以在界面上创建镜像描述符,绑定GitHub的repo,生成镜像。之后在界面上创建作业描述符,填上镜像地址,启动参数,资源需求,选择资源池,就可以运行作业,看作业运行日志等。这些所有操作也可以通过REST API来调用,对于一些高级的需求,Capos提供Golang和Python的SDK,可以让用户申请资源,然后启动作业,广告系统就是利用SDK,在Capos上面申请多个资源,灵活的控制这些资源的生命周期,一键启动一个分布式的广告系统来做模拟测试。

Capos大部分组件都是用Golang实现的,Capos的核心组件,任务调度运行CapScheduler是今天主要和大家分享和探讨的模块。CapScheduler是一个基于Mesos的Scheduler,负责任务的接收,元数据的管理,任务调度。CapExecutor是Mesos的一个customized executor,实现Pod-like的逻辑,以及pure container resource的功能,在设计上允许Capos用户利用Capos SDK复用计算资源做自定义调度。

Capos Scheduler的架构图如下所示:
2.png

上图浅蓝色部分是Mesos的组件,包括Mesos master,Mesos agent,Mesos zookeeper。Mesos作用是把所有单体的主机的资源管理起来,抽象成一个CPU、Memory、Port、GPU等的资源池,供之上的Capos scheduler使用。

其中Capos scheduler是一个active-standy的HA模型,在scheduler中我们实现了一个raft based的k-v用来存储Metadata,active的scheduler注册成为Mesos之上的一个framework,可以收到资源,根据调度策略来启动作业。

Capbox是一个定制实现的Mesos的executor,作为Mesos agent的资源的占位符,接收请求与Mesos agent上的Docker daemon通信启动容器。其中也实现了POD-like的功能,同时可以启动多个容器共享network,磁盘等。

Capos scheduler提供两类作业运行,一个是简单作业直接在Capbox运行,另一个是复杂带有编程语义的作业,我们称之为AppMaster,其本身运行占用一个CapBox,然后通过编程语义二次申请CapBox运行作业。
首先说明下简单作业运行流程,这里的简单作业,提交的作业通过json描述,可以包含多个Container,然后scheduler收到请求之后,命中某个offer,向Mesos发送offer启动请求,在请求中同时夹带着作业json信息,把作业启动起来,scheduler根据Mesos状态同步信息来控制作业的生命周期。

如果是AppMaster Programmatically二次调度的作业,首先需要把AppMaster启动,这部分和简单作业运行是一致的,然后AppMaster再申请一个到多个资源来启动CapBox,运行作业。此时AppMaster申请的CapBox的生命周期完全由AppMaster决定,所以这里AppMaster可以复用CapBox,或者批量申请CapBox完成自己特定的调度效果。多说一句,AppMaster可以支持client-mode和cluster-mode,client-mode是指AppMaster运行在集群之外,这种情况适用于把AppMaster嵌入在用户原先的程序之中,在某些场景更符合用户的使用习惯。

说完Capos的使用方式后,我们可以聊下在Capos系统中一些设计的思考:

1、Scheduler的调度job和offer match策略,如下图所示:
3.png


  1. 缓存offer。当scheduler从Mesos中获取offer时候,Capos scheduler会把offer放入到cache,offer在TTL后,offer会被launch或者归还给Mesos,这样可以和作业和offer的置放策略解耦。
  2. 插件化的调度策略。Capos scheduler会提供一系列的可插拔的过滤函数和优先级函数,这些优先级函数对offer进行打分,作用于调度策略。用户在提交作业的时候,可以组合过滤函数和优先级函数,来满足不同workload的调度需求。
  3. 延迟调度。当一个作业选定好一个offer后,这个offer不会马上被launch,scheduler会延迟调度,以期在一个offer中match更多作业后,再launch offer。获取更高的作业调度吞吐。

2、Metadata的raft-base key value store

1. 多个scheduler之间需要有一个分布式的kv store,来存储作业的Metadata以及同步作业的状态机。在scheduler downtime切换的时候,新的scheduler可以接管,做一些recovery工作后,继续工作。
2. 基于Raft实现的分布式一致性存储。Raft是目前业界最流行的分布式一致性算法之一,Raft依靠leader和WAL(write ahead log)保证数据一致性,利用Snapshot防止日志无限的增长,目前Raft各种语言均有开源实现,很多新兴的数据库都采用Raft作为其底层一致性算法。Capos利用了etcd提供的raft lib, 实现了分布式的一致性数据存储方案。etcd为了增强lib的通用性,仅实现了Raft的核心算法,网络及磁盘io需要由使用者自行实现。Capos中利用etcd提供的rafthttp包来完成网络io,数据持久化方面利用channel并行化leader的本地数据写入以及follower log同步过程,提高了吞吐率。
3. Capos大部分的模块都是Golang开发,所以目前的实现是基于etcd的raft lib,底层的kv存储可以用BoltDB,Badger和LevelDB。有些经验可以分享下,在调度方面我们应该关注关键路径上的消耗,我们起初有引入StormDB来自动的做一些key-value的index,来加速某些带filter的查询。后来benchmark之后发现,index特别在大规模meta存储之后,性能下降明显,所以目前用的纯kv引擎。在追求高性能调度时候,写会比读更容器达到瓶颈,BoltDB这种b+ tree的实现是对读友好的,所以调度系统中对于kv的选型应该着重考虑想LevelDB这种lsm tree的实现。如果更近一步,在lsm tree基础上,考虑kv分离存储,达到更高的性能,可以考虑用badger。不过最终选型,需要综合考虑,所以我们底层存储目前实现了BoltDB、Badger和LevelDB这三种引擎。

3、编程方式的AppMaster

1. 简单的作业可以直接把json描述通过REST API提交运行,我们这边讨论的是,比较复杂场景的SaaS,可能用户的workload是一种分布式小系统,需要多个Container资源的运行和配合。这样需要Capos提供一种编程方式,申请资源,按照用户需要先后在资源上运行子任务,最终完成复杂作业的运行。
2. 我们提供的编程原语如下:

1. Capbox.go capbox是Capos中资源的描述:
4.png

AppMaster可以用这些API申请资源,释放资源,获取资源的状态更新,在此基础上可以实现灵活的调度。
2. Task.go task也就是可以在Capbox上运行的task,如下图所示:
5.png

在资源基础上,appmaster可以用api启动/停止作业,appmaster也可以复用资源不断的启动新的作业。基于以上的api,我们可以把广告模拟系统,AI框架tensorflow,xgboost等分布式系统运行在Capos之上。

4、Capos对比下Netflix开源的Titus和Kubernetes

1. Netflix在今年开源了容器调度框架Titus,Titus是一个Mesos framework,titus-master是基于fenso lib的Java based scheduler,meta存储在cassandra中。titus-executor是Golang的Mesos customized executor。因为是Netflix的系统,所以和AWS的一些设施是绑定的,基本上在私有云中不太适用。
2. Kubernetes是编排服务方面很出色,在扩展性方面有Operator,Multiple Scheduler,CRI等,把一切可以开放实现的都接口化,是众人拾柴的好思路,但是在大规模调度短作业方面还是有提升空间。
3. Capos是基于Mesos之上的调度,主要focus在大规模集群中达到作业的高吞吐调度运行。

在分布式调度编排领域,有诸多工业界和学术界的作品,比如开源产品Mesos,Kubernetes,YARN,调度算法Flow based的Quincy,Firmament。在long run service,short term workload以及function call需求方面有Service Mesh,微服务,CaaS,FaaS等解决思路,私有云和公有云的百家争鸣的解决方案和角度,整个生态还是很有意思的。绝技源于江湖、将军发于卒伍,希望这次分享可以给大家带来一些启发,最后感谢Capos的individual contributor(字母序):chenyu.zheng、fei.liu、guiyong.wu、huahui.yang、shangyan.zhou、wei.shao。
#Q&A
Q:Capos如何处理健康检查?之前了解到,Mesos内置的健康检查不是特别完善。

A:目前Capos focus的作业大部分都是短作业类型,所以我们目前就是通过容器的退出码来判断success或者fail,如果你说的健康检查是针对服务的,一般实现是支持多种健康检查的方式,bash,http等,然后为了大规模容器运行情况下的可用性,建议这种健康检查的发起client和服务instance是在一台机器上,或者是一个Pod中,发现不健康通过某种机制上报,或者退出Container,但是需要控制Threshold以免整个服务downtime。这样可以探测instance的健康,整个服务的健康,可以在通过外部的一些子系统去check。



Q:关于调度方面,分享中只提到了使用了一系列的可插拔的过滤函数和优先级函数,我想问下能否具体描述下如何被调度的?和yarn里使用的Fair Schedule或者DRF算法的异同有哪些?因为对于多种资源维度的调度是一个很复杂的问题,希望知道Hulu这方面有什么心得和思考?

A:目前实现是,会针对一个请求,首先根据过滤函数比如一些constraints进行offer过滤,然后剩下的offer apply所有的优先级打分函数,进行打分,打分的时候,会根据一个请求和offer的资源,算CPU和mem的比例,选取出dominate的resource进行主要评分,然后选取最优的offer进行bind,bind之后不会马上调度,而是会delay scheduler,这样一般在比较繁忙的情况下,一次offer launch可以启动多个tasks,这是对于大规模吞吐的考虑。 以上这些实现还是queue-base的调度,借鉴了一些Fair Schedule和drf的思路,具体差别你了解了Capos scheduler策略后,应该就会有自己的想法了。多种资源维度,目前我们是根据dominate resource作为主要评分标准的,当然你也可以看下我最后分享提到的一些flow-base的scheduler算法,比如firmament。希望可以回答你的问题。



Q:Capos是否支持,数据中心之间的备份/切换。比如Zone - A的数据中心出现网络故障,把服务迁移到另一个指定的区域 Zone - B(仍然考虑恢复以后优先部署到 Zone - A)。之前考虑是类似一个Mask的机制,如果故障就加一定的Mask值(比如Opcacity)在某个集群上,然后调度的时候去参考这个Mask值,不知道Hulu有没有类似的需求或者考虑过这样的机制?

A:Capos是on Mesos,Mesos是根据zk做选主,而且Capos scheduler中还有一个raft base key value store,所以这些条件,使得Capos是一个datacenter的解决方案。目前Hulu是有多个DataCenter的,所以看架构组件图,你可以看到,我们有一个Capos portal,在这个组件下,是可以选择不同DataCenter去run workload。所以我们目前对于数据中心的备份和切换,主要是依赖Capos portal这个组件,在Gateway的位置做的控制。



Q:想请问下Capos的鉴权是怎么做的,有没有用户权限认证系统?此外,针对每个用户有没有容器资源使用量的限制?

A:可以翻到之前share的架构组件图,我们有一个Capos portal组件,这个组件是提供Restful API和Portal,我们在这边集成Hulu SSO,然后关联Hulu yellowpages(Hulu的服务权限控制系统),做的用户的认证,我们分成自己的Capos APP, team的APP,别的组无法操作不属于自己的Capos APP。对于Quota的管理,我们做了Queue/Label机制,每个服务会建一个标识,然后在标识底下配置总的资源使用量,以及可以用的机器列表(通配符),用这样的机制控制Capos的用户资源使用。



以上内容根据2018年7月10日晚微信群分享内容整理。分享人杨华辉,Hulu senior software developer,目前在Hulu beijing cloud infrastructure组,主要从事分布式容器调度,分布式存储方面的研发。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

Mesos container在360广告系统的应用

尼古拉斯 发表了文章 • 0 个评论 • 1238 次浏览 • 2018-05-12 18:16 • 来自相关话题

【编者的话】本文作者将技术与业务相结合,讲解Mesos与Container的技术架构,面对当前的业务痛点,可以解决哪些问题,并且如何应用到360商业广告系统中。 #背景简介 我是一名SRE工程师,我们负责管理与维护360商业广告平台 ...查看全部
【编者的话】本文作者将技术与业务相结合,讲解Mesos与Container的技术架构,面对当前的业务痛点,可以解决哪些问题,并且如何应用到360商业广告系统中。
#背景简介

我是一名SRE工程师,我们负责管理与维护360商业广告平台,说起SRE工程师大家可能会想到谷歌公司,因为SRE毕竟是谷歌提出的概念。

作为SRE工程师我想说一下我们的自我修养。我们的主要工作是减少琐事,不断的扩大服务规模,同时我们还要保证整个系统的高可靠性和可维护性,不能随着业务规模的不断增大,招揽越来越多的人来维护业务是不合理的。

我们广告通过360搜索或者360手机端的应用进行展示,比如在360搜索输入“鲜花”会有广告展示,每天有数百亿次的投放与展示,手机端主要通过360的手机安全卫士,手机助手等等的一些应用进行广告的投放与展示。
01.jpg

#Why Container?

说一下为什么要使用容器解决我们的问题,还有演讲的主题为什么不写Why Docker?

说到容器大家第一时间会想到Docker,它实现了一个容器引擎(Docker engine)。除了Docker,在容器生态圈还有一些公司他们实现了自己的容器引擎,比如CoreOS的RKT,比如我们使用的Mesos的容器引擎(Mesos containerizer),这些引擎不依赖于Docker本身,可以解决稳定性和扩展性的问题。
##业务痛点

我先不说我们为什么用容器解决这些问题,说一下业务上我们有哪些痛点,并且这些问题可能大家都会碰到。

  1. 数据中心迁移,这个问题大家多数都会遇到,在迁移过程中要把之前的业务熟悉一遍,需要重新部署,测试还会遇到一些环境配置不一致的问题。

  1. 故障恢复,服务器宕机之后,传统业务都部署在物理服务器上,这样也需要重新部署,这样会带来很多麻烦。

  1. 操作系统不一致,现在我们很多不同的操作系统,比如CentOS 5、6、7都在用,迁移的时候很麻烦,还有一些系统内核的Bug需要去解决。

  1. 生产环境配置不一致,生产环境有一些服务器工程师都可以登录,如果改了一些配置导致线上出现问题的情况也是可能发生的。

  1. 测试环境不一致,可能每个人申请一台虚拟机专门做测试,导致测试结果也不一致。

  1. 服务的扩展性较低,传统业务扩容一般需要一台中控机或者有一套部署环境,每一次都需要重新添加一批服务器进行扩容。

  1. 服务器资源利用率问题,使用物理机部署服务,每一天都有服务的高峰低谷,由于采用静态资源划分的方式,资源利用率非常低会给公司造成很多资源上的浪费。

下面我来说一下我们为什么要用Docker来解决我们的问题。

Docker有一个隐喻叫“集装箱”。其实Docker的英文翻译是“码头工人”,这个隐喻给使用者很多暗示,告诉大家快来使用Docker吧,使用Docker就像使用集装箱一样,能够随时随地的,无拘无束的启动你的应用。像Docker官方的口号一样“build、ship、and Run Any APP Anywhere”,Docker为什么可以解决我们遇到的这些业务痛点呢?因为集装箱是有固定的标准,它的大小一致,这样货物在公路、铁路、海洋运输就不用考虑货物的尺寸等问题了,并且依赖大型机械化进行转运,等于是实现了一套标准的运输体系,可以给整个世界带来很大的商业潜力。
##Docker的标准化怎么实现?

正如我上面说到的,Docker的实质化就是标准,Docker的标准化是怎么实现的呢?

首先,Docker有自己标准化的文档管理方式,它的标准化文档方式就是有自己的Dockerfile,可以定义一系列的软件系统版本。

第二点,Docker有对应用的统一操作方法,在物理环境不同的应用有不同的启动方法,如果你用Docker启动程序,可以通过docker run的方式来启动。在服务迁移过程中只要使用docker run命令来启动你的程序就可以了。

第三点,为了维护生产环境的一致性和配置变更的幂等性,Docker创造性的使用了类似Git管理代码的方式对环境镜像进行管理。每次都需要docker pull下载镜像,Docker container本身只有container layer这一层可写,你每次重新部署的时候这一层是会被删掉的,这样可以保证Docker实际环境每次都是幂等的。
##在服务容器化过程中可能遇到的问题

在服务容器化过程当中,我们可能会遇到哪些问题?当大家使用物理机的时候,为了SSH登陆服务器,每台服务器都会开通SSH服务并且添加对应的账号。如果你使用Docker服务还要开通SSH服务的22端口,你需要考虑一下你的服务是否真的需要登录到容器中,或者你容器化的方式是否正确或者它是否适合你的业务。还有一些人这样使用Docker:在容器中开放rsync服务端口,甚至还有在Docker container里面部署puppet agent同步工具,这样做我觉得是完全没有必要的。我们都是不支持SSH或者类似的服务连接到Docker内部的。
2.jpg

如果你不让我登录到物理机上,不让我连到Docker内部,我怎么看我的日志呢?

我们有一套日志系统,后端对接的服务是Elasticsearch,会使用Docker的syslog模块通过UDP的方式写入Graylog里,Graylog或者Grafana都可以进行展示、查询,这样我们就可以及时的发现线上的问题。
3.jpg

##Docker的网络性能

4.jpg

使用了Docker,大家可能会考虑,它的网络性能会怎么样,我们其实也做过一些调研。我们主要用的是Hostonly和Bridge这两种模式,如果用Hostonly基本和直接在物理服务器上运行程序的性能是差不多的,现在我们也有团队专门做Calico服务方面的研究,比如你有一些爬虫服务,可能希望有一些独立的外网IP,可以考虑使用Calico为一个container单独分配外网IP。

或者有网络隔离的需求的话,也可以使用Calico服务。由于我们主要针对是私有云,直接用hostonly模式多一些。
##存储镜像

关于Docker仓库,大家可能会问服务容器化之后,主要用什么仓库存储镜像呢?哪种镜像仓库比较好?之前我们搭建过Docker官方的仓库,只有单节点不是高可用的,数据可靠性也不是非常好,我们是用的无认证模式。

现在我们使用了Harbor,用这个系统做了二次开发,后端存储用的S3存储系统,数据可靠性是非常高的,多机房之间可以进行数据同步,支持用户认证,大家根据自己的用户密码进行登录上传镜像等操作。之后我们还会做一个Docker仓库的CDN化,多机房直接访问CDN服务下载镜像。
5.jpg

##怎样把数据写到本地

大家使用Docker可能会考虑数据怎么写到本地,我们使用Mesos+Docker之后,是不是所有服务都要需要无状态的呢?我们推荐无状态服务运行在Mesos+Docker之上。但是如果你有把日志落到本地的需求,我们现在也是可以支持的。
6.jpg

我列出的这些产品,比如CephFS、MySQL、Kafka、HDFS、Aerospike、Redis都是数据持久化的一种方式,比如流式数据一般用Kafka多一些,数据直接通过Kafka消费出来,通过一些计算模型后再重新写入Kafka,或者如果想数据落到本地的需求直接在Container中挂载CephFS也是可以的。
##服务的注册和发现

关于服务的注册和发现,大家可能会有一些问题。比如我用了Mesos+Docker之后,我们的一些服务是在mesos-slave节点之间飘逸的,有可能因为一台物理机宕机了,你的服务会在另外一台mesos-slave节点上启动,我怎么知道我的服务启动到具体哪台IP或者具体哪台机器上呢?
7.jpg

我们服务发现主要用的是Mesos-DNS还有Marathon,底层数据依赖于ZooKeeper。还有一些公司可能用etcd或者Consul,我们也有在用不过比较少。

关于使用了Docker,服务如何进行调度?还有Docker服务如果对于本地数据有依赖的话需要如何加载?希望大家可以带着问题思考一下,一会儿我会详细说明。
#Why Mesos?

为什么要用Mesos?

当前遇到的一个背景就是在当前互联网环境下,越来越多的分布式计算系统产生。
8.jpg

如果说维护一个大型业务团队需要部署的框架或者分布式系统非常多,但是市面上又没有一种系统能够把所有的应用框架都部署到一个集群里,这样就会导致我之前说的比如资源利用率会很低,可维护性很低。因为不同的集群有不同的配置,所以我们就想把这些多个应用布到一个大型的资源池里,这样可以更好的共享硬件资源。因为我们的服务都是支持动态扩缩容的,这样也可以简化一些部署上的逻辑,并且最大化的利用资源,最终实现服务可调度,数据可以共享。
##使用Mesos的优点


1、资源利用率非常高

因为之前大家用物理服务器的时候,是静态资源划分的方式,这种方式资源浪费得比较多。因为服务每天都有高峰和低谷时段,如果你用Mesos的话,使用了动态服务扩缩容,比如白天广告展示的量会非常大,最高的时候每秒已经超过一百万,但是在晚上访问量非常低,你就可以把这批机器资源释放出来,供一些离线业务运行,比如Hadoop。可以达到最大化的资源利用率。
9.jpg

2、便捷性

Mesos本身支持对所有资源打标签,大家可以打固定的标签。这样在提交资源的时候,可以根据你想要的资源提出申请。比如你想要一个GPU的资源,比如你要1核的我就会分配给你一核的,像乘坐飞机一样,你想坐头等舱只要有资源就可以分配给你,Mesos也是这样,我们支持端口、CPU、内存、硬盘等等的划分。
10.jpg

3、可扩展性非常好

因为它本身的设计原理是两极调度框架,这样带来的好处是它非常的简单。因为Mesos本身只负责资源调度,把任务调度交给了运行在它之上的具体框架进行调度。所以如果你要横向扩展Mesos的话,非常方便。
11.jpg

4、模块化

因为Mesos支持在Mesos API之上定义各种各样的framework,大家可以自由添加framework,我们主要用的Marathon、Flink等官方与自定义framework,具体使用哪种框架,大家可以根据需要去设计。
12.jpg


Mesos的目标

Mesos的目标,其实主要就是给我们带来资源的高利用率,支持多种多样的自定义框架,包括当前支持的还有以后新产生的分布式计算框架等,都可以建立在Mesos之上。

* 可扩展性。现在全球节点最大的是Twitter有45000个mesos-slave。

* 可靠性。因为Mesos采用的是热备的方式,存在一个master节点,如果遇到主从节点切换的时候非常快,大概10秒钟就能完成。

Mesos的架构
13.jpg

Mesos的主要组成是由ZooKeeper实现master的高可用,还可以保证数据的一致性,保存所有的Mesos sleve节点和信息。Mesos master主要用于接收agent上报给Mesos master的资源,Mesos master会分配offer给具体给它之上运行的framework。

Framework是基于Mesos API定义的调度器,会根据调度需求分配具体的offer。

最底层是Mesos agent,用来接受和执行Mesos master发给它的命令,通过Mesos agent之上的executor启动task。

Mesos的实现

Mesos是用的两万行的C++代码编写而成,故障恢复使用的是ZooKeeper,框架都是可拓展的、可以自定义的,并且是模块化的。是Apache顶级的孵化项目,同时还是开源的,项目成立于2009年。

Mesos的结果

Mesos给我们带来的是更高的资源利用率与可靠性。
##Mesos master的故障恢复机制

接下来说一下Mesos master的故障恢复机制。
14.jpg

因为Mesos master只有一个软体状态,只会列出它之上的framework以及mesos-slave的信息,在Mesos master需要进行切换的时候,通过ZooKeeper进行leader的重新选取,选取好新的leader后,只需要所有的framework和mesos-slave节点重新注册到新的Mesos master之上,时间就10秒钟左右。如有你有上万台机器,可能会同时连Mesos master会不会造成大量的链接导致master服务不可用,官方有这样的设置可以设定链接的比例来进行控制。
##Mesos的生态圈有哪些框架

Marthon framework
15.jpg


* 运行长任务。从应用框架字面的意思,任务就像跑长跑一样,这个框架其实就是运行长任务(long running job)的。

* 服务发现。Marathon还可以实现服务发现,有比较好的API接口,比如我有一个APP id对应具体机器的IP是什么。

* 健康检测&事件通知机制。Marathon支持对你所启动的任务进行健康检测,比如端口或者你自定义命令都可以,有事件通知机制,正因为有了事件通知机制才可以在马拉松之上建立一些实时的服务发现,知道哪些服务宕掉了,在哪些新节点启动了,可以保证我们的实时发现服务,重新指向新的服务器。

* WebUI。Marathon有自己的Web UI,可以通过界面直接操作,非常方便。

* 限定条件。你可以设定一大堆的限定条件,比如我之前说的像你选飞机的舱位一样,你设定了网卡必须是万兆的,Marathon会根据你设定的限定条件,帮你选择对应资源。

* Labels。Labels标签也是我们常用的,随着资源利用率越来越大,可能有各种应用,大家可以加上各种的标签,方便的查询。

* 数据持久化。数据持久化也是支持的,可以支持挂载本地卷。

* 服务的预热。这个功能用得不是特别多,比如你在服务启动的时候会需要启动时间,这个时间健康检测是失败的,你可能需要设定一个预热时间,保证服务启动之后正常的健康检测才生效。

* 优雅退出。优雅退出这个问题,大家可能都会遇到,比如像C++不涉及内存自动回收可能需要程序上设计优雅退出的问题,你可以通过Marathon设置一个退出时间,保证你的服务正常退出之后,才把以前的服务都退掉,新的服务启动。

* 支持自定义的containerizer和GPU资源的调度。

Marathon-LB
16.jpg

Marathon-LB是我们用的一个实时发现的服务,Marathon-LB是基于Haproxy和Marathon eventbus机制设计的。其实除了Marathon-LB还有一些其他的服务实时发现,但是都是基于Marathon的事件通知机制设计的。因为Marathon有事件总线的实时更新,可以实时的改变服务后端的IP。如果有宕机或者有服务自动扩缩容的话,Marathon-LB可以实时改变Haproxy的配置,Marathon-LB主要是通过第四层IP加端口的方式进行服务代理,Marathon-LB支持TCP或者HTTP的代理方式。

Mesos-DNS
17.jpg

我们还使用了Mesos官方的Mesos-DNS服务,用于一些对实时性要求不高的服务,比如我们把STORM容器化以后Nimbus和Supervisor之间的通信可能就不是那么频繁,如果有Nimbus宕机的情况,只需要通过Mesos-DNS就可以重新发现AppID对应的新的Nimbus IP。你可以使用Mesos-DNS发现AppID对应的所有后端节点的IP,可以保证你的服务节点随时都可以访问到你想访问到的IP。Mesos-DNS有一定的延迟性,我们测试大概有十几秒。
#Mesos VS YARN

我说一下在我们做技术选型的时候,我们也做过Mesos和YARN方面的调研。

Mesos主要是能调度各种样的资源,有CPU、内存、端口、硬盘;YARN主要是CPU和内存。

两者都是两极调度策略但是又有不同。

Mesos本身只做资源的调度,不负责具体任务的调度,把任务调度交给framework调度。

YARN全都是YARN本身进行资源调度,一个程序提交给它一个任务都由YARN来决定是否接受或者拒绝这个资源,而Mesos却不同。

Mesos因为是对物理资源进行管理与调度的,YARN主要基于Hadoop来做。

根据需要,我们最后还是选择了Mesos来作我们的分布资源管理框架。
#Mesos VS Kubernetes

说起Mesos可能很多同学觉得使用了Marathon提供了容器任务的管理能力,可能就需要跟Kubernetes系统进行比较一下。

本身来讲,Mesos和Kubernetes是两个东西,Mesos是一个分布式的资源管理框架,被称为分布式系统的内核。假如你有很多物理资源,你想把它整合成一个逻辑资源层面的物理资源池,那么你用Mesos是最合适不过的了。

Mesos解决问题的核心是如何把资源整合成一个大型的物理资源池,它上面运行什么,怎么跑它并不关注。

Kubernetes主要是一个自动化的容器操作平台,操作主要包括部署、调度还有节点集群间的扩容等等。

Kubernetes解决问题的核心主要是围绕容器来做的,这两个系统本身没有可比性。因为Mesos支持很多framework,比如Marathon可以实现容器的调度,所以大家就会把这两个平台进行比较。

如果你想搭建这样一个容器管理平台或者调度平台,从我个人来讲第一点从任务上来讲,Marathon只支持长任务型的,Kubernetes支持的比较广,比如支持长时间任务(long running job),节点后台支撑型(node-daemon)等等各种各样的任务。

说一下稳定性方面,Kubernetes是谷歌官方推出的,它的更新比较频繁,更新频繁可能带来的就不是特别稳定,大家可能理解我可以多做一些线下测试,但是事实确实是这样的,Kubernetes更新非常频繁。Mesos一般每半年更新一次,一年发布两个版本,会经过充分测试。Mesos产品设计因为是开源的,是Apache基金会下面的顶级项目,会在社区跟大家进行投票与沟通,决定未来我们的产品怎么做,我们会增加哪些功能。

第三种主要是从功能上来讲,Kubernetes是由谷歌做的,所以它的考虑会非常全面,它的生态非常全面,你想要的功能基本都有,包括网络Kubernetes其实也是有的,其实Kubernetes本身的网络做得不是特别好,很多用Kubernetes都是用Calico实现的。Mesos系统的设计思路则定义了任务调度和功能上整体依赖于调度器的设计,所以可以把Mesos看成一个大乐高底层的基础板。

对于这两个框架,选择哪一个都没有对与错,只有适合与否,选择一个适合你们的工具才是最重要的。
#Mesos/Container在360的一些应用

我说一下Mesos/Container在360的一些应用。
18.jpg

我们从2015年开始,就对分布式的调度系统或者容器调度平台进行了调研,最后选择使用Mesos,因为我们想构建一个大型的物理资源池。在2016年业务正式上线,包括之后说的一些服务的容器化,2016年我们也使用了Chronos,可以运行一些物理机上运行的crontab任务,长时间支持服务在线运行。2017年我们已经实现了两个机房各部署了一个大型的资源池,节点达到了单集群最大1000个以上,任务达到5000个以上,10个以上的自定义framework。
##解决的问题

部署,现在部署可能你只需要在Marathon上改变你的镜像(image)地址,或者只需要把instance数改大就可以扩容。

故障恢复,如果有一台mesos-slave宕掉了,会自动在其他的节点上启动。

服务降级,关于服务降级,我们的资源池服务器是有限的,1000台服务器如果资源快用满了,有些业务就需要做服务降级,不是所有业务都有动态扩缩容。我们主要处理广告业务,广告业务实时日志流比较多,在资源不够的时候,会让某些业务降级。平时每秒处理20万条,降级时让它每秒处理10万条或者5万条,有一定数据延迟也没有关系,因为数据不会丢只会慢慢处理完。

服务发现,关于服务发现,现在有了Mesos-DNS和Marathon-LB我们可以做到实时的服务发现,因为是动态资源划分,我们的任务就可能实时变化。
##Storm集群的容器化

19.jpg

上图是原来通过物理级部署的,所有的Supervisor节点都是一台台物理机还要单独部署一个Nimbus,如果Nimbus节点宕掉非常麻烦,比如有些同学说我可能会用Keepalived做高可用,这确实是一种方案,但是如果你的集群需要频繁的扩容或者缩容就会非常麻烦,你要是不对资源进行动态管理的话,势必带来的就是资源的浪费,因为不可能一天24小时都满负荷运行。

把服务容器化之后,所有的Supervisor都运行在container(mesos-slave)中,Supervisor节点会通过Mesos-DNS发现Nimbus(master)的IP。现在集群资源都是动态利用的。
20.jpg

##图片服务的容器化

重点说一下图片服务的容器化。
21.jpg

图片服务主要用的PHP 7来做的,我们也会面临像阿里一样在双十一的时候,因为广告展示与投放量非常大,每秒达到上百万次,因为给用户进行展示与投放的图片会根据用户的习惯去动态的缩放与拼接。如果我放着很多机器专门用来做图片服务,可能也可以达到你的需求,但是在空闲时间段比如夜里资源浪费得非常多,对资源的利用率不是非常好。

我们就制定了这样一套方案,首先把PHP服务容器化,之后我们根据亚马逊AWS的策略,做了自己的方案,跑一个long running job,根据Marathon的API获取你的图片服务具体是哪台机器,由于所有机器上的监控都用了二次开发,通过API接口能获取负载、CPU,内存等等信息。当图片服务器的负载上升了肯定是压力最大的时候,这样我们只需要设定一个阈值。

比如系统负载大于10超过10次,就进行一次扩容,扩容的倍数是1.5倍,原来我有10台机器,现在要扩容到15台。大家可能会问你这个最大能扩到多少?我一定要设定一个最大值不能无限的扩。比如我们设定一个36,最大扩到36台,在5分钟内可能判断10次,如果这个负载水平一直很高,就不进行缩容。

我肯定还会设定一个最低值,比如最低值是6台,可能到了夜里直接减为6台,每次都需要通过Marathon的API实时发现后端所有机器计算出一个平均值。服务的监控,我们对每台Mesos slave都有监控,具体的container我们做了异步,通过异步把日志写到Graylog中,监控日志传输通过UDP协议。如果发生网络中断的情况也不会有太大影响,因为UDP是可丢的不可靠的。
##其他

我们还有其他服务的一些容器化,有Web service相关的,Aerospike服务,通过组播实现集群之间的通信部署起来比较方便,Marathon-LB也是完全的Docker化的,毕竟是代理层像LVS一样,可能会有服务瓶颈。Kafka MirrorMaker我们用来进行多机房之间的数据传输,原来直接部署在物理机上,这样虽然不会有太大问题,如果宕掉之后数据不能在多个集群当中进行同步,对实时性不能要求那么高。如果做了容器化之后是可调度的,都是可高可用的,我们会保证服务的可靠性。Redis也有做容器化,支持数据的落地和持久化,因为我们有CephFS还有更多的一些无状态的服务也运行在Mesos之上。
22.jpg

最后我要说一下我们的服务CI/CD是怎么做的,CI/CD主要是通过GitLab runner。我们会定义一个Gitlab-CI,可以直接把你提交的代码进行Docker build,把镜像自动提交到对应的仓库,通过API修改Marathon上面对应的地址,最后实现上线自动化。
#未来计划

未来我们想做的,因为CephFS的量不是很大,CephFS之后想上一些写入量比较大的业务,看看效果如何。我们不是做公有云的对于Calico的需求不是那么急切,之前一直没有上这个服务。之后我们可能会做一些Calico相关的,比如一些爬虫的应用,如果用公司的Nat代理的话,可能遇到一些IP被封,导致整个代理IP都不能访问对应的网站就有一些问题了。

还有一些实时的机器学习,现在机器学习主要都基于离线业务来做,实时学习比较少,Marathon和Mesos本身是支持的。

原文链接:Mesos container在360广告系统的应用(作者:李冬)

Mesos 1.5发布,在存储、性能资源管理以及容器化方面有重大改进

大卫 发表了文章 • 0 个评论 • 2118 次浏览 • 2018-02-09 11:57 • 来自相关话题

今天,我很高兴向大家宣布,Apache Mesos 1.5.0版本已经正式与您见面! #新的功能与改进 Mesos 1.5当中包含资源管理、存储与容器化方面的多项重大改进。容器存储接口(简称CSI)支持正是Mesos 1.5当中全瓣 ...查看全部
今天,我很高兴向大家宣布,Apache Mesos 1.5.0版本已经正式与您见面!
#新的功能与改进

Mesos 1.5当中包含资源管理、存储与容器化方面的多项重大改进。容器存储接口(简称CSI)支持正是Mesos 1.5当中全瓣的实验性能力之一,此外亦有大量与之配合的新功能伴随1.5版本一道推出。对代理进行重新配置的新能力将使得操作人员拥有更出色的使用体验。性能提升使得主节点故障转移速度提升80%到85%,而v1 API性能也得到了显著改善。新版本中的资源管理机制更为灵活。此外,同样重要的是,镜像垃圾收集与更强大的Windows支持能力使得您能够更轻松地在不同基础设施类型之上运行Mesos,同时亦可在Mesos之上简单运行多种不同工作负载。

在接下来的文章中,我们将共同了解Mesos 1.5当中的各项卓越改进。
#容器存储接口支持

Mesos 1.5以实验性方式增加了对容器存储接口(简称CSI)[1]的支持能力,这项新规范为存储供应商与容器编排平台之间的全部交互活动定义了一个通用型API。这项功能的出现无疑是Mesos、Kubernetes、Cloud Foundry以及Docker技术社区之间密切合作的结果。CSI的主要作用在于允许存储供应商编写出适用于全部容器编排平台的插件。
对CSI的支持将帮助Mesos始终与规模更大的存储生态系统保持步调一致,从而确保Mesos一直具备更强大的存储支持能力。用户将能够在包含Mesos的任何存储系统当中使用一致的API选项。CSI的out-of-tree插件模式将Mesos的发布周期与存储系统的发布周期区分开来,使得集成系统本身更具可持续性与可维护性。
01.png

上图所示为Mesos所支持的CSI高层架构。若需了解更多细节信息,请参阅说明文档
#提升操作人员使用体验

##代理重新配置策略

在Mesos 1.5之前,用户无法对代理的配置作出任何变更——惟一的方法就是关闭该代理上运行的所有任务,并使用新的代理ID重新启动。任何变化,例如添加额外属性或者新接入磁盘驱动器,都将导致代理启动中止并引发令人头痛的错误:
EXIT with status 1: Failed to perform recovery: Incompatible agent info detected.
------------------------------------------------------------
[...]
------------------------------------------------------------
To remedy this do as follows:
Step 1: rm -f /path/to/work_dir/meta/slaves/latest
This ensures agent doesn't recover old live executors.
Step 2: Restart the agent.

从1.5版本开始,操作人员能够使用新的代理命令行标记--reconfiguration_policy 对代理上应当允许的操作类型进行配置。在将该标记的值设置为additive时,代理将能够接受一切对代理资源量的变更以及对其它属性或故障域的调整。

未来,我们还希望能够进一步添加--reconfiguration_policy=any 设置选项以允许对代理配置作出任意变更。
#性能改进

此版本还包括对主节点故障转移与v1操作状态查询API性能的改进。主节点故障转移完成时间的缩短,源自数据吞吐量高达450%到600%的显著提升,这意味着整体完成时间将缩短80%到85%。
02.png

除此之外,v1操作状态查询API的性能也得到了极大改进,这要归功于我们消除了过程中不必要的复制操作。具体来讲,目前v1 protobuf GetState调用速度较v0提高了36%。此外,v1 JSON Get Sstate性能亦提升了四倍以上。
03.png

更多详尽基准测试结果,请参阅此电子表格
#资源管理

##配额保障改进

此次发布的新版本当中引入了多项与配额机制相关的改进。如今,Mesos将能够更好地保证角色获取配额以及角色不致超额等等,例如:

* 此前,一个角色可收集未使用的预留配额以“愚弄”配额系统,但如今新版本会在分配资源时对预留配额进行核算,从而防止这种情况的发生。
* 资源如今会以细粒度方式进行分配,以防止角色出现超额状况。
* 无配额角色可能收到保留资源的bug已经得到修复。
* 角色的保留资源高于配额资源时,可能出现配额空间缺失的问题已经得到修复。
* 当把资源分配给某个具有资源配额的角色时,此前的版本亦会将部分超出该角色配额之外的资源移交给它。这意味着不同角色的资源配额可能无法得到正确执行。目前这个问题已经通过在分配资源时计算余量的方式得到解决。

##资源提供方抽象

为了将资源与代理生命周期加以拆毁,我们引入了资源提供方这一抽象机制。其作用在于支持代理资源的动态变化、外部资源供应方整合乃至集群范围内资源管理。作为资源责任分离思路的组成部分,我们引入了一项新的资源分配协议,旨在更明确地就成功或失败结果进行通信,同时实现各集群组件间的协调。我们使用新的资源供应方抽象将代理本地存储资源同CSI通过接口加以整合。
#容器化与多平台支持

##Windows 支持能力得到改善

随着Mesos 1.5版本的发布,Windows支持能力得到了极大改善。现在,您在利用Mesos容器运行任务时,可以通过作业对象(MEOS-6690)立足操作系统层级实现资源限制。在使用windows/cpu与windows/mem隔离器时,您可以对CPU周期与虚拟内存强制加以限制。此外,新版本现在也能够正确支持CPU与内存统计信息收集。Mesos fetcher已经被移植到Windows平台,支持通过TLS自动下载文件并释放ZIP压缩文件。在进行配置时,libprocess现在可配合Windows上的OpenSSL支持能力进行构建,这意味着TLS连接将可立足集群之内实现(请注意,由于Windows本身不提供OpenSSL,因此您需要在外部构建或安装OpenSSL)。第一种验证方法CRAM-MD5此次也正式登陆Windows,因此代理将可借此与主节点进行验证。HTTP与TCP状态检查机制也已经能够作用于Windows代理(可用于shell任务; Docker容器运行状态检查也即将推出)。Meos代理不再需要以管理员身份运行,因为其现在能够像普通用户一样创建符号链接,且此项功能已经被集成于代理当中。最后,虽然在上一版本中已经实现,但这里不妨再提一句——Windows本地长路径支持已经实现,意味着您将能够更轻松地立足Windows运行代理(无需进行注册表配置)。
##容器镜像垃圾收集

Mesos 1.5版本支持容器镜像垃圾收集。目前您可以通过两种方式对未使用的镜像层进行垃圾收集:自动与手动。这项功能允许用户轻松解决磁盘空间被docker镜像大量占用的难题。具体请参阅容器镜像垃圾收集说明文档以了解更多细节信息。
##独立容器

本次新版本包含一组新的操作程序API,用于启动并管理所谓“独立容器”这一新型原语。独立容器类似于由Mesos代理之上的框架所启动的容器,只是独立容器由操作程序在Mesos代理上直接启动。如此一来,这些容器将无需使用Mesos执行器,且具有其它一些限制特性(例如无法使用预留资源等)。与此同时,独立容器几乎与其它容器完全隔离,并与容器镜像类似——能够使用同样的容器化功能集。

此项功能的发布旨在支持CSI工作流,但各API并不限于此用例。未来,此项功能可能将被用于为各代理节点实现守护进程。具体请参阅MESOS-7302以了解更多细节信息。
#Mesos内部

##支持gRPC客户端

此次新版本包含一套gRPC客户端打包器。gRPC是一种PC机制,并作为RESST API的替代性方案在云原生领域愈发受到欢迎。作为将gRPC整合至Mesos的第一步,我们在libprocess当中添加了此客户端打包器以支持CSI。该功能在默认情况下处于禁用状态,您可以在安装有OpenSSL库的集群当中使用--enable-grpc (autotools)加以启用。该包装类负责在内部维护gRPC运行时数据结构,同时提供一个简单接口,以便实现与libprocess的基于actor模式相兼容的异步gRPC调用。我们还利用这项新功能连接CSI插件。除此之外,大家也可以使用这项新功能创建Mesos模块,用以同其基于gRPC的服务进行通信。
##复制日志改进

Mesos复制日志可帮助各类框架(例如Apache Aurora)将自身状态保存为多套副本,从而在故障转移及重新启动时实现状态保留。从1.5版本开始,大家将能够读取来自一套非主导VOTING复制日志副本处以最终一致化方式进行读取。如此一来,您将能够在非主导框架副本之上进行其它处理工作,例如将部分读取任务移交至待命副本,或者将高频复制日志副本 保留在内存内以缩短故障转移时间。
#升级

从Mesos 1.4.0升级至Mesos 1.5.0非常简单。请参阅升级指南以了解更多与升级至Mesos 1.5.0相关的细节信息。
#社区

您是否在本次发布的新版本中受到了启发?您是否希望参与其中?您对此有何见解?我们期待着听到您的声音!请立即加入工作组或在社区中开启对话!
#鸣谢!

感谢Mesos 1.5.0版本项目组的59位贡献者:

Aaron Wood, Adam B, Adam Dangoor, Akash Gupta, Alastair Montgomery, Alexander Rojas, Alexander Rukletsov, Anand Mazumdar, Andrei Budnik, Andrew Schwartzmeyer, Andrey Dudin, Andy Pang, Anindya Sinha, Armand Grillet, Avinash sridharan, Benjamin Bannier, Benjamin Hindman, Benjamin Mahler, Benno Evers, Bob Eckert, Chun-Hung Hsiao, Cynthia Thomas, Deepak Goel, Dmitry Zhuk, Gaston Kleiman, Gastón Kleiman, Gilbert Song, Greg Mann, Ilya Pronin, Jack Yang, James DeFelice, James Peach, Jan Schlicht, Jason Lai, Jeff Coffler, Jiang Yan Xu, Jie Yu, Joerg Schad, John Kordich, Joseph Wu, Julien Pepy, Kapil Arya, Kevin Klues, Megha Sharma, Meng Zhu, Michael Park, Nathan Jackson, Neil Conway, Packt, Pranay Kanwar, Qian Zhang, Quinn Leng, Richard Shaw, ThodorisZois, Till Toenshoff, Tomas Barton, Tomasz Janiszewski, Vinod Kone, Zhitao Li

希望Apache Mesos 1.5能够让您满意!

原文链接:Mesos 1.5: Storage, Performance, Resource Management, and Containerization improvements

去哪儿网OPS基于Mesos/Docker构建的Elasticsearch容器化私有云

尼古拉斯 发表了文章 • 0 个评论 • 2913 次浏览 • 2017-11-16 15:42 • 来自相关话题

【编者的话】本次分享主要介绍一下去哪儿网 OPS 团队利用 Mesos 资源管理平台和 Docker 容器技术所构建的 Elasticsearch 容器化的私有云。主要有四个部分, 第一个部分主要介绍一个我们当初做这个平台的背景,和现在的规模和现状,第二个部分 ...查看全部
【编者的话】本次分享主要介绍一下去哪儿网 OPS 团队利用 Mesos 资源管理平台和 Docker 容器技术所构建的 Elasticsearch 容器化的私有云。主要有四个部分, 第一个部分主要介绍一个我们当初做这个平台的背景,和现在的规模和现状,第二个部分主要简单介绍一下整个平台的技术实现,最后分享是持续构建方面的工作以及监控和报警相关方面的工作。
#背景与现状

2015年底到2016年初的这段时间,公司业务线对 ES 的需求量暴增,传统的使用 ES 的方式逐渐显现出一些弊端,主要有一下几点的内容:
01.jpg

针对上述所列的几点弊端,我们最初制定的几点设计目标如下:
02.jpg

最终,为了达到这几点目标,我们就设计和开发了这个平台。
03.jpg

自从16年3、4月份这个平台上线以来,工作效率得到了很大改进,主要有以下三个方面:
04.jpg

下面这个图是统计的过去传统的使用方式与现在的平台的方式使用 ES 所带来的资源利用率的提升:
05.jpg

这个是我们目前的平台规模:
06.jpg

07.jpg

整个平台支持了很多重要系统后端的数据存储,比如:
08.jpg

#技术实现

刚开始做这个平台的时候,我们主要调研参考了以下三个系统和平台:
9.jpg

第一个 Elastic Cloud 是 Elastic 官方提供的一个公有云的服务,他能够提供快速集群构建的能力,也具备自助化配置,快速扩容能力,比较符合我们的预期功能。第二个 Amazon Elasticsearch Service 同样也是一个公有云服务,能够提供快速的集群构建能力,自助化配置等等,同样也为我们提供了极大的参考价值。第三个是一个开源的基于 Mesos 的一个调度框架,他的设计是一个 Framework 代表一个 ES 集群,Framework 的每一个 Executor 代表一个 ES 节点,但是也有许多不支持,包括不支持多种角色节点的配置,不支持自助化的配置,不支持插件的安装,这与我们的设计初衷是相违背的。结合了上述三个例子,我们设计指定了我们自己的技术方案。
10.jpg

整个平台基于 Mesos,所有组件以 Docker 容器的形式被 Marathon 调度跑起来,这个是一个整体的结构图:
11.jpg

我们底层所有的机器都是被同一个 Mesos 来进行统一管理的,Mesos 之上运行着 Marathon 调度框架,值得注意的是,我们有两层的 Marathon,底层比较大的 Marathon 我们称之为 Root Marathon,上层包含在 Root Marathon 之中的小的 Marathon 我们称之为 Sub Marathon,Root Marathon 只负责调度内层的Sub Marathon,内存的 Sub Marathon 才是真正承载着我们每一个 Es Saas 服务。我们所有的组件都是跑在 Docker 容器里面的。
12.jpg

那么我们平台的资源是怎么分配的呢,这个图是一个分配的结构图,可以看到资源是按照 Marathon 分层的这种方式来分配的,Root Marathon 拥有系统所有的资源,Sub Marathon 是资源分配的最小单位,每一个都有它既定的资源,资源结构如此,当然集群间的逻辑隔离也是如此。
13.jpg

Sub Marathon 不仅有他自己的资源,而且我们将它和业务线做了一一映射,也就是说一个Sub Marathon 唯一的代表一个业务线,同时它也是承载了业务线的所有集群。

下面这个图展示的是 Sub Marathon 内部细节的结构图:
14.jpg

一个 Sub Marathon 可以承载多个 ES 集群,每一个 ES 集群有4个重要的组件,分别是:Bamboo,es-master,es-datanode,es2graphite,这4个组件是组成 ES 集群的基础,他们分别对应着一个 Marathon 的 APP,APP 的 task 是真正的 ES 节点。 下面这个图展示了上述4种基础组件之间的关系:
15.jpg

默认的 ES 有3个 master 节点和3个 datanode 节点,他们分为两个 Marathon APP 独立运行,他们之间互相的服务发现是由 Bamboo + HAProxy 这个组件来完成的,这样他们才能连成一个集群,es2graphite 负责收集 ES 集群指标,它的原理就是调用 ES 内部的接口获取指标,然后聚合打到后端的 Graphite 上分析展示。pyadvisor 这个组件不是存在每一个集群中的,而是 run 在每一个 mesos slave 上的一个服务,他们负责收集容器维度的指标,聚合之后打到后端 Graphite 上实时展示,下面就是一个具体的 slave 机器上的快照:
16.jpg

每个机器上可以跑多个 ES 节点,不同的 ES 节点之间使用端口号来区别。

在每一个 ES 集群中,起着至关重要作用的就是服务发现,而这个服务发现是由 Bamboo + HAProxy 这个组件来完成的。
17.jpg

Bamboo 是一个开源的跑在 Marathon 之上服务发现的工具,它的原理就是注册了 Marathon 的 callback 接口接受 Marathon 事件消息时时解析并 reload haproxy。

ES 集群内部服务发现的配置其实只是用了一句图中的配置项,这个配置项是 ES 的单播地址,是告诉 ES 节点去哪个机器的哪个端口找 master 的,我们只是简单的把他替换成了 Haproxy 的 host 和 port。ES 节点在起来的时候,Bamboo 检测到启动事件,随即通过 Marathon API 获取到真实的 Master 的 host 和 port,然后 Reload Haproxy 建立端口转发关系,同时,ES Datanode 节点在起来的时候,就会通过 Haproxy 的前端 host 和 port 经转发到真实的 Master 地址上,由此实现了服务发现的过程。三个 Master 之间也是同样的道理,他们通过 Haproxy 再“回连”自己。

在数据持久化和可靠性方面我们做了一下几个方面的工作:
18.jpg

#配置和部署

接下来介绍一下我们做的自助配置和持续构建方面的工作,有关所有的 ES 的配置我们都存在了 GitLab 中,包括一个特殊的 pre-run 文件,这个文件定义了在我们启动 ES 节点实例之前我们该做些什么,这个文件是可以修改的,可以由业务线同学自定义。同时一些其他的配置文件也是存在 GitLab 上的,修改之后,只需要重启容器即可生效。
19.jpg

同时我们在自助管理方面也做了一些工作,下图是我们自己做的一个 Web 系统, 用来展示详细的集群信息和做一些自助化配置方面的工作。
20.jpg

21.jpg

22.jpg

在新集群交付的时候,我们也是直接交付这个 Web 页面,业务线同学可以很方便的查到信息,也可以很方便的做一些操作。说到交付,我们在持续构建方面也做了一些工作。
23.jpg

这个是新的 ES 集群从配置到部署到上线的整个过程,都是基于 Jenkins 来做的,一共有三步,第一步是配置的初始化,这一步中会生成部署过程中所有的配置文件,生成之后直接存储到 GitLab 中,到了第二步集群部署的时候,我们会按照顺序读取配置,一一的将各个组件提交到 Marathon,最后一步就是 Marathon 调度运行,等全部完成之后,我们一个完整的 ES 集群也就 work 了。
#监控与报警

最后一部分说一下监控和报警,监控指标的收集,主要有两个方式:
24.jpg

下面是指标聚合之后的一个示例:
25.jpg

26.jpg

关于报警,主要有一下几个方面:
27.jpg

最后,用一张图来总结一下所有的内容:
28.jpg

从 ES 的建立到销毁,我们做到了 ES 集群整个生命周期的管理,建立初我们会做容量预估和参数的配置,等到部署的时候,我们有持续构建部署的工具来做,服务上线之后我们提供了可以自助配置,自助插件的 web 工具,极大的方便了开发人员,同时也有完备的监控和报警。集群下线的时候,统一的回收资源,做一些清理拓补的工作。

原文链接:OPS基于Mesos/Docker构建的Elasticsearch容器化私有云&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=w4%2BKnbJeburqHxw1NITmvjD%2F0Yl2jglryfwheZBsvTHlPo4n1tH5rOO3wR0XQnJj)(作者:马文)

携程容器云优化实践

尼古拉斯 发表了文章 • 0 个评论 • 4134 次浏览 • 2017-11-10 20:54 • 来自相关话题

随着微服务架构的流行,把容器技术推到了一个至高点上;而随着Docker,Kubernetes等容器技术的日趋成熟,DevOps的概念也再次热度上升;面对容器化的大潮趋势,各家公司都在积极地响应和实践,携程也在这方面做了不少工作,形成了自己的容器云平台。 ...查看全部
随着微服务架构的流行,把容器技术推到了一个至高点上;而随着Docker,Kubernetes等容器技术的日趋成熟,DevOps的概念也再次热度上升;面对容器化的大潮趋势,各家公司都在积极地响应和实践,携程也在这方面做了不少工作,形成了自己的容器云平台。

从容器云的打造思路上,携程将其划分成了水上、水下两大部分:

* 水下部分是指容器云服务的基础架构
* 水上部分是指面向容器而产生的一系列工程实践配套

水下部分对Dev来说相对透明,而水上部分则会对Dev工作有直接影响,也就是DevOps概念里所提到“混乱之墙”所在的地方。所以只要水上、水下同时做好了,容器云才能真正落地,并符合DevOps理念的设想。
#一、基础架构

容器云在携程主要经历了以下3个阶段:
01.png

##第一阶段,模拟虚机,通过OpenStack进行管理

在这个阶段,主要的目的是验证携程已有的应用是否能够在Docker容器下正常运行,并提升系统与容器的兼容性。这个过程中系统的主要架构还是使用OpenStack的nova模块,把Docker模拟成虚机的形式进行管理,除了应用实际运行的环境产生了变化,其他任何流程,工具都不变,从而使影响范围控制在最小。
##第二阶段,实现镜像发布,使用Chronos运行Job应用

在这个阶段,主要的目的是通过镜像的方式实现应用的发布和变更。真正实现 Immutable Delivery,即一旦部署后,不再对容器进行变化。并且在这个过程中,架构从比较繁重的OpenStack体系中解脱出来。使用轻量级的Mesos+Chronos来调度Job应用,在这个过程中我们同时去掉了对Long Running的Service类型应用的支持,以方便测试在极端情况下调度的消耗,和整个系统的稳定性。

此时,整个容器云的架构如下图:
02.jpg

实践证明这个架构在应对大量并发Job的调度时,Mesos自身调度消耗过大,因为每启动一次Job都需要拉起一个Docker实例,开销客观。同时也证明在携程这样的应用体量下,直接使用开源Framework是无法满足我们的需求的,这也促使我们开始走向自研Framework的方向。
##第三阶段,自研Framework

在这个阶段,我们主要要解决的问题有:

* 同时支持Job与Service两种类型的应用
* 为每个Docker实例分配独立的IP
* 支持Stateful的应用
* 完善容器的监控体系

此时的总体架构如下图:
03.jpg

与第二阶段的架构不同之处:

* 首先,重新封装了Mesos的Rest API层,使得对外提供的API更丰富(可以与其他已有系统结合,提供更多的功能),同时基于一些规范统一的考虑,收拢了一些个性化参数的使用。除此之外,独立抽象API层也是为了将来能够快速适配其他架构体系,如Kubernetes时,可以做到对上应用透明。
* 其次,对Mesos做了集群化分布,从而提高Mesos本身的可用性。
* 最后,为了应对大量Job类应用的调度,采用了与long running一样的方式,将Executor放置于容器内部。做到Job调度时,不重新启动容器,而是在容器内部调度一个进程。

说完了系统架构后,还有2个比较重要的问题:
##网络

携程对容器实例的要求是,单容器单IP,且可路由,所以网络选项上采用的仍旧是Neutron+OVS+VLan这个模式,这个模式比较稳定,网络管理也比较透明。在实际对每个容器配置网络的过程中,携程自研了一套初始化hook机制,以通过该机制在容器启动后从外部获取对应的网络信息,如网段,或者Neutronport等,在配置到容器内,这样就完成了网络配置的持久化。大致的机制如下图所示:
04.jpg

当然利用这个hook机制还能处理其他一些特殊的case,之后也会有提到。
##监控

05.jpg

监控分为2个部分,一块是对Mesos集群的监控。携程用了很多开源技术,如:Telegraf、InfluxDB、Grafana等,并做了一些扩展来实现Mesos集群的监控,采集mesos-master状态、task执行数量、executor状态等等,以便当Mesos集群出现问题时能第一时间知道整个集群状态,进而进行修复。

另一块是对容器实例的监控,携程监控团队开发了一套监控系统hickwall, 实现了对容器的监控支持。 hickwall agent部署在容器物理机上,通过Docker client 、Cgroup等采集容器的运行情况,包括 CPU 、Memory、Disk IO等常规监控项;由于容器镜像发布会非常频繁的创建、删除容器,因此我们把容器的监控也做成自动发现,由hickwall agent发现到新的容器,分析容器的label信息(比如: appid、版本等)来实现自动注册监控;在单个容器监控的基础上,还可以按照应用集群来聚合显示整个集群的监控信息。
06.jpg

##自研Framework的动机


* 轻量化,专注需求

开源Framework为了普适性,和扩展性考虑,相对都比较重,而携程实际的使用场景,并不是特别复杂,只需要做好最基础的调度即可。因此自研的话更可以专注业务本身的需求,也可以更轻量化。

* 兼容性,适配原有中间件

由于携程已经形成了比较完整的应用架构体系,以及经过多年打造已经成熟的中间件系列。所以自研Framework可以很好地去适配原有的这些资源,使用开源项目反而适配改造的成本会比较大,比如路由系统,监控系统,服务治理系统等等。

* 程序员的天性,改不如重写

最后一点就比较实在了,开源项目使用的语言,框架比较分散,长远来说维护成本比较大

##自研Framework的甜头

正如前面所说,自研Framework能够很方便地解决一些实际问题,下面就举一个我们碰到的实际例子。

我们知道Mesos本身调度资源的方式是以offer的模式来处理的,简单来说就是Mesos将剩余资源的总和以offer的形式发送出来,如果有需求则占用,没有需求则回收,待下次发送offer。但是如果碰到下图这样的情况,即Mesos一直给出2核的资源,并且每次都被占用,那一个需要4核的实例什么时候能拿到资源呢?
07.jpg

我们把这种情况叫做offer碎片,也就是一个先到的大资源申请,可能一直无法得到合适的offer的情况。

解决这个问题的办法其实很简单,无非2种:

  1. 将短时间内的offer进行合并,再看资源申请的情况
08.jpg

  1. 缩短mesosoffer的timeout时间,使其强制回收合并资源,再次offer
09.jpg


携程目前采用的方案2,实现非常简单。

以上大致介绍了一下携程容器云的水下部分,即基础架构的情况,以及自研Framework带来的一些好处。关于Kubernetes,由于我们封装了容器云对外的API层,所以其实对于底层架构到底用什么,已经可以很好的掌控,我们也在逐步尝试将一些stateful的应用跑在Kubernetes上,做到2套架构的并存,充分发挥各自的优势。
#二、工程实践

容器化的过程除了架构体系的升级,对原先的工程实践会带来比较大的冲击。也会遇到许多理念与现实相冲突的地方,下面分别介绍携程遇到的一些实际问题和解决思路。
##代码包到镜像,交付流程如何适配,如何迁移过渡?

DevOps理念提倡“谁开发,谁运行”,借助docker正好很方便的落地了这个概念。携程的CI/CD系统同时支持了基于镜像与代码包的发布。这样做的好处是能够在容器化迁移的过程中做到无缝和灰度。
10.jpg

##能像虚机一样登陆机器吗?SSH?

Docker本身提倡单容器单进程,所以是否需要sshd是个很尴尬的问题。但是对于Docker实例的控制,以及执行一些必须的命令还是很有必要的,至少对于ops而言是一种非常有效的排障手段。所以,携程采用的方式是,通过web console与宿主机建立连接,然后通过exec的方式进入容器。
11.jpg

##Tomcat能否作为容器的主进程?

我们知道主进程挂掉,则容器实例也会被销毁。而Java开发都知道,Tomcat启动失败是很正常的case。由此就产生了一个矛盾,Tomcat启动失败,并不等同于容器实例启动失败,我们需要去追查Tomcat启动失败的原因。由此可见,Tomcat不能作为容器的主进程。因此,携程仍旧使用Supervisord来维护Tomcat进程。同时在启动时会注册一些自定义hook,以应对一些特殊的应用场景。比如:某些应用需要在Tomcat成功启动,或成功停止后进行一些额外的操作,等等。
12.jpg

##JVM配置是谁的锅?

容器上线后一段时间,团队一直被一个JVM OOM的问题所困扰,原来在虚机跑的好好的应用,为什么到容器就OOM了呢?最后定位到问题的原因是,容器采用了cpu quota的模式,但JVM无法准确的获取到cpu的数量,只能获取到宿主机cpu的数量;同时由于一些java组件会根据cpu的数量来开启thread数量,这样就造成了堆外内存殆尽,最终造成OOM。

虽然,找到了OOM的原因,但是对于容器云来说,却面临了一个棘手的问题。容器实例不像虚机,在虚机上,用户可以按需定义JVM配置,然后再将代码进行发布。在容器云上,发布的是镜像,JVM的配置则变成了镜像的包含物,无法在runtime时进行灵活修改。

而且,容器本身并不考虑研发流程上的一些问题。比如,我们有不同的测试环境,不同的测试环境可能有不同的JVM配置,这显然与docker设想的,一个镜像走天下的想法矛盾了。

最后,对于终端用户而言,在选择容器时,往往挑选的是flavor,因此我们需要对应不同的flavor定义一套标准的JVM配置,利用之前提到的容器启动时的hook机制,从外部获取该容器匹配的标准JVM配置。

我们也总结了一些对于对外内存的最佳实践,如下:

Xmx = Xms = Flavor 80%
* Xss = 256K
* 堆外最小800,最大2G,符合这个规则之内,以20%计

##问题又来了,用户需要自定义JVM?

最终,我们将JVM配置划分成了3个部分:

  1. 系统默认推荐部分
  2. 用户自定义Override部分
  3. 系统强制覆盖部分

允许用户通过代码或外部配置系统,对应用的JVM参数进行配置,这些配置会覆盖掉系统默认推荐的配置,但是有一些配置是公司标准,不允许覆盖的,比如统一的JMX服务地址等,这些内容则会在最终被按标准替换成公司统一的值。
13.jpg

##Dockerfile的原罪

Dockerfile有很多好处,但同时也存在很多坏处:

* 无法执行条件运算
* 不支持继承
* 维护难度大
* 可能成为一个后面,破坏环境标准

因此,如果允许PD对每个应用都自定义Dockerfile的话,很有可能破坏已有的很多标准,产生各种各样的个性化行为,使得统一运维变成不可能,这种情况在携程这样的运维体谅下,是无法接受的。
##打造“Plugin”服务平台

所以,携程决定通过 “Plugin”服务的方式,把Dockerfile的使用管控起来,将一些常规的通过Dockerfile实现的功能形成为“Plugin”,在Image build的过程中进行执行。这样做的好处是,所提供的服务可标准化,并且可复用,还可以任意组装。比如:我们分别提供“安装FTP”,“安装Jacoco”等插件服务。用户在完成自己的代码后,进行image build时就可以单选或多选这些服务,那最后形成的image中就会附带这些插件。并且针对不同的测试环境可以选择不同的插件,形成不同的镜像。
14.jpg

对于一个“Plugin”而言,甚至可以定义一些hook(注册supervisord hook),以及一些可exec执行的脚本,从而进一步扩展了“Plugin”的能力。比如可以插入一个Tomcat的启停脚本,从而获取从外部控制容器内Tomcat的能力。
15.jpg

公司内的每个PD都可以申请注册“Plugin”,审核通过后,就可以在平台上被其他应用所使用。注册步骤:

  1. 为服务定义名称和说明
  2. 选择服务可支持的环境(如:测试,生产)
  3. 上传自定义的Dockerfile
  4. 上传自定义的可运行脚本
16.jpg

17.jpg


##“Jacoco Plugin”的实例

Jacoco是一个在服务端收集代码覆盖率的工具,以帮助测试人员确认测试覆盖率。这个工具的使用有以下几个需求:

  1. 需要在代码允许环境中安装Jacoco agent
  2. 只需要在特定的测试环境进行安装,生产环境不能安装
  3. 被测应用启动后,需要往Jacoco后端服务进行注册
  4. 测试过程中可以方便控制Jacoco的启停(通过Tomcat启动参数控制)

针对以上的需求,定制一个“JacocoPlugin”的工作,如下图:
18.jpg


  1. 通过dockerfile安装 jacoco agent
  2. 注册一个supervisord hook,在tomcat启动成功后向Jacoco service进行注册
  3. 利用一个自定义tomcat重启脚本,并在平台的web server上暴露API来控制Jacoco的启停

这样,所有容器云上的应用在image build时就都可以按需选择是否需要开通Jacoco服务了。
19.jpg

利用这样的平台机制,还提供了一系列其他类型的“Plugin”服务,以解决环境个性化配置的问题。
#三、总结


  1. DevOps或者容器化是理念的变化,更需要接地气的实施方案
  2. 基础架构,工程实践和配套服务,需要并进,才能落地
  3. 适合自己的方案才是最好的方案

携程的容器云进程还在不断的进化之中,很多新鲜的事务和问题等待着我们去发现和探索。

作者简介:王潇俊,多年来致力于云平台及持续交付的实践。2015年加入携程,参与携程部署架构的全面改造,主导设计和打造新一代的适用于微服务的发布系统。同时负责基于携程私有云的兼容虚机与容器的持续交付平台。ROR狂热粉丝,敏捷文化的忠实拥趸。

原文链接&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=bWkIjfRZWxqiliz9Dzk6utuzNefKy4zdNZH%2BqVjeYKoc0XKaFb%2FrxpPgrbNrSege)

Mesos容器引擎的架构设计和实现解析

李颖杰 发表了文章 • 0 个评论 • 2923 次浏览 • 2017-09-19 15:14 • 来自相关话题

【编者的话】提到容器,大家第一时间都会想到Docker,毕竟Docker是目前最为流行的容器开源项目,它实现了一个容器引擎(Docker engine),并且为容器的创建和管理、容器镜像的生成、分发和下载提供一套非常便利的工具链,而它的容器镜像格式几乎就是业界 ...查看全部
【编者的话】提到容器,大家第一时间都会想到Docker,毕竟Docker是目前最为流行的容器开源项目,它实现了一个容器引擎(Docker engine),并且为容器的创建和管理、容器镜像的生成、分发和下载提供一套非常便利的工具链,而它的容器镜像格式几乎就是业界的事实标准。但其实除了Docker之外,在容器的开源生态圈中还有其它一些项目也在做自己的容器引擎,这样的项目一般也被称作为容器运行时(container runtime),比如:CoreOS的rkt和Mesos的容器引擎(Mesos containerizer)。

在本文中,我将对Mesos容器引擎进行一个全面的介绍,解释在Docker如此流行的情况下Mesos为什么还要坚持做自己的容器引擎,介绍Mesos容器引擎的总体架构和各核心组件,以及它对容器各相关标准规范的采纳和支持。
#容器和容器引擎的定义

首先我们来了解一下什么是容器。我个人对容器的定义是:一个或一组使用了cgroups做资源限定、使用了namespace做资源隔离、且使用了的镜像文件做根文件系统的进程。如下图1所示:
1.jpg

图 1

由此可见,实现容器的三大核心技术分别是:

  1. Cgroups(Control Cgroups,控制群组):Linux中的Cgroups包含多个不同的子系统,如:CPU、memory、device等。通过这些子系统就可以对容器能够使用的各种资源进行限定,比如:通过CPU子系统可以限定容器使用CPU资源的相对权重和单位时间内能够使用的的CPU时间。
  2. Namespace(命名空间):Linux同样支持多个namespace,如:mount、network、pid等。通过这些namespace可以对容器进行不同维度的资源隔离,比如:通过mount namespace可以让容器具有自己独立的挂载空间,在主机或别的容器中发生的挂载事件对该容器就不可见,反之亦然。通过network namespace可以让容器具有自己独立的网络协议栈,而不必和其所在主机共用同一个网络协议栈。
  3. Layered filesystem(分层文件系统):Linux中的layered filesystem有多种不同的实现,如:AUFS、overlayfs等。通过这些layered filesystem配合mount namespace就可以快速部署出容器自己独立的根文件系统。而且,基于同一个镜像文件创建出来的多个容器可以共享该镜像文件中相同的只读分层,以达到节省主机磁盘空间的效果。

上面这三种技术都是在Linux系统中存在已久且相对成熟的技术,但让终端用户直接使用它们来创建和管理容器显然并不方便。所以,容器引擎就应运而生了,它所做的主要工作就是将这三种技术在其内部有机地结合和利用起来以实现创建容器和管理容器的生命周期,并对外提供友好的接口让用户能够方便的创建和管理容器。Cgroups、namespace和layered filesystem的详细介绍我就不再本文中赘述了,感兴趣的读者可以查阅Linux中这三种技术的相关文档。

需要指出的是,容器引擎对这三种技术的使用往往是有选择且可定制的,比如:用户可以通过容器引擎创建一个使用cgroups memory子系统但不使用CPU子系统的容器,这样的容器对内存资源的使用就会受到相应的限定,但对CPU资源的使用则不受任何限定。用户也可以创建一个使用mount namespace但不使用network namespace的容器,这样的容器就会有自己独立的挂载空间,但和主机共用一个网络协议栈。Mesos容器引擎在这方面的可定制化进行得非常彻底,除了上面所说的对cgroups子系统和namespace的定制之外,Mesos容器引擎还能够支持无镜像文件创建容器,这是其它容器引擎所不具备的。
#Mesos容器引擎产生的背景

在Docker如此流行的情况下,Mesos为什么还要坚持做自己的容器引擎呢?其实Mesos在很早期的版本就和Docker进行了集成,用户可以通过Mesos创建一个Docker容器,在内部实现上,Mesos agent会调用Docker的命令行和Docker engine通信,以让其创建Docker容器。这也就是意味着Mesos对容器的管理严重依赖于Docker engine,而这种做法的问题是:

  1. 稳定性不足:Mesos常常会被用来管理几千甚至上万节点的生产环境,而在如此大规模的生产环境中,稳定性是极其重要的。而在这样的环境中,通过实测我们发现Docker engine的稳定性是有所不足的,有时会出现停止响应甚至一些莫名其妙的bug,而这样的问题反映到Docker社区中后有时又无法及时得到解决。这就促使了Mesos的开发者开始设计和实现自己的容器引擎。
  2. 难于扩展:Mesos的用户常常会提出一些和容器相关的新需求(比如:让容器能够使用GPU资源,通过CNI配置容器的网络,等等),而这些需求都受限于Docker engine的实现,如果Docker社区拒绝采纳这些需求,或有完全不同的实现方式,那Mesos作为Docker engine之上的调用方也无计可施。

众所周知,Mesos的定位是数据中心操作系统,它是一个非常好的通用资源管理和资源调度系统,一开始就是一个“大脑级“的存在,但如果只有“大脑”没有“四肢”(对容器的支持就是“四肢”的一种),或“四肢“掌握在别人手中,那Mesos本身和其生态圈的可持续发展显然是受限的。所以,发展自己的“四肢”是Mesos逐步发展壮大的必然选择。

基于上述这些原因,Mesos社区决定要做自己的容器引擎,这个容器引擎完全不依赖于Docker engine(即:和Docker engine没有任何交互),但同时它又完美兼容Docker镜像文件。这也就意味着,用户可以通过Mesos在一台没有安装运行Docker engine的主机上,基于任意Docker镜像创建出容器。
#Mesos容器引擎的总体架构和核心组件

首先我们来看一下Mesos的总体架构,以及容器引擎在其中的位置。
2.jpg

图 2

上图2中蓝色部分是Mesos自身的组件,可以看到Mesos是典型的Master + Agent架构。Master运行在Mesos集群中的管理节点上,可以有多个(一般设置为三个、五个等奇数个),它们相互之间通过Zookeeper来进行leader选举,被选举成leader的master对外提供服务,而其他master则作为leader master的备份随时待命。Master之上可以运行多个计算框架,它们会调用master提供的API发起创建任务的请求。Master之下可以管理任意多个计算节点,每个计算节点上都运行一个Agent,它负责向Master上报本节点上的计算资源,并接受master下发的创建任务的请求,将任务作为容器运行起来。而Agent内部的一个组件containerizer就是用来管理容器的生命周期的(包括:容器的创建/更新/监控/销毁),它就是Mesos的容器引擎。

我们再来进一步看一下Mesos容器引擎内部的总体架构和核心组件。
3.jpg

图 3

如上图所示,Meoss容器引擎内部包含了多个组件,主要有:Launcher、Provisioner(其内部又包含了store和backend两个组件)和Isolator。下面来逐一介绍这些组件的主要功能和用途。
##Launcher

Launcher主要负责创建和销毁容器,由于容器的本质其实就是主机上的进程,所以launcher在其内部实现上,主要就是在需要创建容器时,调用Linux系统调用fork()/clone()来创建容器的主进程,在需要销毁容器时,调用Linux系统调用kill()来杀掉容器中的进程。Launcher在调用clone()时根据需要把容器创建在其自己的namespace中,比如:如果容器需要自己的网络协议栈,那launcher在调用clone()时就会加入CLONE_NEWNET的参数来为容器创建一个自己的network namespace。

Launcher目前在Mesos中有两种不同的实现:Linux launcher和Posix launcher,上面提到的就是Linux launcher的实现方式,Posix launcher适用于兼容Posix标准的任何环境,它主要是通过进程组(process group)和会话(session)来实现容器。在Linux环境中,Mesos Agent会默认启用Linux launcher。
##Provisioner

为了支持基于镜像文件创建容器,Mesos为其容器引擎引入了Provisioner。这个组件完成的主要工作是通过store组件来下载和缓存指定的镜像文件,通过backend组件基于指定的镜像文件来部署容器的根文件系统。
##Store

Mesos容器引擎中目前已经实现了Appc store和Docker store,分别用来支持Appc格式的镜像和Docker镜像,此外,Mesos社区正在实现OCI store以支持符合OCI(Open Container Initiative)标准格式的镜像。所以基本上,针对每种不同的镜像文件格式,Mesos都会去实现一个对应的store。而以后当OCI镜像格式成为业界容器镜像文件的标准格式时,我们可能会考虑在Mesos容器引擎中只保留一个OCI store。

Store下载的镜像会被作为输入传给backend来去部署容器的根文件系统,且该镜像会被缓存在agent本地的工作目录中,当用户基于同一镜像再次创建一个容器时,Store就不会重复下载该镜像,而是直接把缓存中的镜像传给backend。
##Backend

Backend的主要工作就是基于指定镜像来部署容器的根文件系统。目前Mesos容器引擎中实现了四个不同的backend:

  1. AUFS:AUFS是Linux中的一种分层文件系统。AUFS backend就是借助这种分层文件系统把指定镜像文件中的多个分层挂载组合成一个完整的根文件系统给容器使用。基于同一镜像文件创建出来的多个容器共享相同的只读层,且各自拥有独立的可写层。
  2. Overlay:Overlay backend和AUFS backend非常类似,它是借助Overlayfs来挂载组合容器的根文件系统。Overlayfs也是一种分层文件系统,它的原理和AUFS类似, 所以,AUFS backend所具备的优点Overlay backend都有,但不同的是Overlayfs已经被Linux标准内核所接受,所以,它在Linux平台上有更好的支持。
  3. Copy:Copy backend的做法非常简单,它就是简单地把指定镜像文件的所有分层都拷贝到一个指定目录中作为容器的根文件系统。它的缺点显而易见:基于同一镜像创建的多个容器之间无法共享任何分层,这对计算节点的磁盘空间造成了一定的浪费,且在拷贝镜像分层时也会消耗较大的磁盘I/O。
  4. Bind:Bind backend比较特殊,它只能够支持单分层的镜像。它是利用bind mount这一技术把单分层的镜像以只读的方式挂载到指定目录下作为容器的根文件系统。相对于Copy backend,Bind backend的速度更快(几乎不需要消耗磁盘I/O),且多个容器可以共享同一镜像,但缺点就是只能支持单分层镜像,且根文件系统是只读的,如果容器在运行时需要写入数据,就只能通过额外挂载外部卷的方式来实现。

在用户没有指定使用某种backend的情况下,Mesos Agent在启动时会以如下逻辑来自动启用一种backend:

  1. 如果本节点支持Overlayfs,启用Overlay backend。
  2. 如果本节点不支持Overlayfs但支持AUFS,启用AUFS backend。
  3. 如果OverlayFS和AUFS都不支持,启用Copy backend。

由于Bind backend的局限性较大,Mesos Agent并不会自动启用它。
##Isolator

Isolator负责根据用户创建容器时提出的需求,为每个容器进行指定的资源限定,且指引launcher为容器进行相应的资源隔离。目前Mesos内部已经实现了十多个不同的isolator,比如:cgroups isolator通过Linux cgroups来对容器进行CPU、memory等资源的限定,而CNI isolator会指引launcher为每个容器创建一个独立network namespace以实现网络隔离,并调用CNI插件为容器配置网络(如:IP地址、DNS等)。

Isolator在Mesos中有着非常好的模块化设计,且定义了一套非常清晰的API接口让每个isolator可以根据自己所需要完成的功能去有选择地实现。这套isolator接口贯穿容器的整个生命周期,Mesos容器引擎会在容器生命周期的不同阶段通过对应的接口来调用isolator完成不同的功能。下面是一些主要的Isolator接口:

* prepare():这个接口在容器被创建之前被调用,用来完成一些准备性的工作。比如:cgroups isolator在这个接口中会为容器创建对应的cgroups。
* isolate():这个接口在容器刚刚被创建出来但还未运行时被调用,用来进行一些资源隔离性的工作,比如:cgroups isolator在这个接口中会把容器的主进程放入上一步创建的cgroups中以实现资源隔离。
* update():当容器所申请的资源发生变化时(如:容器在运行时申请使用更多的CPU资源),这个接口会被调用,它用来在运行时动态调整对容器的资源限定。
* cleanup():当容器被销毁时这个接口会被调用到,用来进行相关的清理工作。比如:cgroups isolator会把之前为容器创建的cgroups删除。

借助于这种模块化和接口标准化的设计,用户可以很方便地根据自己的需求去实现一个自己的isolator,然后将其插入到Mesos agent中去完成特定资源的限定和隔离。
#Mesos容器引擎对容器标准规范的支持

容器这项技术在近几年来飞速发展,实现了爆炸式的增长。但就像任何一种成熟的技术一样,在度过了“野蛮生长期”后,都需要制定相应的规范来对其进行标准化,让它能够持续稳定地发展。容器技术也不例外,目前已知的容器相关的标准规范有:

  1. OCI(Open Container Initiative):专注于容器镜像文件格式和容器生命周期管理的规范,目前已经发布了1.0的版本。
  2. CNI(Container Network Interface):专注于容器网络支持的规范,目前已经发布了0.6.0版本。
  3. CSI(Container Storage Interface):专注于容器存储支持的规范,目前还在草案阶段。

标准规范带来的益处是显而易见的:

  1. 对于终端用户:标准化的容器镜像和容器运行时能够让用户不必担心自己被某个容器引擎所“绑架”,可以更加专注于对自身业务和应用的容器化,更加自由地去选择容器引擎。
  2. 对于网络/存储提供商:标准规范中定义的网络/存储集成接口把容器引擎的内部实现和不同的网络/存储解决方案隔离开来,让各提供商只需实现一套标准化接口就可以把自己的解决方案方便地集成到各个容器引擎中去,而不必费时费力地去逐个适配不同的容器引擎。

Mesos容器引擎在设计和实现之初,就持有拥抱和采纳业界标准规范的态度,是最早支持CNI的容器引擎之一,且目前正在积极实现对OCI镜像规范的支持。CSI目前正在由Mesos社区和Kubernets社区一起主导并逐步完善,待CSI逐渐成熟后,Mesos容器引擎自然会第一时间支持。日后,作为同时支持三大标准规范的容器引擎,Mesos容器引擎自然会更好地服务上层应用框架和终端用户,同时更加完善地支持各种主流网络/存储解决方案。

原文链接:Mesos容器引擎的架构设计和实现解析

作者:张乾,目前就职于Mesosphere,担任Mesosphere中国区研发负责人。国内首位Apache Mesos committer,专注于各种容器相关的开源技术。

Mesos 在爱奇艺的实践

李颖杰 发表了文章 • 0 个评论 • 2463 次浏览 • 2017-09-18 19:46 • 来自相关话题

【编者的话】Mesos 在爱奇艺目前管理着大约 2000 台物理机,分布在多个数据中心,单个集群最大节点数接近 600。 Mesos 平台每周启动的容器超过 500 万,峰值在线容器数近 2 万;适当的资源超卖给我们带来的是在最近一个 ...查看全部
【编者的话】Mesos 在爱奇艺目前管理着大约 2000 台物理机,分布在多个数据中心,单个集群最大节点数接近 600。

Mesos 平台每周启动的容器超过 500 万,峰值在线容器数近 2 万;适当的资源超卖给我们带来的是在最近一个季度中,所有集群 CPU 平均利用率超过 20%,而最繁忙的集群超过 50%,这对于一家互联网公司来说非常不易。

在这些惊讶的数字背后,Mesos 支撑着许多重要业务,包括但不限于,几乎所有视频、音频、图片转码,对服务质量和稳定性要求非常高的在线服务以及 StormSpark 这类实时计算分析业务等。
#牛刀小试
时光如逝,回望 Mesos 在爱奇艺的发展历程,也并非一番风顺。且不论起初的时候人员不足,借人帮助开发,开源代码成熟度不够,一日三坑,不得不暂时搁置一些项目;更别提在一家发展迅速的科技娱乐公司去推动基础设施服务变革的乏力感。
1.jpeg

爱奇艺从 2013 年底开始调研 Mesos,这个声称受到 Google Borg 集群管理系统启发的开源数据中心操作系统核心。

Mesos 是一个 ASF 顶级开源项目,Mesos的作者也创建了 Mesosphere 公司来更好的推动 Mesos 生态的发展。

并且,基于 Mesos,Mesosphere 发布了开源的数据中心操作系统 DC/OS,这一次,暴露在你眼前的不仅是内核,而是一个完整的数据中心操作系统。

在 2014 年初,我们将 Mesos 0.16.0 部署到了生产环境,之上运行了一个自研的任务调度器,以短任务的形式运行视频转码业务。

这之后,由于人员和开发量的关系,以及到了年中的时候,我们发现 Chronos 作为基于 Mesos 的短任务调度器已经变得比较完善,顺理成章的,我们尝试从自研的转码框架切换到 Chronos,由此开始了一段新的征程。
#有得有失
2.jpeg

和使用 Mesos 的感觉不一样,Chronos 并没有 Mesos 那样稳定,以至于在后面大半年的时间里,我们使用了一些临时手段来维持稳定,直到后来有更多时间彻底解决了 Chronos 的稳定性问题,在那之后,Chronos 几乎没有再出过问题。

我们对 Chronos 进行了大量开发,其中有超过 30 个 commit 回馈到 Chronos 社区并被接受,而大部分则是我们内部私有的改动,不够通用,所以没有提交到社区,而我们内部则为修改后的 Chronos 取名为 Sisyphus,古希腊中推着石头上山的神,这也是我们为数不多的自认为取得好的项目名字!
3.jpeg

伴随着 Chronos 稳定性的提高,转码业务量逐步切换到 Mesos 集群,直到 2015 年中转码团队不再维护任何生产集群;至此,Chronos 完全支撑了公司的转码生产业务。

在开发 Chronos 的同时,我们也上线了 Hadoop on Mesos 业务,不过由于业务量不大,以及后来 YARN/MapReduce2 的推出,我们将运行在 Mesos 上的业务全部迁移到了 YARN 集群。

另一方面,Storm 在解决了一些问题之后,能够稳定的提供服务,所以我们也将 Storm 业务接入了 Mesos 集群。对于另一个可以运行在 Mesos 之上的框架 Spark 来说,彼时的 Spark 运行在 Mesos 上还不够稳定,所以我们并没有上线 Spark on Mesos 业务。
4.jpeg

因为,2014 年底我们开始了对 Marathon 的调研,并且在 Marathon 之上设计和开发我们自己的 PaaS 平台 QAE(iQIYI App Engine)。
#自研 PaaS 平台 QAE
QAE 是一个完全自助式的(除了配额申请)容器云平台,用户(公司内部开发者)只需要申请资源配额,就能在 QAE 上实现对 App 的全自助式管理,生命周期管理自不必说,其它的高级功能例如:

* 基于角色的鉴权
* App 和容器的监控
* 非侵入式的接入自定义监控
* 订阅式的报警
* 根据任何监控指标自动伸缩
* 支持灰度发布、AB 测试
* App 的高级分布策略
* 健康检查
* 日志管理
* 历史容器管理(方便排障)
* 在线控制台
* CI/CD,自动部署

这里还想啰嗦几句,我对 IaaSPaaS 的理解。

从用户角度来看,IaaS 和 PaaS 面向的用户群有所区别,前者要求用户对系统有更好的理解,更高的熟悉度,类似管理员的角色;而后者要求用户对软件开发环境有更好的熟练度,类似开发者角色。

另一方面,从用户的角度来说,IaaS 提供虚机本非用户所需,用户得到的虚机和物理机并没有本质区别,所以对用户来说,没有什么附加值;IaaS 之所以普遍存在,出发点并不是为了给用户提供更好,更高级的服务,而是节约计算成本,提高大规模计算资源的维护能力。

所以,PaaS 平台 QAE 是更好的选择。
#从容器到微服务

经过两年多的漫长发展,QAE 羽翼渐丰,也接入了近万的在线容器,形成了良好的用户口碑,已经变成了能够吸引用户主动采用的平台。
5.jpeg

我们的下一步是乘上微服务的风口,提供更多的微服务友好的基础设施以及产品给我们的用户(公司内部开发者)。

因为微服务几乎总是和容器形影不离,可能会被人误以为实现了容器云平台,自然而然的也就实现了微服务平台。

在我看来,其实不然,容器仅仅只是一种软件分发、运行方式,和服务并不位于同一个维度;微服务之所以和容器形影不离,无非是容器相较于虚机来说更加易用,灵活,更加适合微小的服务来利用物理计算资源。

想象一下,微服务带来了什么问题?

一个单体 App,如果需要部署 100 个实例来提供服务,以前基于虚机的时候,开发者需要部署 100 台虚机,不管他用什么方式,总之需要部署;要知道,爱奇艺并没有专门的应用 SRE 帮助开发者维护运行环境;而现在,如果开发者使用 QAE 来管理他的 App,那么只需要在 QAE 上部署一次即可,100 个,1000 个实例,不过是点点按钮的事情。

所以,在这个例子中,对于开发者来说,将业务管理成本降低了 100 倍,太棒了!

但是,如果开发者决定将单体 App 拆分呢?如果拆成 100 个微服务,会变成什么情况?

在 QAE 上他得部署 100 次,即使 QAE 有 App 复制/导入的功能,也依然捉襟见肘,运维成本高企。

更难的是,这 100 个微服务的治理,100 个微服务的拓扑、依赖关系是什么样的?各个微服务之间的流量是怎样的?流量是否健康?微服务接口是否有完善的鉴权管理?是否能从各种维度对微服务之间的请求限流?服务调用跟踪排障?怎样快速发现,接入服务,跨数据中心的流量管控等等?

而这些微服务基础设施,严格来说,并非需要总是和容器联系起来,而是应该作为另一个维度的基础设施,发挥着举足轻重的作用,微服务基础设施之于微服务就像虚机和容器之于单个 App 实例一样重要。

微服务基础设施例如:

API gateway,APM,链路调用跟踪,服务中心等正在积极的开发当中,相信和 QAE 一样,两年过后,一定也会得到内部用户的认可。
#只争朝夕
两年太远,只争朝夕;来看看我们现在正在做哪些事情呢。

改造 QAE 的健康检查,以前是基于 Marathon 的健康检查,由于 Marathon 健康检查是集中式的,所以当容器达到数千的时候,可能会出现瓶颈;而 Mesos 的分布式健康检查则不会有这个问题,因为计算节点总是伴随着业务规模规模一起增长的。

QAE 支持托管计算资源,作为一个通用的平台,我们有一些推荐的最佳实践,比如:容器的配置有上限,因为我们不希望用户把容器当做虚机,甚至物理机来使用;

支持的网络特性,分布特性有限制,例如:共享的集群可不想让用户使用 HOST 网络模式;

出于这些考虑,有些非常想使用 QAE 的特殊业务(例如:直播转码,HCDN 等)不得不被挡在了门外。

所以,我们正在实现 QAE 支持托管的计算资源,主要需要实现:

* 计算集群对用户的鉴权,托管的集群只能被有权限的用户看到和使用
* 集群特性,QAE 需要能够探测集群支持的特性,例如:这个集群支持 HOST 网络模式,支持配置 32 核的超大容器等等。

除了 QAE 之外,对于 Mesos 和 Docker,我们也在做一些很酷的事情:

* 切换到 Mesos unified container,踢掉Docker daemon 这个一直不太稳定的家伙
* 从 Device-Mapper 切换到 OverlayFS,另一个在高并发新建/删除容器下不够稳定的组件
* 从可配置的静态资源超分迁移到动态的 Mesos Oversubscription,进一步提升资源利用率;这是一个和南京大学合作的项目,相信很快就会有结果
* 实现离线和在线业务的真正混布,结合 Mesos Oversubscription,进一步降低集群管理成本,提高利用率
* 使用 Mesos 统一管理 GPU 计算资源
* 引入公有云,提高 Mesos 集群扩容的速度和效率,让业务能够自由的在私有云和公有云上调度。

6.jpeg

虽然自认为我们在推动公司容器化应用的道路上取得了一些阶段性的成果,但路漫漫,其修远兮,还有更多的事情等着我们去完成!

原文链接:Mesos 在爱奇艺&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=NYBMuWCQxzEEN%2BkTiTVtG7ia%2FvYUb9jbjhfMRAk0CtsjTYDM4JM7YaD%2BXe0vtoFP)(作者:luffy)

作者介绍:
luffy,目前负责公司私有云计算平台(虚机及容器)的建设;加入爱奇艺前,在英特尔开源技术中心参与 MeeGo、Tizen 移动操作系统的开发;开源软件用户、爱好者、贡献者,对多个开源项目有代码贡献,从操作系统基础软件 Systemd,D-Bus 到云计算项目 Mesos,Chronos 等。

为什么我们要开源自己研发的高性能容器编排系统 Eru2

尼古拉斯 发表了文章 • 0 个评论 • 3067 次浏览 • 2017-09-08 20:36 • 来自相关话题

【编者的话】原则上来说 Eru 只是将 Docker 作为容器最小单元引擎,并不做过强的耦合和依赖。通过架构层面上的设计和优化,使得 Eru 可以支持上千甚至上万台物理机器集群,满足小型到大型公司平台层面的调度编排需求。 【烧脑式Ku ...查看全部
【编者的话】原则上来说 Eru 只是将 Docker 作为容器最小单元引擎,并不做过强的耦合和依赖。通过架构层面上的设计和优化,使得 Eru 可以支持上千甚至上万台物理机器集群,满足小型到大型公司平台层面的调度编排需求。

【烧脑式Kubernetes实战训练营】本次培训理论结合实践,主要包括:Kubernetes架构和资源调度原理、Kubernetes DNS与服务发现、基于Kubernetes和Jenkins的持续部署方案 、Kubernetes网络部署实践、监控、日志、Kubernetes与云原生应用、在CentOS中部署Kubernetes集群、Kubernetes中的容器设计模式、开发Kubernetes原生应用步骤介绍等。

作为自己 30 岁之前的一个「小目标」,白天我提交完最后一个大特质修正后,Eru2 的开源计划就走入了倒计时阶段。2007-2017 眨眼 10 年。启蒙于 hongqn 的豆瓣后端体系介绍而步入了系统工程师的深坑,受教于金山快盘的工程化实践,又有幸与启蒙自己的豆瓣平台组共事两年一起做 Douban App Engine,在 (*)aaS 的道路上越走越远。14年洲际旅行回国,从芒果TV 到 ENJOY ,从最初的 DAE Copy on Docker 到理论上国内首批大规模使用 Redis Cluster 并提供了 Cerberus容器化解决方案,这后面驱动的都是我一直想做的大一统平台。

幸运的是,有 Docker,DAE 当年隔离的问题再也不是问题 。不幸的是,有 Docker,容器的不稳定在大集群下面对管理提出了更高的要求。Docker 就像一把双刃剑,关键是你怎么去用它。Borg 提供了一个视角,而它的亲儿子 Kubernetes 以压倒性的优势成为了平台层面的事实标准。在它的身后,角落里 Docker 的亲儿子 Swarm 还在负隅顽抗,而它的身边,是一个叫 Mesos 的尸体。

那么问题来了,为什么我们要做这个东西呢?

让我们把眼光放回 2014 年,就以当时的业界视角来看,其实你是没多少选择的。当年的 Kubernetes 江湖传闻就一个人全职开发,除了 Google 爹的光环以外复杂的概念和尚不稳定的特性,没有全知全能的视野当时的你会知道终有一天它终将为王?甚至 Mesos 上的 Marathon 在先发优势上都能把 Kubernetes 按在地上摩擦,但一想到以 Apache 之名下 Mesos 那「笨重」的结构你会轻易去尝试?至于 Docker 的亲儿子,它的爹还在忙于 1.0 的 stable,它的妈还不知道是在世界的哪个角落,所以造轮子并非一个不可理解的选择。我们再把时间拨到2015年,半个前豆瓣平台组还能有机会在宜信大数据给我们带来基于特定工程的最优解 Lain。即便到了 2017 年,从我的个人角度来看,虽然 Kubernetes 几乎一统江湖,但自建平台也还是有一定土壤的。

如 Kubernetes 吧,Google 二儿子,Borg 血统最为纯净的继承者,万千资源于一身的编排调度平台集大成者,早期用户也不得不面对其架构复杂部署困难的问题。对于小公司而言,上 Kubernetes 带来的成本远高于其带来 DevOps 效率提升而降低的成本。对于中大型公司而言,Kubernetes 本身相对而言的排他性对于已有基础设施重建以及业务适配又是一个需要额外成本的地方。至于超大公司以他们的人力物力财力,就我某几位不愿意透露姓名的P8/P9基友所言,早就脱离社区自己玩自己的去了,毕竟业务才是来钱的大爷。你不能说它不行,乐观锁的分配能力完全能满足一家豆瓣类似规模的中大型公司,Pod Service 的概念抽象使得所谓的微服务化变得前所未有的简单直观。但一个东西不能说它好就要去上对吧,自己的业务模式 Workflow 要不要改造,如何改造,对于 Kubernetes 本身的运维经验有没有积累,现有的基础设施怎么办,这都是需要考虑的问题。况且线上用了 Kubernetes 了,离线任务要不要用,怎么用,如何和 Apache 全家桶搅一起,都要摸索。

其他的几种选择来说,Lain 对于特定工程来说是最优解,没有比一个能自举的平台更加迷人了。然而就我对他们的了解,如果你的团队没有豆瓣那种我要打10个的素质,学习成本还是蛮高的,需要严格的遵从 Workflow 和开发范式,需要有相当高的 DevOps 能力。已经死掉的 Mesos 系而言,光是 Apache 之名就足以吓跑很多人,已经到 2017 的今天,Hadoop 的部署使用还能出书出课程收费教人,让人不得不对其同门 Mesos 的易用性打上一个问号。况且就以资源分配来说,悲观锁资源邀约的设计在大集群下的性能还是比较堪忧的,就不说这也是一套强侵入式的架构。至于 Docker 亲儿子,在 Engine 尚未表现出足以服众的稳定性前提下,把编排直接结合进其中作为一个 Mode,作为一个平台特性的东西来讲,这是大忌。同样的,Swarm 除了原生这一个「吸引人」的地方以外,无论是资源分配,Workflow 的集成和服务抽象均不如 Kubernetes。

还有一个就是,就以上几个平台而言,离线服务均都没考虑在内。当然 Mesos 会好些,但需要额外的框架支持,这种二元结构是它的优势也是它的劣势。如 Yarn 的离线计算如何结合容器平台,如怎样结合各类不同的 Fault tolerant job scheduler,这都需要使用者自行摸索。

那么我们又做了什么?

Eru2 本质上不是一揽子解决方案,结合在芒果TV 时期的经验,我们并不想做成特定工程类的最优解,而是一个尽可能减少对现有基础设施侵入的基础组件,因为这不是一个技术问题,这是政治问题。它的设计目标有:

* 高效而精确并且多维度的资源分配和实时再分配
* 尽可能的复用现有基础设施,尽可能减少对现有基础设施的排他性和侵入性
* 不提供全家桶
* 满足离线需求,提供接口满足离线计算,做大一统平台
* 无论多大规模,尽可能的易维护
* 对业务而言改动小,易接入
* 使用者心智负担低

在芒果 TV 的时候,我们全自动化无人管理过上千容器的单一 Redis 集群,而这种集群还有另外几个。在 ENJOY 的时候整个公司的看得到的看不到的甚至开发机都由我们驱动。不能说我们做得多好吧,毕竟这几年在互联网荒漠的长沙全职在做的除我和不愿意透露姓名的 tonicbupt 以外只有在 ENJOY 期间的 timfeirg,dante 和 wrfly 了。再能1个打10个,多少资源干多少活,我们只是想给这个浮躁的技术圈增加那么一点新的可能性。

原文链接:https://zhuanlan.zhihu.com/p/28961390

Mesos上搭建hadoop遇到的问题

回复

Miss刘 发起了问题 • 1 人关注 • 0 个回复 • 1405 次浏览 • 2018-06-26 11:59 • 来自相关话题

如何在Redhat/Centos上部署marathon bamboo+haproxy开源软件

回复

self_flying 发起了问题 • 2 人关注 • 0 个回复 • 1827 次浏览 • 2017-12-20 15:22 • 来自相关话题

mesos和Kubernetes 你会选择谁?

回复

张夏 回复了问题 • 3 人关注 • 2 个回复 • 2372 次浏览 • 2017-09-19 16:31 • 来自相关话题

向marathon提交发布成功,但实际发布并没有执行

回复

胡椒豆 发起了问题 • 1 人关注 • 0 个回复 • 1996 次浏览 • 2017-08-09 16:16 • 来自相关话题

Marathon如何对Application执行一条命令?

回复

styshoo 回复了问题 • 1 人关注 • 1 个回复 • 2095 次浏览 • 2017-07-15 10:01 • 来自相关话题

marathon 做高可用的时候,多个marathon 在mesos注册的那个framework ID是存在什么地方的?

回复

徐磊 回复了问题 • 2 人关注 • 2 个回复 • 2241 次浏览 • 2017-05-16 16:33 • 来自相关话题

Mesos容器化之后管理Docker这种方案可取吗

回复

wisen 回复了问题 • 2 人关注 • 1 个回复 • 1914 次浏览 • 2017-02-27 20:58 • 来自相关话题

国内容器领域活跃的技术/服务输出公司信息集合?

回复

wisen 回复了问题 • 3 人关注 • 1 个回复 • 2313 次浏览 • 2017-02-18 14:17 • 来自相关话题

实录分享 | Mesos PMC 带你回顾 Mesos 2016

回复

Dataman数人科技 发起了问题 • 2 人关注 • 0 个回复 • 3325 次浏览 • 2017-02-04 18:35 • 来自相关话题

如何通过marathon拉取需要认证的私有镜像仓库

回复

kairu 回复了问题 • 3 人关注 • 2 个回复 • 2698 次浏览 • 2017-01-22 15:08 • 来自相关话题

【腾讯云】#容器团队#高级容器研发#招聘

Shirleyee 发表了文章 • 1 个评论 • 235 次浏览 • 2019-05-24 10:33 • 来自相关话题

高级容器研发工程师 工作职责 负责公有云/私有云中 Kubernetes/Devops 等产品技术方案设计与研发工作;负责 Kubernetes 相关前沿技术规划和调研工作,从技术上保证产品的竞争力;负责与产品及客户沟通,判定需求的合理 ...查看全部
高级容器研发工程师
工作职责
  1. 负责公有云/私有云中 Kubernetes/Devops 等产品技术方案设计与研发工作;
  2. 负责 Kubernetes 相关前沿技术规划和调研工作,从技术上保证产品的竞争力;
  3. 负责与产品及客户沟通,判定需求的合理性,找出最合适的方式解决客户问题。
工作要求
  1. 3 年以上后端开发经验,Coding、Debug 能力强, 有丰富的架构设计经验;
  2. 熟悉 C/C++/Go/Java/Python/Ruby 等至少二种编程语言;
  3. 熟悉 Docker/Kubernetes/Swarm/Mesos 等技术;
  4. 熟悉 Jenkins/ELK/Prometheus 等技术优先;
  5. 熟悉 AWS/Google Cloud 等云计算厂商产品优先。


有意请戳:
Wechat:13723737494
Email:Shirleyeee@foxmail.com

集群调度系统的演进

JetLee 发表了文章 • 0 个评论 • 836 次浏览 • 2019-04-03 13:01 • 来自相关话题

Kubernetes 已经成为容器编排领域的事实标准,将来所有应用都会在 Kubernetes 上开发和运行,这个系列文章的目的是深入浅出的介绍 Kubernetes 底层实现的原理。 Kubernetes 是一个集群调度系统,今 ...查看全部
Kubernetes 已经成为容器编排领域的事实标准,将来所有应用都会在 Kubernetes 上开发和运行,这个系列文章的目的是深入浅出的介绍 Kubernetes 底层实现的原理。

Kubernetes 是一个集群调度系统,今天这篇文章主要是介绍 Kubernetes 之前一些集群调度系统的架构,通过梳理他们的设计思路和架构特点,我们能够学习到集群调度系统的架构的演进过程,以及在架构设计时需要考虑的主要问题,对理解 Kubernetes 的架构会非常有帮助。
#基本概念

我们需要先了解集群调度系统里面的一些基本的概念,为了方便大家理解,我通过一个例子来解释这些概念,假设我们要实现一个分布式的定时任务系统(分布式的 Cron),这个系统管理了一组 Linux 主机,用户通过系统提供的的 API / UI 定义定时任务(就类似在 Linux 里面定义 Crontab) ,系统会根据任务的定义,来定时来执行相应的任务,在这个例子里面有如下基本概念:

* 集群(Cluster):这个系统管理的 Linux 主机组成一个资源池,用来运行任务,这个资源池就是集群。
* 作业(Job):就是定义集群如何去执行任务,在例子里面 Crontab 就是一个简单的作业,里面明确的告诉了集群需要在什么时间(时间间隔) ,做什么事情(执行的脚本)。一些作业的定义会复杂很多,比如还会定义一个作业分几个任务做完,以及任务之间的依赖关系,还包括每一个任务对资源的需求。
* 任务(Task):作业需要被调度成具体的执行任务,如果我们定义了一个作业是每天晚上凌晨 1 点执行一个脚本,那么在每天凌晨 1点被执行的这个脚本进程就是任务。

在设计集群调度系统的时候,这个调度系统的核心任务也就是 2 个:

* 任务调度。作业提交给集群调度系统之后,需要对提交的作业拆分成具体的执行任务,并且跟踪和监控任务的执行结果。在分布式 Cron 的例子中,调度系统需要按照作业的要求定时启动进程,如果进程执行失败,需要重试等,一些复杂的场景,比如 Hadoop 的 Map Reduce ,调度系统需要把 Map Reduce 任务拆分成相应的多个 Map 和 Reduce 任务,并且最终拿到任务执行结果的数据。
* 资源调度:本质上是对任务和资源做匹配,根据集群中主机的资源使用情况,分配合适的资源来运行任务。和操作系统的进程调度算法比较类似,资源调度的主要目标是,在固定的资源供给的情况下,尽可能提高资源使用率,减少任务等待的时间(任务等待资源去执行的时间),减少任务运行的延迟或者响应时间(如果是批量任务的话,就是任务从开始执行到结束的时间,如果在线响应式任务的话,比如 Web 应用,就是每一次响应请求的时间),尽可能公平(资源公平的被分配到所有任务)的同时,还需要考虑任务的优先级。这些目标里面有一些是有冲突的,需要平衡,比如资源利用率和响应时间,公平和优先级。

#Hadoop MRv1

Map Reduce 是一种并行计算模型,Hadoop 是可以运行这种并行计算的集群管理平台,其中 MRv1 是 Hadoop 平台的 Map Reduce 任务调度引擎的第一代版本,简单来说,用户定义了 一个 Map Reduce 计算,提交给 Hadoop 之后,由 MRv1 负责在集群上调度和执行这个作业,并且返回计算结果。 MRv1 的架构看起来是这样的:
1.png

架构还是比较简单的,标准的 Master/Slave 的架构,有 2 个核心组件:

* Job Tracker 是集群主要的管理组件,同时承担了资源调度和任务调度的责任。
* Task Tracker 运行在集群的每一台机器上,负责在主机上运行具体的任务,并且汇报状态。

随着 Hadoop 的流行和各种需求的增加,MRv1 有如下问题需要改进:

  1. 性能有一定瓶颈:支持管理的最大节点数是 5千个节点,支持运行的任务最大数量 4万,还有一定的提高空间。
  2. 不够灵活,无法扩展支持其他任务类型。Hadoop 生态里面除了 Map Reduce 类型任务,还有其他很多任务类型需要调度,比如 Spark,Hive,HBase,Storm,Oozie 等,所以需要一个更加通用的调度系统,能够支持和扩展更多的任务类型。
  3. 资源利用率比较低。MRv1 给每个节点静态配置了固定数目的 Slot ,每个 Slot 也只能够运行的特定的任务的类型(Map or Reduce),这就导致资源利用率的问题,比如大量 Map 任务在排队等待空闲资源,但实际上机器有大量 Reduce 的 Slot 被闲置。
  4. 多租户和多版本的问题。比如不同部门在同一个集群里面运行任务,但是彼此是逻辑上隔离的,或者在同一个集群里面运行不同版本的 Hadoop。

#YARN

YARN(Yet Another Resource Negotiator)是 Hadoop 的第二代调度系统,主要目的就是为了解决 MRv1 中的各种问题。YARN 的架构看起来是这样的:
2.png

YARN 简单的理解就是,相对于 MRv1 的主要改进就是,把原来的 JobTrack 的职责,拆分给两个不同的组件来完成:Resource Manager 和 Application Master:

* Resource Manager:承担资源调度的职责,管理所有资源,将资源分配给不同类型的任务,并且通过“可插拔”的架构来很容易的扩展资源调度算法。
* Application Master:承担任务调度的职责,每一个作业(在 YARN 里面叫做 Application)都会启动一个对应的 Application Master,它来负责把作业拆分成具体的任务、向 Resource Manager 申请资源、启动任务、跟踪任务的状态并且汇报结果。

我们看看这种架构改变是如何解决 MRv1 的各种问题的:

* 将原来的 Job Tracker 的任务调度职责拆分出来,大幅度提高了性能。原来的 Job Tracker 的任务调度的职责拆分出来由 Application Master 承担,并且 Application Master 是分布式的,每一个实例只处理一个作业的请求,将原来能够支撑的集群节点最大数量,从原来的5千节点提升到1万节点。
* 任务调度的组件,Application Master,和资源调度解耦,而且是根据作业的请求而动态创建的,一个 Application Master 实例只负责一个作业的调度,也就更加容易支持不同类型的作业。
* 引入了容器隔离技术,每一个任务都是在一个隔离的容器里面运行,根据任务对资源的需求来动态分配资源,大幅提高了资源利用率。不过有一个缺点是,YARN 的资源管理和分配,只有内存一个维度。

#Mesos 的架构

YARN 的设计目标依然是服务于 Hadoop 生态的调度,Mesos 的目标更近一步,被设计成一个通用的调度系统,能够管理整个数据中心的作业,看的出来 Mesos 的架构设计很多借鉴了 YARN,将作业调度和资源调度分别由不同的模块承担,不过 Mesos 和 YARN 很大不同的地方是对资源的调度方式,设计了一个叫非常独特的 Resource Offer 的机制,进一步释放了资源调度的压力,增加了作业调度的扩展性。
3.png

Mesos 的主要组件是:

* Mesos Master ,单纯是承担资源分配和管理的组件,的对应到 YARN 里面就是那个 Resource Manager,不过工作方式会稍微有些不太一样,后面会讲到。
* Framework,承担作业调度,不同的作业类型都会有一个对应的 Framework,比如负责 Spark 作业的 Spark Framework。

##Mesos 的 Resource Offer

看起来 Mesos 和 YARN 架构非常类似,不过实际上在资源管理的方面, Mesos 的 Master 有非常独特(甚至有些奇怪)的 Resource Offer 机制:

* YARN 中 Resource Manager 提供资源的方式是被动的,当资源的消费者(Application Master) 需要资源的时候,会调用 Resource Manager 的接口来获取到资源,Resource Manager 只是被动的响应 Application Master 的需求。
* Mesos 的 Master 提供资源的方式是主动的。Mesos 中的 Master 会定期的主动推送当前的所有可用的资源(就是所谓的 Resource Offer,后面统一都叫 Offer)给 Framework,Framework 如果有任务需要被执行,不能主动申请资源,只有当接收到 Offer 的时候,从 Offer 里面挑选满足要求的资源来接受(在 Mesos 里面这个动作叫做 Accept),剩余的 Offer 就都拒绝掉(这个动作叫做 Reject),如果这一轮 Offer 里面没有足够能够满足要求的资源,只能等待下一轮 Master 提供 Offer。

相信大家看到这个主动的 Offer 机制的时候,会和我有同样的感觉,就是效率比较低,会产生如下问题:

* 任何一个 Framework 的决策效率会影响整体的效率。为了一致性,Master 一次只能给一个 Framework 提供 Offer,等待这个 Framework 挑选完 Offer 之后,再把剩余的提供给下一个 Framework,这样的话,任何一个 Framework 做决策的效率就会影响整体的效率;
* “浪费”很多时间在不需要资源的 Framework 上。 Mesos 并不知道哪个 Framework 需要资源,所以会出现有资源需求的 Framework 在排队等待 Offer,但是没有资源需求的 Framework 却频繁收到 Offer 的情况。

针对上面的问题,Mesos 提供了一些机制来做一定程度的缓解,比如给 Framework 设置一个做决策的超时时间,或者允许 Framework 可以通过设置成 Suppress 状态来表示不需要接受 Offer等,因为不是本次讨论的重点,所以细节就不展开了。

实际上,Mesos 采用这种主动 Offer 的机制,也是有一些明显的优点的:

* 性能明显提高。根据模拟测试一个集群最大可以支撑 10 万个节点,Twitter 的生产环境最大集群支撑 8 万个节点,主要原因是 Mesos Master主动 Offer 的机制,进一步简化了 Mesos Master 的工作职责,Mesos 中将资源调度的过程(资源 —> 任务的匹配)分成了 2 个阶段:资源 —> Offer —> 任务 。Mesos Master 只负责完成第一个阶段,第二个阶段的匹配交给 Framework 来完成。
* 更加灵活,能够满足更加负责的任务调度的策略。举个例子,All Or Nothings 的资源使用策略。

##Mesos 的调度算法 DRF(Dominant Resource Fairness)

关于 DRF 算法,其实对我们理解 Mesos 架构并没有什么关系,但是在 Mesos 中却非常核心和重要,所以多啰嗦几句。

上面说了,Mesos 是轮流给 Framework 提供 Offer 的,那么每次该挑选哪个 Framework 提供 Offer 呢?这就是 DRF 算法要解决核心的问题, 基本原则就是要兼顾公平和效率,在经量满足所有 Framework 对资源需求的同时,也要应该尽可能公平,避免某一个 Framework 占用太多资源而把其他 Framework 给“饿死”。

DRF 是 min-max fairness 算法的一个变形,简单来说就是每次都挑选支配资源占用率(Dominant Resource Usage)最低的那个 Framework 提供 Offer。如何计算 Framework 的“支配资源占用率”呢?就是从 Framework 占用的所有资源类型里面,挑选资源占用率最小的那个资源类型最为支配资源(Dominant Resource),它的资源占用率就是这个 Framework 的支配资源占用率( Dominant Resource Usage),举个例子,一个 Framework X 的 CPU 占用了整体资源的 20%,内存是 30%,磁盘是 10%,那么这个 Framework 的支配资源占用率就是 10%,官方术语把磁盘叫做支配资源, 这个 10% 叫做支配资源占用率。

DRF 的最终目的是把资源平均的分配给所有 Framework,如果一个 Framework X 在这一轮 Offer 中接受(Accept Offer)了过多的资源,那么就要等更长的时间才能获得下一轮 Offer 的机会。不过仔细的读者会发现,这个算法里面有一个假设,就是 Framework 接受了资源之后,会很快释放掉,否则就会有 2 个后果:

  1. 其他 Framework 被“饿死“。某个 Framework A 一次性的接受了集群中大部分资源,并且任务一直运行不退出,这样大部分资源就被 Framework A 一直霸占了,其他 Framework 就没法获得资源了。
  2. 自己被饿死。因为这个 Framework 的支配资源占用率一直很高,所以长期无法获得 Offer 的机会,也就没法运行更多的任务。

所以实际上,Mesos 只适合调度短任务,Mesos 在设计之初就是为数据中心中的段任务而设计的。
#总结一下

从大的架构上,所有调度系统的架构都是 Master / Slave 的架构,Slave 端安装在每一台需要管理的机器上,用来收集主机信息,在主机上执行任务。Master 主要负责做资源调度和任务调度,资源调度对性能要求比较高,任务调度对可扩展性要求较高,总体趋势是讲这两类职责解耦,分别由不同的组件来完成。
4.png


原文链接:集群调度系统的演进(作者:邵明岐)

Makisu:Uber开源的快速Docker镜像生成工具

hokingyang 发表了文章 • 0 个评论 • 1785 次浏览 • 2018-12-16 15:59 • 来自相关话题

为了保证业务平稳发展,我们引入了一种使得工程师们可以动态高效快速部署上千台服务的微服务架构,这种服务大大提高了我们平台上的乘客司机的使用体验。 尽管这种模式支撑了我们快速增长的应用环境,但是由于业务规模太大也带来了痛点。为了容易维护和 ...查看全部
为了保证业务平稳发展,我们引入了一种使得工程师们可以动态高效快速部署上千台服务的微服务架构,这种服务大大提高了我们平台上的乘客司机的使用体验。

尽管这种模式支撑了我们快速增长的应用环境,但是由于业务规模太大也带来了痛点。为了容易维护和升级微服务,2015年采用了Docker技术,确保资源和服务被打包成一个单元。

随着Docker的发展,核心架构团队开发了一套快速高效为Apache Mesos和基于Kubernetes的容器生态产生Dockerfiles配置文件并将应用代码打包在Docker image中的技术。考虑到微服务技术的快速发展,我们开源了核心模块,Makisu,以便其它用户能够收到同样的效果。
# Uber的Docker之路
2015年早期,我们在裸服务器上部署了大约400个服务,他们共享主机上的依赖包和配置文件,仅有很少资源限制。随着工程师规模扩大,依赖管理和资源隔离成为一个问题。为了解决这个问题,核心架构团队开始将服务移植到Docker中,随之建立了标准化和流程化的容器创建流程自动化机制。

新容器化运行环境在服务生命周期管理的运行速度和可靠性方面带来很大提高。然而,访问服务依赖的密钥被打包进image,带来了潜在的安全隐患。简单说,一旦一个文件被放入Docker image中,就会永久存在。尽管可以通过其他这种手段隐藏这些密钥,但是Docker并不提供真正将他们从image中移除的功能。

其中一个解决方案是docker-squash,一个删除Docker image中间步骤所需文件的开源工具,但是带来的问题就是创建image的时间翻倍,这个问题基本抵消了采用微服务架构带来的好处。

为了解决这个问题,我们决定分叉Docker自研我们需要的功能。如果在创建image时候,把所需的密钥以volume方式挂载,这样最终的Docker image中就不留任何密钥的痕迹。因为没有额外延迟,而且代码更改也很少,因此这方法很有效。架构团队和服务团队都满意了,容器架构被更好地利用起来。
# 大规模编译容器image
到了2017年,这种架构不再能满足需求。随着Uber的增长,平台规模也同样受到很大挑战。每次创建超过3000个服务,每天有若干次,大大增加了消耗时间。有些需要2个小时,大小超过10GB,消耗大量存储空间和带宽,严重影响开发者生产率。

此时,我们认识到创建可以扩展的容器image是很重要的。为此提出了三个需求:无特殊权限创建,支持分布式cache,image大小优化。
## 无特殊权限创建
2017年,核心架构团队开始将Uber的计算负载迁移到提供自动化、可扩展和更加弹性化的统一平台上。随之而来,Dockerfile也需要能够运行在共享集群上的容器中。

不幸的是,Docker创建逻辑依赖于一种通过对比创建时间来决定不同层次之间不同的copy-on-write文件系统。这个逻辑需要特权挂载或者卸载容器内部的目录,以便给新系统提供安全机制。也就意味着,Docker无法做到无root权限创建。
## 支持分布式缓存(cache)
通过分层缓存(cache)技术,用户可以复用之前的创建版本和层级,可以减少执行时候的冗余。Docker为每个创建提供分布式缓存,但是并不支持不同分支和服务。需要依靠Docker本地缓存层,但是因为集群内的生成新版本要求不断清空缓存,造成缓存命中率大大降低。

过去,Uber采用指定机器创建指定服务的方式提高命中率,然而,这种方法对于多种服务构成的系统来说显然是不够的。考虑到我们每天会使用上千种服务,这个过程也增加了调度复杂性。

显然一个好的缓存策略对我们的方案更加重要,最终分布式缓存方案既可以解决性能问题,也能够解决创建系统时的调度问题。
## 优化image大小
小images节省空间,并且可以节省转换、压缩和启动时间。

为了优化image大小,我们计划采用多阶段步骤。在众多方案中并不很特别:通过中间态image,将运行时所需文件拷入瘦身的最终image。尽管需要比较复杂的Dockerfiles,但可以减小image大小,因此可以很好地弹性部署。

另外,通过减少image中的层数也可以减少image大小,image比较大有可能是某些文件被中间层创建,删除或者更新的结果。如前所述,即使后续步骤删除了临时文件,但是在开始层中仍然存在,占据相应空间。减少层数可以大大减少删除或更新的文件在之前层中依然存在的可能性,因此可以减小image大小。
# 介绍Makisu
为了实现以上想法,我们开发了自己的image工具,Makisu,实现更加动态,更快容器创建,更加弹性等功能。其特点包括:

* 不需要特殊权限,开发过程更加容易移植;
* 开发集群内部使用分布式层间缓存提高性能;
* 提供灵活层间管理,减少images中不必要文件;
* 与容器Docker兼容;支持标准和多阶段开发命令。

下面详细介绍这些特性。
## 不需要特殊权限
与其它虚机相比Docker image更加轻量是因为中间层只包括运行开发步骤前后文件系统的差别。Docker计算差别,并使用需要特权的CoW文件系统生成中间层。

为了实现不需要特权生成中间层,Makisu在内存中进行文件系统扫描。运行开发步骤后,在此扫描文件系统,更新内存视图,将变化文件添加到新一层。

Makisu也对压缩速度进行了优化,这对弹性部署非常重要。Docker使用Go中默认gzip库压缩层级,当遇到带有大量text文件的image层来说性能很慢。文件扫描阶段后,即使没有缓存,Makisu在很多方面比Docker要快,其中P90开发时间将近节省50%。
## 分布式缓存
Makisu用key-value数据库映射Dockerfiles中操作行到存放在Docker镜像仓库中的层数。key-value数据库可以用Redis或者文件系统。Makisu也用缓存TTL确保缓存内容不会存放太久。

缓存key用当前开发命令和前一条命令的key一起生成。缓存值是生成层内容的哈希值,也用来定位当前层在Docker镜像仓库中的位置。

在Dockerfile的初始化阶段,层生成并且异步推到Docker镜像仓库和key-value库中。后续同样步骤可以从缓存层中获取并解压获取,避免冗余操作。
## 灵活层间操作
为开发过程对iamge层进行控制,Makisu映入了新的操作注释:#!COMMIT,指代Dockerfile中可以生成新层的行。这一简单机制对减少容器image大小很关键( 后续操作要删除或者更新文件 ),解决了密钥跨层存取的问题。每个commit层在分布式缓存中得以体现,集群中其它开发者也可以使用这一更新结果。

以下是一个Dockerfile的实例,其中使用了Makisu的操作注释:
FROM debian:8 AS build_phase
RUN apt-get install wget #!COMMIT
RUN apt-get install go1.10 #!COMMIT
COPY git-repo git-repo
RUN cd git-repo && make

FROM debian:8 AS run_phase
RUN apt-get install wget #!COMMIT
LABEL service-name=test
COPY –from=build_phase git-repo/binary /binary
ENTRYPOINT /binary

本例中,安装了运行时需求包(wget和go1.10),并在相应层内commit,后续创建服务代码。当这些committed层创建后,在分布式缓存中得以更新,其它开发这可以使用,大大提高了开发工作冗余操作的速度。

第二阶段,开发再次安装wget,这次Makisu重用了之前生成的代码。最后,服务代码从开发阶段拷贝到最终image,并生成最终image。这一示例生成一个瘦身的最终image,具体结构如图一所示:
image1.png

图一 Docker为每一步启动一个新容器并生成三层,Makisu在一个容器中编排所有步骤并跳过不必要的层生成
## Docker兼容
Docker image一般是由一些明文按顺序展开的tar文件和两个配置文件构成,Makisu生成的image跟Docker Daemon和镜像仓库完全兼容。

Makisu也支持多阶段开发,通过#!COMMIT的引入,可以实现不必要步骤跳过,并节省空间。

另外,因为#!COMMIT格式化为注释,Makisu使用的Dockerfiles可以被Docker完全兼容。
# 如何使用Makisu
如果想使用Makisu,用户可以直接下载二进制代码,并且不带RUN地运行简单Dockerfiles。用户可以下载Makisu,运行在Docker容器内部,或者作为Kubernetes/Apache Mesos持续集成的工作流。

- 本地使用Makisu二进制代码
- 本地使用Makisu image
- 作为Kubernetes工作流运行Makisu

原文链接:Introducing Makisu: Uber’s Fast, Reliable Docker Image Builder for Apache Mesos and Kubernetes(翻译:杨峰)

DockOne微信分享(一八一):小米弹性调度平台Ocean

李颖杰 发表了文章 • 0 个评论 • 2402 次浏览 • 2018-07-20 23:50 • 来自相关话题

小米弹性调度平台在公司内的项目名称为Ocean(以下简称Ocean)。 Ocean目前覆盖了公司各种场景的无状态服务,同时对于一些基础服务组件,比如:MySQL、Redis、Memcache、Grafana等等抽象为了PaaS平台 ...查看全部
小米弹性调度平台在公司内的项目名称为Ocean(以下简称Ocean)。

Ocean目前覆盖了公司各种场景的无状态服务,同时对于一些基础服务组件,比如:MySQL、Redis、Memcache、Grafana等等抽象为了PaaS平台Ocean的服务组件。

Ocean平台作为小米公司级PaaS平台,目前正在做的事情和后续的一些规划,这里简单列几个:CI/CD、故障注入、故障自愈、容量测试等等。

目前Ocean平台已支持IDC和多云环境,此次分享只介绍IDC内的实践。

Ocean平台因启动的比较早,当时Kubernetes还没有release版本,所以早起的选型是Marathon + Mesos的架构,此次的分享底层也是Marathon + Mesos架构(目前已在做Marathon + Mesos/Kubernetes双引擎支持,本次分享不涉及Kubernetes底层引擎相关内容)。

先分享一张Ocean平台的整体架构图:
1.png

关于容器的存储、日志收集、其他PaaS组件(RDS、Redis等等)、动态授权、服务发现等等本次分享不做介绍。
#容器网络的前世今生

做容器或者说弹性调度平台,网络是一个避不开的话题,小米在做弹性调度的时候网络有以下几方面的考虑:

1. 要有独立、真实的内网IP,便于识别和定位,无缝对接现有的基础设施;
2. 要与现有的物理机网络打通;
3. 要能保证最小化的网络性能损耗(这一点基本上使我们放弃了overlay的网络方式);

因小米弹性调度平台启动的很早,而早期容器网络开源方案还不是很成熟,还不具备大规模在生产环境中使用的条件。所以综合考虑,我们选择了DHCP的方案。

DHCP方案的实现:

1. 网络组规划好网段;
2. 划分专属Ocean的vlan,并做tag;
3. 搭建DHCP server,配置规划好的网段;
4. 容器内启动DHCP client,获取IP地址。
5. 物理机上配置虚拟网卡,比如eth0.100,注:这个100就是vlan ID,和tag做关联的,用于区分网络流量。

此方案中有几个细节需要注意:

1. DHCP server需要做高可用:我们采用了 ospf+vip的方式;
2. 启动的容器需要给重启网卡的能力,以获取IP地址,即启动容器时需要增加NET_ADMIN能力;
3. 需要配置arp_ignore,关闭arp响应,net.ipv4.conf.docker0.arp_ignore=8。

DHCP网络模式,在Ocean平台运行了很长一段时间。

DHCP网络从性能上、独立IP、物理网络互通等方面都已满足需求。既然DHCP已满足需求,那么我们后来为什么更换了网络模型。

因为DHCP的方式有几个问题:

1. IP地址不好管理,我们需要再做个旁路对IP地址的使用情况做监控,这就增加了Ocean同学维护成本;
2. 每次资源扩容需要网络组同学帮我们手动规划和划分网段,也增加了网络同学的管理成本。

针对以上2个痛点,我们重新对网络进行了选型。重新选型时社区用的比较多的是Calico和Flannel。那我们最后为什么选择了Flannel?还是基于:要有独立IP、和现有物理网络互通、最小化网络性能损耗这3点来考虑的。

Calico在这3点都能满足,但是侵入性和复杂度比较大:

1. Calico的路由数目与容器数目相同,非常容易超过路由器、三层交换、甚至节点的处理能力,从而限制了整个网络的扩张。
2. Calico的每个节点上会设置大量的iptables规则、路由,对于运维和排查问题难道加大。
3. 和现有物理网络互联,每个物理机也需要安装Felix。

而Flannel + hostgw方式对于我们现有的网络结构改动最小,成本最低,也满足我们选型需求,同时也能为我们多云环境提供统一的网络方案,因此我们最终选择了Flannel+hostgw方式。

下面简单介绍下Ocean在Flannel+hostgw上的实践。

1. Ocean和网络组协商,规划了一个Ocean专用的大网段;
2. 网络组同学为Ocean平台提供了动态路由添加、删除的接口,即提供了路由、三层交换简单OpenAPI能力;
3. Ocean平台规范每台宿主机的网段(主要是根据宿主机配置,看一台宿主机上启动多少实例,根据这个规划子网掩码位数);
4. 每台容器宿主机上启动Flanneld,Flanneld从etcd拿宿主机的子网网段信息,并调用网络组提供的动态路由接口添加路由信息(下线宿主机删除路由信息);
5. Dockerd用Flanneld拿到的网段信息启动Docker daemon。
6. 容器启动是根据bip自动分配IP。

这样容器的每个IP就分配好了。容器的入网和出网流量,都依赖于宿主机的主机路由,所以没有overlay额外封包解包的相关网络消耗,只有docker0网桥层的转发损耗,再可接受范围内。

以上为小米ocean平台改造后的网络情况。

网络相关的实践,我们简单介绍到这里,下面介绍发布流。
#发布流

对于一个服务或者任务(以下统称job)的发布流程,涉及如下几个方面:

1. 需要创建要发布job的相关信息。
2. 基于基础镜像制作相关job的部署镜像。
3. 调用Marathon做job部署。
4. job启动后对接小米运维平台体系。
5. 健康检查

发布流程的统一管理系统(以下统称deploy)做发布流整个Pipeline的管理、底层各个组件的调用、维护了各个stage的状态。

下面针对这几点展开详细介绍下:

job的相关信息:job我们可以理解为业务需要部署的项目模板,是Ocean平台发布的最小粒度单元。因其为业务项目模板,所以需要填写的信息都是和业务项目相关的内容,需要填写job名称、选择集群(在哪个机房部署)、给定产品库地址(业务代码的Git或SVN地址)、选择容器模板(启动的容器需要多大的资源,比如1CPU 2G内存 100G磁盘等)、选择基础镜像版本(比如CentOS:7.3,Ubuntu:16.04等)、选择依赖的组件(比如JDK、Resin、Nginx、Golang、PHP等等业务需要根据自己的代码语言和环境需求选择)、填写启动命令(服务如何启动)、监听端口(服务监听的端口是多少,该端口有几个作用:1. 提供服务;2. 健康检查;3. 创建ELB关联;4. 会和job名字一起上报到zk,便于一些还没有服务发现的新项目平滑使用Ocean平台提供的服务发现机制)。

以上是最基本的job信息,还有一些其他的个性化设置,比如环境变量、共享内存、是否关联数据库等等,这里不展开介绍了。

制作job镜像:上面的job信息创建好后,便可以进入真正的发布流程了。发布的时候会根据用户设置的job信息、基于Ocean提供的基础镜像来制作job镜像。这里面主要有2个流程,一个是docker build 制作镜像,一个是业务代码的编译、打包。

Docker build 基于上面填写的job信息解析成的Dockerfile进行。我们为什么不直接提供Dockerfile的支持,而做了一层页面的封装:

* 对于开发接入成本比较高,需要单独了解Dockerfile文件格式和规范。
* 开发人员越多,写错Dockerfile的几率越大,对于Ocean同学来说排错的成本就会越高。
* 此封装可以规范Dockerfile,业务只需要关心和job相关的最基本信息即可,不需要了解Dockerfile具体长什么样子。

Docker build会在镜像里拿业务代码,然后进行业务代码的编译、打包;关于业务编译、打包Ocean内做了一些针对原部署系统(服务部署到物理机)的兼容处理,可以使业务直接或很少改动的进行迁移,大大降低了迁移的成本。

job镜像build成功后,会push到Ocean私有的Registry。

调用marathon做job部署:镜像build成功后,deploy会调用Marathon的接口,做job的部署动作(底层Marathon + Mesos之间调度这里也不展开讲,主要说下我们的Ocean上做的事情)。

job部署分2种情况:

* 新job的部署:这个比较简单,deploy直接调用Marathon创建新的job即可。
* job版本更新:更新我们需要考虑一个问题,如何使job在更新过程中暂停,即支持版本滚动更新和业务上的灰度策略。

Marathon原生是不支持滚动更新的,所以我们采用了一个折中的办法。
在做job更新的时候,不做job的更新,是创建一个新的job,除版本号外新job名字和旧job名字相同,然后做旧job缩减操作,新job扩容操作,这个流程在deploy上就比较好控制了。

更新期间第一个新job启动成功后默认暂停,便于业务做灰度和相关的回归测试等。

对接运维平台体系:基础镜像内打包了docker init,容器在启动的时候docker init作为1号进程启动,然后我们在docker init中做了和目前运维平台体系打通的事情,以及容器内一些初始化相关的事情。

包括将job关联到业务的产品线下、启动监控Agent、日志收集、对接数据流平台、注册/删除ELB、启动日志试试返回给deploy等等。

健康检查:我们做健康检查的时候偷了些懒,是基于超时机制做的。
job编译成功后,deploy调用Marathon开始部署job,此时Marathon便开始对job做健康检查,再设置的超时时间(这个超时时间是可配置的,在job信息内配置)内一直做健康检查,直到健康检查成功,便认为job发布成功。发布成功后,整个发布流结束。
#弹性ELB

job部署成功后,就是接入流量了。在Ocean平台流量入口被封装为了ELB基础服务。

在ELB模块入口创建ELB:选择集群(即入口机房,需要根据job部署的机房进行选择,为了规范化禁止了elb、job之间的夸机房选择);选择内、外网(该服务是直接对外提供服务,还是对内网提供服务);填写监听端口(job对外暴露的端口);选择调度算法(比如权重轮询、hash等);选择线路(如果是对外提供服务,是选择BGP、还是单线等)。

ELB创建好后,会提供一个ELB的中间域名,然后业务域名就可以cname到这个中间域名,对外提供服务了。

大家可以看到,ELB的创建是直接和job名字关联的,那么job目前的容器实例、之后自动扩缩的容器实例都是怎么关联到ELB下的呢?

这里也分2种情况:

1. job已经启动,然后绑定ELB:这种情况下,我们做了一个旁路服务,
已轮询的方式从Marathon获取实例信息,和创建的ELB后端信息进行比较,并以Marathon的信息为准,更新ELB的后端。
2. 绑定ELB后,job扩缩:上面在发布流中提到,docker init会做ELB的注册、删除动作。

job在扩容的时候会在docker init初始化中将job注册到ELB后端;job在缩容的时候会接收终止信息,在接收终止信号后,docker init做回收处理,然后job实例退出。在回收处理的过程中会操作该实例从ELB摘除。

到此ELB的基本流程就分享完了,下面说下自动扩缩。
#自动扩缩

自动扩缩目前包括定时扩缩和基于Falcons的动态扩缩。
##定时扩缩

比如一些服务会有明显的固定时间点的高峰和低谷,这个时候定时扩缩就很适合这个场景。

定时扩缩的实践:定时扩缩我们采用了Chronos。

在deploy内封装了Chronos任务下发的接口,实际下发的只是定时回调任务。到任务时间点后触发任务,该任务会回调deploy 发布服务的接口,进行job的扩缩。这里我们为什么没有直接调用Marathon的接口,是因为在deploy中,我们可以自行控制启动的步长、是否添加报警等更多灵活的控制。
##基于Falcon动态扩缩

Falcon是小米内部的监控平台(和开源的Open-Falcon差别并不大,但是Ocean平台job内的Falcon Agent 基于容器做过了些改造)。Ocean平台是基于Falcon做的动态调度。用户自行在Ocean上配置根据什么指标进行动态调度,目前支持CPU、内存、thirft cps。这些metric通过Falcon Agent 上报到Falcon平台。用于做单容器本身的监控和集群聚合监控的基础数据。

然后我们基于聚合监控来做动态扩缩。例如,我们在Ocean平台上配置了基于CPU的扩缩,配置后,deploy会调用Falcon的接口添加集群聚合的监控和回调配置,如果实例平均CPU使用率达到阈值,Falcon会回调deploy做扩缩,扩缩实例的过程和定时扩缩是一样的。
#遇到的一些特例问题

Ocean从启动开始遇到了很多问题,比如早起的Docker版本有bug会导致docker daemon hang住的问题,使用Device Mapper卷空间管理的问题等等。

下面针对本次的分享,简单列5个我们遇到的问题,然后是怎么解决的。

1、ELB更新为什么没有采用Marathon事件的机制,而是使用了旁路服务做轮询?

* 我们发现marathon的事件并不是实时上报,所以这个实时性达不到业务的要求;
* 在我们的环境中也碰到了事件丢失的问题。

所以我们采用了旁路服务轮询的方式。

2、虽然Ocean平台已经做了很多降低迁移成本的工作,但是对于一些新同学或者新业务,总还是会有job部署失败的情况。针对这种情况,我们增加了job的调试模式,可以做到让开发同学在实例里手动启动服务,查看服务是否可以正常启动。

3、ELB的后端数目不符合预期。

主要是由于slave重启导致实例应该飘到其他的机器时,Marathon低版本的bug导致启动的实例数与预期不一致。解决该问题是通过登录到Marathon,通过扩缩实例然后使实例数达到预期,但是这又引进了另外一个问题,ELB的后端存在了残留的IP地址没有被清理,虽然这个因为健康检查而不影响流量,但是暂用了额外的IP资源,所以我们又做了个旁路服务,用于清理这些遗留IP。

4、容器内crontab不生效。业务在容器内使用了crontab,但是在相同的宿主机上,个别容器crontab不生效问题。

我们解决的方式是为启动的容器增加相应的能力,即启动的时候mesos executor增加 AUDIT_CONTROL 选项。

5、容器内看到的Nginx worker进程数没有隔离的问题。

我们在物理机上配置Nginx时通常会将Nginx的worker进程数配置为CPU核心数并且会将每个worker绑定到特定CPU上,这可以有效提升进程的Cache命中率,从而减少内存访问损耗。然后Nginx配置中一般指定worker_processes指令的参数为auto,来自动检测系统的CPU核心数从而启动相应个数的worker进程。在Linux系统上Nginx获取CPU核心数是通过系统调用 sysconf(_SC_NPROCESSORS_ONLN) 来获取的,对于容器来说目前还只是一个轻量级的隔离环境,它并不是一个真正的操作系统,所以容器内也是通过系统调用sysconf(_SC_NPROCESSORS_ONLN)来获取的,这就导致在容器内,使用Nginx如果worker_processes配置为auto,看到的也是宿主机的CPU核心数。

我们解决的方式是:劫持系统调用sysconf,在类Unix系统上可以通过LD_PRELOAD这种机制预先加载个人编写的的动态链接库,在动态链接库中劫持系统调用sysconf并根据cgroup信息动态计算出可用的CPU核心数。
#Q&A

Q:请教下你们ELB用的什么代理软件,HAProxy、Nginx?是否遇到过缩容时出现部分请求失败的问题,有解决方案吗?

A:IDC ELB底层封装的是公司的LVS,LVS管理平台提供了完事的API支持,ELB这边调用LVS管理平台的API进行的相关操作。缩容目前没有遇到流量丢失问题,这个是在docker init内接收信号,然后做的回收处理。

Q:hostgw如何访问外网?
>A:是通过路由出网的,容器的IP是路由上真实存在的IP网段,由网络组提供的API进行的动态配置。

Q:都劫持了,为啥不用 LXCFS?
>A:LXCFS目前仅支持改变容器的CPU视图(/proc/cpuinfo文件内容)并且只有--cpuset-cpus参数可以生效,对于系统调用sysconf(_SC_NPROCESSORS_ONLN)返回的同样还是物理机的CPU核数。另:我们采用的劫持方案已开源,欢迎围观:https://github.com/agile6v/container_cpu_detection

以上内容根据2018年7月17日晚微信群分享内容整理。分享人赵云,小米云平台运维部SRE,负责小米有品产品线运维工作。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

DockOne微信分享(一八十):Hulu大规模容器调度系统Capos

Andy_Lee 发表了文章 • 0 个评论 • 1341 次浏览 • 2018-07-13 15:24 • 来自相关话题

Hulu是美国领先的互联网专业视频服务平台,目前在美国拥有超过2000万付费用户。Hulu总部位于美国洛杉矶,北京办公室是仅次于总部的第二大研发中心,也是从Hulu成立伊始就具有重要战略地位的分支办公室,独立负责播放器开发,搜索和推荐,广告精准投放,大规模用户 ...查看全部
Hulu是美国领先的互联网专业视频服务平台,目前在美国拥有超过2000万付费用户。Hulu总部位于美国洛杉矶,北京办公室是仅次于总部的第二大研发中心,也是从Hulu成立伊始就具有重要战略地位的分支办公室,独立负责播放器开发,搜索和推荐,广告精准投放,大规模用户数据处理,视频内容基因分析,人脸识别,视频编解码等核心项目。

在视频领域我们有大量的视频转码任务;在广告领域当我们需要验证一个投放算法的效果时,我们需要为每种新的算法运行一个模拟的广告系统来产出投放效果对比验证;在AI领域我们需要对视频提取帧,利用一些训练框架产出模型用于线上服务。这一切都需要运行在一个计算平台上,Capos是Hulu内部的一个大规模分布式任务调度和运行平台。

Capos是一个容器运行平台,包含镜像构建,任务提交管理,任务调度运行,日志收集查看,Metrics收集,监控报警,垃圾清理各个组件。整个平台包含的各个模块,如下图所示:
1.png

用户可以在界面上创建镜像描述符,绑定GitHub的repo,生成镜像。之后在界面上创建作业描述符,填上镜像地址,启动参数,资源需求,选择资源池,就可以运行作业,看作业运行日志等。这些所有操作也可以通过REST API来调用,对于一些高级的需求,Capos提供Golang和Python的SDK,可以让用户申请资源,然后启动作业,广告系统就是利用SDK,在Capos上面申请多个资源,灵活的控制这些资源的生命周期,一键启动一个分布式的广告系统来做模拟测试。

Capos大部分组件都是用Golang实现的,Capos的核心组件,任务调度运行CapScheduler是今天主要和大家分享和探讨的模块。CapScheduler是一个基于Mesos的Scheduler,负责任务的接收,元数据的管理,任务调度。CapExecutor是Mesos的一个customized executor,实现Pod-like的逻辑,以及pure container resource的功能,在设计上允许Capos用户利用Capos SDK复用计算资源做自定义调度。

Capos Scheduler的架构图如下所示:
2.png

上图浅蓝色部分是Mesos的组件,包括Mesos master,Mesos agent,Mesos zookeeper。Mesos作用是把所有单体的主机的资源管理起来,抽象成一个CPU、Memory、Port、GPU等的资源池,供之上的Capos scheduler使用。

其中Capos scheduler是一个active-standy的HA模型,在scheduler中我们实现了一个raft based的k-v用来存储Metadata,active的scheduler注册成为Mesos之上的一个framework,可以收到资源,根据调度策略来启动作业。

Capbox是一个定制实现的Mesos的executor,作为Mesos agent的资源的占位符,接收请求与Mesos agent上的Docker daemon通信启动容器。其中也实现了POD-like的功能,同时可以启动多个容器共享network,磁盘等。

Capos scheduler提供两类作业运行,一个是简单作业直接在Capbox运行,另一个是复杂带有编程语义的作业,我们称之为AppMaster,其本身运行占用一个CapBox,然后通过编程语义二次申请CapBox运行作业。
首先说明下简单作业运行流程,这里的简单作业,提交的作业通过json描述,可以包含多个Container,然后scheduler收到请求之后,命中某个offer,向Mesos发送offer启动请求,在请求中同时夹带着作业json信息,把作业启动起来,scheduler根据Mesos状态同步信息来控制作业的生命周期。

如果是AppMaster Programmatically二次调度的作业,首先需要把AppMaster启动,这部分和简单作业运行是一致的,然后AppMaster再申请一个到多个资源来启动CapBox,运行作业。此时AppMaster申请的CapBox的生命周期完全由AppMaster决定,所以这里AppMaster可以复用CapBox,或者批量申请CapBox完成自己特定的调度效果。多说一句,AppMaster可以支持client-mode和cluster-mode,client-mode是指AppMaster运行在集群之外,这种情况适用于把AppMaster嵌入在用户原先的程序之中,在某些场景更符合用户的使用习惯。

说完Capos的使用方式后,我们可以聊下在Capos系统中一些设计的思考:

1、Scheduler的调度job和offer match策略,如下图所示:
3.png


  1. 缓存offer。当scheduler从Mesos中获取offer时候,Capos scheduler会把offer放入到cache,offer在TTL后,offer会被launch或者归还给Mesos,这样可以和作业和offer的置放策略解耦。
  2. 插件化的调度策略。Capos scheduler会提供一系列的可插拔的过滤函数和优先级函数,这些优先级函数对offer进行打分,作用于调度策略。用户在提交作业的时候,可以组合过滤函数和优先级函数,来满足不同workload的调度需求。
  3. 延迟调度。当一个作业选定好一个offer后,这个offer不会马上被launch,scheduler会延迟调度,以期在一个offer中match更多作业后,再launch offer。获取更高的作业调度吞吐。

2、Metadata的raft-base key value store

1. 多个scheduler之间需要有一个分布式的kv store,来存储作业的Metadata以及同步作业的状态机。在scheduler downtime切换的时候,新的scheduler可以接管,做一些recovery工作后,继续工作。
2. 基于Raft实现的分布式一致性存储。Raft是目前业界最流行的分布式一致性算法之一,Raft依靠leader和WAL(write ahead log)保证数据一致性,利用Snapshot防止日志无限的增长,目前Raft各种语言均有开源实现,很多新兴的数据库都采用Raft作为其底层一致性算法。Capos利用了etcd提供的raft lib, 实现了分布式的一致性数据存储方案。etcd为了增强lib的通用性,仅实现了Raft的核心算法,网络及磁盘io需要由使用者自行实现。Capos中利用etcd提供的rafthttp包来完成网络io,数据持久化方面利用channel并行化leader的本地数据写入以及follower log同步过程,提高了吞吐率。
3. Capos大部分的模块都是Golang开发,所以目前的实现是基于etcd的raft lib,底层的kv存储可以用BoltDB,Badger和LevelDB。有些经验可以分享下,在调度方面我们应该关注关键路径上的消耗,我们起初有引入StormDB来自动的做一些key-value的index,来加速某些带filter的查询。后来benchmark之后发现,index特别在大规模meta存储之后,性能下降明显,所以目前用的纯kv引擎。在追求高性能调度时候,写会比读更容器达到瓶颈,BoltDB这种b+ tree的实现是对读友好的,所以调度系统中对于kv的选型应该着重考虑想LevelDB这种lsm tree的实现。如果更近一步,在lsm tree基础上,考虑kv分离存储,达到更高的性能,可以考虑用badger。不过最终选型,需要综合考虑,所以我们底层存储目前实现了BoltDB、Badger和LevelDB这三种引擎。

3、编程方式的AppMaster

1. 简单的作业可以直接把json描述通过REST API提交运行,我们这边讨论的是,比较复杂场景的SaaS,可能用户的workload是一种分布式小系统,需要多个Container资源的运行和配合。这样需要Capos提供一种编程方式,申请资源,按照用户需要先后在资源上运行子任务,最终完成复杂作业的运行。
2. 我们提供的编程原语如下:

1. Capbox.go capbox是Capos中资源的描述:
4.png

AppMaster可以用这些API申请资源,释放资源,获取资源的状态更新,在此基础上可以实现灵活的调度。
2. Task.go task也就是可以在Capbox上运行的task,如下图所示:
5.png

在资源基础上,appmaster可以用api启动/停止作业,appmaster也可以复用资源不断的启动新的作业。基于以上的api,我们可以把广告模拟系统,AI框架tensorflow,xgboost等分布式系统运行在Capos之上。

4、Capos对比下Netflix开源的Titus和Kubernetes

1. Netflix在今年开源了容器调度框架Titus,Titus是一个Mesos framework,titus-master是基于fenso lib的Java based scheduler,meta存储在cassandra中。titus-executor是Golang的Mesos customized executor。因为是Netflix的系统,所以和AWS的一些设施是绑定的,基本上在私有云中不太适用。
2. Kubernetes是编排服务方面很出色,在扩展性方面有Operator,Multiple Scheduler,CRI等,把一切可以开放实现的都接口化,是众人拾柴的好思路,但是在大规模调度短作业方面还是有提升空间。
3. Capos是基于Mesos之上的调度,主要focus在大规模集群中达到作业的高吞吐调度运行。

在分布式调度编排领域,有诸多工业界和学术界的作品,比如开源产品Mesos,Kubernetes,YARN,调度算法Flow based的Quincy,Firmament。在long run service,short term workload以及function call需求方面有Service Mesh,微服务,CaaS,FaaS等解决思路,私有云和公有云的百家争鸣的解决方案和角度,整个生态还是很有意思的。绝技源于江湖、将军发于卒伍,希望这次分享可以给大家带来一些启发,最后感谢Capos的individual contributor(字母序):chenyu.zheng、fei.liu、guiyong.wu、huahui.yang、shangyan.zhou、wei.shao。
#Q&A
Q:Capos如何处理健康检查?之前了解到,Mesos内置的健康检查不是特别完善。

A:目前Capos focus的作业大部分都是短作业类型,所以我们目前就是通过容器的退出码来判断success或者fail,如果你说的健康检查是针对服务的,一般实现是支持多种健康检查的方式,bash,http等,然后为了大规模容器运行情况下的可用性,建议这种健康检查的发起client和服务instance是在一台机器上,或者是一个Pod中,发现不健康通过某种机制上报,或者退出Container,但是需要控制Threshold以免整个服务downtime。这样可以探测instance的健康,整个服务的健康,可以在通过外部的一些子系统去check。



Q:关于调度方面,分享中只提到了使用了一系列的可插拔的过滤函数和优先级函数,我想问下能否具体描述下如何被调度的?和yarn里使用的Fair Schedule或者DRF算法的异同有哪些?因为对于多种资源维度的调度是一个很复杂的问题,希望知道Hulu这方面有什么心得和思考?

A:目前实现是,会针对一个请求,首先根据过滤函数比如一些constraints进行offer过滤,然后剩下的offer apply所有的优先级打分函数,进行打分,打分的时候,会根据一个请求和offer的资源,算CPU和mem的比例,选取出dominate的resource进行主要评分,然后选取最优的offer进行bind,bind之后不会马上调度,而是会delay scheduler,这样一般在比较繁忙的情况下,一次offer launch可以启动多个tasks,这是对于大规模吞吐的考虑。 以上这些实现还是queue-base的调度,借鉴了一些Fair Schedule和drf的思路,具体差别你了解了Capos scheduler策略后,应该就会有自己的想法了。多种资源维度,目前我们是根据dominate resource作为主要评分标准的,当然你也可以看下我最后分享提到的一些flow-base的scheduler算法,比如firmament。希望可以回答你的问题。



Q:Capos是否支持,数据中心之间的备份/切换。比如Zone - A的数据中心出现网络故障,把服务迁移到另一个指定的区域 Zone - B(仍然考虑恢复以后优先部署到 Zone - A)。之前考虑是类似一个Mask的机制,如果故障就加一定的Mask值(比如Opcacity)在某个集群上,然后调度的时候去参考这个Mask值,不知道Hulu有没有类似的需求或者考虑过这样的机制?

A:Capos是on Mesos,Mesos是根据zk做选主,而且Capos scheduler中还有一个raft base key value store,所以这些条件,使得Capos是一个datacenter的解决方案。目前Hulu是有多个DataCenter的,所以看架构组件图,你可以看到,我们有一个Capos portal,在这个组件下,是可以选择不同DataCenter去run workload。所以我们目前对于数据中心的备份和切换,主要是依赖Capos portal这个组件,在Gateway的位置做的控制。



Q:想请问下Capos的鉴权是怎么做的,有没有用户权限认证系统?此外,针对每个用户有没有容器资源使用量的限制?

A:可以翻到之前share的架构组件图,我们有一个Capos portal组件,这个组件是提供Restful API和Portal,我们在这边集成Hulu SSO,然后关联Hulu yellowpages(Hulu的服务权限控制系统),做的用户的认证,我们分成自己的Capos APP, team的APP,别的组无法操作不属于自己的Capos APP。对于Quota的管理,我们做了Queue/Label机制,每个服务会建一个标识,然后在标识底下配置总的资源使用量,以及可以用的机器列表(通配符),用这样的机制控制Capos的用户资源使用。



以上内容根据2018年7月10日晚微信群分享内容整理。分享人杨华辉,Hulu senior software developer,目前在Hulu beijing cloud infrastructure组,主要从事分布式容器调度,分布式存储方面的研发。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

Mesos container在360广告系统的应用

尼古拉斯 发表了文章 • 0 个评论 • 1238 次浏览 • 2018-05-12 18:16 • 来自相关话题

【编者的话】本文作者将技术与业务相结合,讲解Mesos与Container的技术架构,面对当前的业务痛点,可以解决哪些问题,并且如何应用到360商业广告系统中。 #背景简介 我是一名SRE工程师,我们负责管理与维护360商业广告平台 ...查看全部
【编者的话】本文作者将技术与业务相结合,讲解Mesos与Container的技术架构,面对当前的业务痛点,可以解决哪些问题,并且如何应用到360商业广告系统中。
#背景简介

我是一名SRE工程师,我们负责管理与维护360商业广告平台,说起SRE工程师大家可能会想到谷歌公司,因为SRE毕竟是谷歌提出的概念。

作为SRE工程师我想说一下我们的自我修养。我们的主要工作是减少琐事,不断的扩大服务规模,同时我们还要保证整个系统的高可靠性和可维护性,不能随着业务规模的不断增大,招揽越来越多的人来维护业务是不合理的。

我们广告通过360搜索或者360手机端的应用进行展示,比如在360搜索输入“鲜花”会有广告展示,每天有数百亿次的投放与展示,手机端主要通过360的手机安全卫士,手机助手等等的一些应用进行广告的投放与展示。
01.jpg

#Why Container?

说一下为什么要使用容器解决我们的问题,还有演讲的主题为什么不写Why Docker?

说到容器大家第一时间会想到Docker,它实现了一个容器引擎(Docker engine)。除了Docker,在容器生态圈还有一些公司他们实现了自己的容器引擎,比如CoreOS的RKT,比如我们使用的Mesos的容器引擎(Mesos containerizer),这些引擎不依赖于Docker本身,可以解决稳定性和扩展性的问题。
##业务痛点

我先不说我们为什么用容器解决这些问题,说一下业务上我们有哪些痛点,并且这些问题可能大家都会碰到。

  1. 数据中心迁移,这个问题大家多数都会遇到,在迁移过程中要把之前的业务熟悉一遍,需要重新部署,测试还会遇到一些环境配置不一致的问题。

  1. 故障恢复,服务器宕机之后,传统业务都部署在物理服务器上,这样也需要重新部署,这样会带来很多麻烦。

  1. 操作系统不一致,现在我们很多不同的操作系统,比如CentOS 5、6、7都在用,迁移的时候很麻烦,还有一些系统内核的Bug需要去解决。

  1. 生产环境配置不一致,生产环境有一些服务器工程师都可以登录,如果改了一些配置导致线上出现问题的情况也是可能发生的。

  1. 测试环境不一致,可能每个人申请一台虚拟机专门做测试,导致测试结果也不一致。

  1. 服务的扩展性较低,传统业务扩容一般需要一台中控机或者有一套部署环境,每一次都需要重新添加一批服务器进行扩容。

  1. 服务器资源利用率问题,使用物理机部署服务,每一天都有服务的高峰低谷,由于采用静态资源划分的方式,资源利用率非常低会给公司造成很多资源上的浪费。

下面我来说一下我们为什么要用Docker来解决我们的问题。

Docker有一个隐喻叫“集装箱”。其实Docker的英文翻译是“码头工人”,这个隐喻给使用者很多暗示,告诉大家快来使用Docker吧,使用Docker就像使用集装箱一样,能够随时随地的,无拘无束的启动你的应用。像Docker官方的口号一样“build、ship、and Run Any APP Anywhere”,Docker为什么可以解决我们遇到的这些业务痛点呢?因为集装箱是有固定的标准,它的大小一致,这样货物在公路、铁路、海洋运输就不用考虑货物的尺寸等问题了,并且依赖大型机械化进行转运,等于是实现了一套标准的运输体系,可以给整个世界带来很大的商业潜力。
##Docker的标准化怎么实现?

正如我上面说到的,Docker的实质化就是标准,Docker的标准化是怎么实现的呢?

首先,Docker有自己标准化的文档管理方式,它的标准化文档方式就是有自己的Dockerfile,可以定义一系列的软件系统版本。

第二点,Docker有对应用的统一操作方法,在物理环境不同的应用有不同的启动方法,如果你用Docker启动程序,可以通过docker run的方式来启动。在服务迁移过程中只要使用docker run命令来启动你的程序就可以了。

第三点,为了维护生产环境的一致性和配置变更的幂等性,Docker创造性的使用了类似Git管理代码的方式对环境镜像进行管理。每次都需要docker pull下载镜像,Docker container本身只有container layer这一层可写,你每次重新部署的时候这一层是会被删掉的,这样可以保证Docker实际环境每次都是幂等的。
##在服务容器化过程中可能遇到的问题

在服务容器化过程当中,我们可能会遇到哪些问题?当大家使用物理机的时候,为了SSH登陆服务器,每台服务器都会开通SSH服务并且添加对应的账号。如果你使用Docker服务还要开通SSH服务的22端口,你需要考虑一下你的服务是否真的需要登录到容器中,或者你容器化的方式是否正确或者它是否适合你的业务。还有一些人这样使用Docker:在容器中开放rsync服务端口,甚至还有在Docker container里面部署puppet agent同步工具,这样做我觉得是完全没有必要的。我们都是不支持SSH或者类似的服务连接到Docker内部的。
2.jpg

如果你不让我登录到物理机上,不让我连到Docker内部,我怎么看我的日志呢?

我们有一套日志系统,后端对接的服务是Elasticsearch,会使用Docker的syslog模块通过UDP的方式写入Graylog里,Graylog或者Grafana都可以进行展示、查询,这样我们就可以及时的发现线上的问题。
3.jpg

##Docker的网络性能

4.jpg

使用了Docker,大家可能会考虑,它的网络性能会怎么样,我们其实也做过一些调研。我们主要用的是Hostonly和Bridge这两种模式,如果用Hostonly基本和直接在物理服务器上运行程序的性能是差不多的,现在我们也有团队专门做Calico服务方面的研究,比如你有一些爬虫服务,可能希望有一些独立的外网IP,可以考虑使用Calico为一个container单独分配外网IP。

或者有网络隔离的需求的话,也可以使用Calico服务。由于我们主要针对是私有云,直接用hostonly模式多一些。
##存储镜像

关于Docker仓库,大家可能会问服务容器化之后,主要用什么仓库存储镜像呢?哪种镜像仓库比较好?之前我们搭建过Docker官方的仓库,只有单节点不是高可用的,数据可靠性也不是非常好,我们是用的无认证模式。

现在我们使用了Harbor,用这个系统做了二次开发,后端存储用的S3存储系统,数据可靠性是非常高的,多机房之间可以进行数据同步,支持用户认证,大家根据自己的用户密码进行登录上传镜像等操作。之后我们还会做一个Docker仓库的CDN化,多机房直接访问CDN服务下载镜像。
5.jpg

##怎样把数据写到本地

大家使用Docker可能会考虑数据怎么写到本地,我们使用Mesos+Docker之后,是不是所有服务都要需要无状态的呢?我们推荐无状态服务运行在Mesos+Docker之上。但是如果你有把日志落到本地的需求,我们现在也是可以支持的。
6.jpg

我列出的这些产品,比如CephFS、MySQL、Kafka、HDFS、Aerospike、Redis都是数据持久化的一种方式,比如流式数据一般用Kafka多一些,数据直接通过Kafka消费出来,通过一些计算模型后再重新写入Kafka,或者如果想数据落到本地的需求直接在Container中挂载CephFS也是可以的。
##服务的注册和发现

关于服务的注册和发现,大家可能会有一些问题。比如我用了Mesos+Docker之后,我们的一些服务是在mesos-slave节点之间飘逸的,有可能因为一台物理机宕机了,你的服务会在另外一台mesos-slave节点上启动,我怎么知道我的服务启动到具体哪台IP或者具体哪台机器上呢?
7.jpg

我们服务发现主要用的是Mesos-DNS还有Marathon,底层数据依赖于ZooKeeper。还有一些公司可能用etcd或者Consul,我们也有在用不过比较少。

关于使用了Docker,服务如何进行调度?还有Docker服务如果对于本地数据有依赖的话需要如何加载?希望大家可以带着问题思考一下,一会儿我会详细说明。
#Why Mesos?

为什么要用Mesos?

当前遇到的一个背景就是在当前互联网环境下,越来越多的分布式计算系统产生。
8.jpg

如果说维护一个大型业务团队需要部署的框架或者分布式系统非常多,但是市面上又没有一种系统能够把所有的应用框架都部署到一个集群里,这样就会导致我之前说的比如资源利用率会很低,可维护性很低。因为不同的集群有不同的配置,所以我们就想把这些多个应用布到一个大型的资源池里,这样可以更好的共享硬件资源。因为我们的服务都是支持动态扩缩容的,这样也可以简化一些部署上的逻辑,并且最大化的利用资源,最终实现服务可调度,数据可以共享。
##使用Mesos的优点


1、资源利用率非常高

因为之前大家用物理服务器的时候,是静态资源划分的方式,这种方式资源浪费得比较多。因为服务每天都有高峰和低谷时段,如果你用Mesos的话,使用了动态服务扩缩容,比如白天广告展示的量会非常大,最高的时候每秒已经超过一百万,但是在晚上访问量非常低,你就可以把这批机器资源释放出来,供一些离线业务运行,比如Hadoop。可以达到最大化的资源利用率。
9.jpg

2、便捷性

Mesos本身支持对所有资源打标签,大家可以打固定的标签。这样在提交资源的时候,可以根据你想要的资源提出申请。比如你想要一个GPU的资源,比如你要1核的我就会分配给你一核的,像乘坐飞机一样,你想坐头等舱只要有资源就可以分配给你,Mesos也是这样,我们支持端口、CPU、内存、硬盘等等的划分。
10.jpg

3、可扩展性非常好

因为它本身的设计原理是两极调度框架,这样带来的好处是它非常的简单。因为Mesos本身只负责资源调度,把任务调度交给了运行在它之上的具体框架进行调度。所以如果你要横向扩展Mesos的话,非常方便。
11.jpg

4、模块化

因为Mesos支持在Mesos API之上定义各种各样的framework,大家可以自由添加framework,我们主要用的Marathon、Flink等官方与自定义framework,具体使用哪种框架,大家可以根据需要去设计。
12.jpg


Mesos的目标

Mesos的目标,其实主要就是给我们带来资源的高利用率,支持多种多样的自定义框架,包括当前支持的还有以后新产生的分布式计算框架等,都可以建立在Mesos之上。

* 可扩展性。现在全球节点最大的是Twitter有45000个mesos-slave。

* 可靠性。因为Mesos采用的是热备的方式,存在一个master节点,如果遇到主从节点切换的时候非常快,大概10秒钟就能完成。

Mesos的架构
13.jpg

Mesos的主要组成是由ZooKeeper实现master的高可用,还可以保证数据的一致性,保存所有的Mesos sleve节点和信息。Mesos master主要用于接收agent上报给Mesos master的资源,Mesos master会分配offer给具体给它之上运行的framework。

Framework是基于Mesos API定义的调度器,会根据调度需求分配具体的offer。

最底层是Mesos agent,用来接受和执行Mesos master发给它的命令,通过Mesos agent之上的executor启动task。

Mesos的实现

Mesos是用的两万行的C++代码编写而成,故障恢复使用的是ZooKeeper,框架都是可拓展的、可以自定义的,并且是模块化的。是Apache顶级的孵化项目,同时还是开源的,项目成立于2009年。

Mesos的结果

Mesos给我们带来的是更高的资源利用率与可靠性。
##Mesos master的故障恢复机制

接下来说一下Mesos master的故障恢复机制。
14.jpg

因为Mesos master只有一个软体状态,只会列出它之上的framework以及mesos-slave的信息,在Mesos master需要进行切换的时候,通过ZooKeeper进行leader的重新选取,选取好新的leader后,只需要所有的framework和mesos-slave节点重新注册到新的Mesos master之上,时间就10秒钟左右。如有你有上万台机器,可能会同时连Mesos master会不会造成大量的链接导致master服务不可用,官方有这样的设置可以设定链接的比例来进行控制。
##Mesos的生态圈有哪些框架

Marthon framework
15.jpg


* 运行长任务。从应用框架字面的意思,任务就像跑长跑一样,这个框架其实就是运行长任务(long running job)的。

* 服务发现。Marathon还可以实现服务发现,有比较好的API接口,比如我有一个APP id对应具体机器的IP是什么。

* 健康检测&事件通知机制。Marathon支持对你所启动的任务进行健康检测,比如端口或者你自定义命令都可以,有事件通知机制,正因为有了事件通知机制才可以在马拉松之上建立一些实时的服务发现,知道哪些服务宕掉了,在哪些新节点启动了,可以保证我们的实时发现服务,重新指向新的服务器。

* WebUI。Marathon有自己的Web UI,可以通过界面直接操作,非常方便。

* 限定条件。你可以设定一大堆的限定条件,比如我之前说的像你选飞机的舱位一样,你设定了网卡必须是万兆的,Marathon会根据你设定的限定条件,帮你选择对应资源。

* Labels。Labels标签也是我们常用的,随着资源利用率越来越大,可能有各种应用,大家可以加上各种的标签,方便的查询。

* 数据持久化。数据持久化也是支持的,可以支持挂载本地卷。

* 服务的预热。这个功能用得不是特别多,比如你在服务启动的时候会需要启动时间,这个时间健康检测是失败的,你可能需要设定一个预热时间,保证服务启动之后正常的健康检测才生效。

* 优雅退出。优雅退出这个问题,大家可能都会遇到,比如像C++不涉及内存自动回收可能需要程序上设计优雅退出的问题,你可以通过Marathon设置一个退出时间,保证你的服务正常退出之后,才把以前的服务都退掉,新的服务启动。

* 支持自定义的containerizer和GPU资源的调度。

Marathon-LB
16.jpg

Marathon-LB是我们用的一个实时发现的服务,Marathon-LB是基于Haproxy和Marathon eventbus机制设计的。其实除了Marathon-LB还有一些其他的服务实时发现,但是都是基于Marathon的事件通知机制设计的。因为Marathon有事件总线的实时更新,可以实时的改变服务后端的IP。如果有宕机或者有服务自动扩缩容的话,Marathon-LB可以实时改变Haproxy的配置,Marathon-LB主要是通过第四层IP加端口的方式进行服务代理,Marathon-LB支持TCP或者HTTP的代理方式。

Mesos-DNS
17.jpg

我们还使用了Mesos官方的Mesos-DNS服务,用于一些对实时性要求不高的服务,比如我们把STORM容器化以后Nimbus和Supervisor之间的通信可能就不是那么频繁,如果有Nimbus宕机的情况,只需要通过Mesos-DNS就可以重新发现AppID对应的新的Nimbus IP。你可以使用Mesos-DNS发现AppID对应的所有后端节点的IP,可以保证你的服务节点随时都可以访问到你想访问到的IP。Mesos-DNS有一定的延迟性,我们测试大概有十几秒。
#Mesos VS YARN

我说一下在我们做技术选型的时候,我们也做过Mesos和YARN方面的调研。

Mesos主要是能调度各种样的资源,有CPU、内存、端口、硬盘;YARN主要是CPU和内存。

两者都是两极调度策略但是又有不同。

Mesos本身只做资源的调度,不负责具体任务的调度,把任务调度交给framework调度。

YARN全都是YARN本身进行资源调度,一个程序提交给它一个任务都由YARN来决定是否接受或者拒绝这个资源,而Mesos却不同。

Mesos因为是对物理资源进行管理与调度的,YARN主要基于Hadoop来做。

根据需要,我们最后还是选择了Mesos来作我们的分布资源管理框架。
#Mesos VS Kubernetes

说起Mesos可能很多同学觉得使用了Marathon提供了容器任务的管理能力,可能就需要跟Kubernetes系统进行比较一下。

本身来讲,Mesos和Kubernetes是两个东西,Mesos是一个分布式的资源管理框架,被称为分布式系统的内核。假如你有很多物理资源,你想把它整合成一个逻辑资源层面的物理资源池,那么你用Mesos是最合适不过的了。

Mesos解决问题的核心是如何把资源整合成一个大型的物理资源池,它上面运行什么,怎么跑它并不关注。

Kubernetes主要是一个自动化的容器操作平台,操作主要包括部署、调度还有节点集群间的扩容等等。

Kubernetes解决问题的核心主要是围绕容器来做的,这两个系统本身没有可比性。因为Mesos支持很多framework,比如Marathon可以实现容器的调度,所以大家就会把这两个平台进行比较。

如果你想搭建这样一个容器管理平台或者调度平台,从我个人来讲第一点从任务上来讲,Marathon只支持长任务型的,Kubernetes支持的比较广,比如支持长时间任务(long running job),节点后台支撑型(node-daemon)等等各种各样的任务。

说一下稳定性方面,Kubernetes是谷歌官方推出的,它的更新比较频繁,更新频繁可能带来的就不是特别稳定,大家可能理解我可以多做一些线下测试,但是事实确实是这样的,Kubernetes更新非常频繁。Mesos一般每半年更新一次,一年发布两个版本,会经过充分测试。Mesos产品设计因为是开源的,是Apache基金会下面的顶级项目,会在社区跟大家进行投票与沟通,决定未来我们的产品怎么做,我们会增加哪些功能。

第三种主要是从功能上来讲,Kubernetes是由谷歌做的,所以它的考虑会非常全面,它的生态非常全面,你想要的功能基本都有,包括网络Kubernetes其实也是有的,其实Kubernetes本身的网络做得不是特别好,很多用Kubernetes都是用Calico实现的。Mesos系统的设计思路则定义了任务调度和功能上整体依赖于调度器的设计,所以可以把Mesos看成一个大乐高底层的基础板。

对于这两个框架,选择哪一个都没有对与错,只有适合与否,选择一个适合你们的工具才是最重要的。
#Mesos/Container在360的一些应用

我说一下Mesos/Container在360的一些应用。
18.jpg

我们从2015年开始,就对分布式的调度系统或者容器调度平台进行了调研,最后选择使用Mesos,因为我们想构建一个大型的物理资源池。在2016年业务正式上线,包括之后说的一些服务的容器化,2016年我们也使用了Chronos,可以运行一些物理机上运行的crontab任务,长时间支持服务在线运行。2017年我们已经实现了两个机房各部署了一个大型的资源池,节点达到了单集群最大1000个以上,任务达到5000个以上,10个以上的自定义framework。
##解决的问题

部署,现在部署可能你只需要在Marathon上改变你的镜像(image)地址,或者只需要把instance数改大就可以扩容。

故障恢复,如果有一台mesos-slave宕掉了,会自动在其他的节点上启动。

服务降级,关于服务降级,我们的资源池服务器是有限的,1000台服务器如果资源快用满了,有些业务就需要做服务降级,不是所有业务都有动态扩缩容。我们主要处理广告业务,广告业务实时日志流比较多,在资源不够的时候,会让某些业务降级。平时每秒处理20万条,降级时让它每秒处理10万条或者5万条,有一定数据延迟也没有关系,因为数据不会丢只会慢慢处理完。

服务发现,关于服务发现,现在有了Mesos-DNS和Marathon-LB我们可以做到实时的服务发现,因为是动态资源划分,我们的任务就可能实时变化。
##Storm集群的容器化

19.jpg

上图是原来通过物理级部署的,所有的Supervisor节点都是一台台物理机还要单独部署一个Nimbus,如果Nimbus节点宕掉非常麻烦,比如有些同学说我可能会用Keepalived做高可用,这确实是一种方案,但是如果你的集群需要频繁的扩容或者缩容就会非常麻烦,你要是不对资源进行动态管理的话,势必带来的就是资源的浪费,因为不可能一天24小时都满负荷运行。

把服务容器化之后,所有的Supervisor都运行在container(mesos-slave)中,Supervisor节点会通过Mesos-DNS发现Nimbus(master)的IP。现在集群资源都是动态利用的。
20.jpg

##图片服务的容器化

重点说一下图片服务的容器化。
21.jpg

图片服务主要用的PHP 7来做的,我们也会面临像阿里一样在双十一的时候,因为广告展示与投放量非常大,每秒达到上百万次,因为给用户进行展示与投放的图片会根据用户的习惯去动态的缩放与拼接。如果我放着很多机器专门用来做图片服务,可能也可以达到你的需求,但是在空闲时间段比如夜里资源浪费得非常多,对资源的利用率不是非常好。

我们就制定了这样一套方案,首先把PHP服务容器化,之后我们根据亚马逊AWS的策略,做了自己的方案,跑一个long running job,根据Marathon的API获取你的图片服务具体是哪台机器,由于所有机器上的监控都用了二次开发,通过API接口能获取负载、CPU,内存等等信息。当图片服务器的负载上升了肯定是压力最大的时候,这样我们只需要设定一个阈值。

比如系统负载大于10超过10次,就进行一次扩容,扩容的倍数是1.5倍,原来我有10台机器,现在要扩容到15台。大家可能会问你这个最大能扩到多少?我一定要设定一个最大值不能无限的扩。比如我们设定一个36,最大扩到36台,在5分钟内可能判断10次,如果这个负载水平一直很高,就不进行缩容。

我肯定还会设定一个最低值,比如最低值是6台,可能到了夜里直接减为6台,每次都需要通过Marathon的API实时发现后端所有机器计算出一个平均值。服务的监控,我们对每台Mesos slave都有监控,具体的container我们做了异步,通过异步把日志写到Graylog中,监控日志传输通过UDP协议。如果发生网络中断的情况也不会有太大影响,因为UDP是可丢的不可靠的。
##其他

我们还有其他服务的一些容器化,有Web service相关的,Aerospike服务,通过组播实现集群之间的通信部署起来比较方便,Marathon-LB也是完全的Docker化的,毕竟是代理层像LVS一样,可能会有服务瓶颈。Kafka MirrorMaker我们用来进行多机房之间的数据传输,原来直接部署在物理机上,这样虽然不会有太大问题,如果宕掉之后数据不能在多个集群当中进行同步,对实时性不能要求那么高。如果做了容器化之后是可调度的,都是可高可用的,我们会保证服务的可靠性。Redis也有做容器化,支持数据的落地和持久化,因为我们有CephFS还有更多的一些无状态的服务也运行在Mesos之上。
22.jpg

最后我要说一下我们的服务CI/CD是怎么做的,CI/CD主要是通过GitLab runner。我们会定义一个Gitlab-CI,可以直接把你提交的代码进行Docker build,把镜像自动提交到对应的仓库,通过API修改Marathon上面对应的地址,最后实现上线自动化。
#未来计划

未来我们想做的,因为CephFS的量不是很大,CephFS之后想上一些写入量比较大的业务,看看效果如何。我们不是做公有云的对于Calico的需求不是那么急切,之前一直没有上这个服务。之后我们可能会做一些Calico相关的,比如一些爬虫的应用,如果用公司的Nat代理的话,可能遇到一些IP被封,导致整个代理IP都不能访问对应的网站就有一些问题了。

还有一些实时的机器学习,现在机器学习主要都基于离线业务来做,实时学习比较少,Marathon和Mesos本身是支持的。

原文链接:Mesos container在360广告系统的应用(作者:李冬)

Mesos 1.5发布,在存储、性能资源管理以及容器化方面有重大改进

大卫 发表了文章 • 0 个评论 • 2118 次浏览 • 2018-02-09 11:57 • 来自相关话题

今天,我很高兴向大家宣布,Apache Mesos 1.5.0版本已经正式与您见面! #新的功能与改进 Mesos 1.5当中包含资源管理、存储与容器化方面的多项重大改进。容器存储接口(简称CSI)支持正是Mesos 1.5当中全瓣 ...查看全部
今天,我很高兴向大家宣布,Apache Mesos 1.5.0版本已经正式与您见面!
#新的功能与改进

Mesos 1.5当中包含资源管理、存储与容器化方面的多项重大改进。容器存储接口(简称CSI)支持正是Mesos 1.5当中全瓣的实验性能力之一,此外亦有大量与之配合的新功能伴随1.5版本一道推出。对代理进行重新配置的新能力将使得操作人员拥有更出色的使用体验。性能提升使得主节点故障转移速度提升80%到85%,而v1 API性能也得到了显著改善。新版本中的资源管理机制更为灵活。此外,同样重要的是,镜像垃圾收集与更强大的Windows支持能力使得您能够更轻松地在不同基础设施类型之上运行Mesos,同时亦可在Mesos之上简单运行多种不同工作负载。

在接下来的文章中,我们将共同了解Mesos 1.5当中的各项卓越改进。
#容器存储接口支持

Mesos 1.5以实验性方式增加了对容器存储接口(简称CSI)[1]的支持能力,这项新规范为存储供应商与容器编排平台之间的全部交互活动定义了一个通用型API。这项功能的出现无疑是Mesos、Kubernetes、Cloud Foundry以及Docker技术社区之间密切合作的结果。CSI的主要作用在于允许存储供应商编写出适用于全部容器编排平台的插件。
对CSI的支持将帮助Mesos始终与规模更大的存储生态系统保持步调一致,从而确保Mesos一直具备更强大的存储支持能力。用户将能够在包含Mesos的任何存储系统当中使用一致的API选项。CSI的out-of-tree插件模式将Mesos的发布周期与存储系统的发布周期区分开来,使得集成系统本身更具可持续性与可维护性。
01.png

上图所示为Mesos所支持的CSI高层架构。若需了解更多细节信息,请参阅说明文档
#提升操作人员使用体验

##代理重新配置策略

在Mesos 1.5之前,用户无法对代理的配置作出任何变更——惟一的方法就是关闭该代理上运行的所有任务,并使用新的代理ID重新启动。任何变化,例如添加额外属性或者新接入磁盘驱动器,都将导致代理启动中止并引发令人头痛的错误:
EXIT with status 1: Failed to perform recovery: Incompatible agent info detected.
------------------------------------------------------------
[...]
------------------------------------------------------------
To remedy this do as follows:
Step 1: rm -f /path/to/work_dir/meta/slaves/latest
This ensures agent doesn't recover old live executors.
Step 2: Restart the agent.

从1.5版本开始,操作人员能够使用新的代理命令行标记--reconfiguration_policy 对代理上应当允许的操作类型进行配置。在将该标记的值设置为additive时,代理将能够接受一切对代理资源量的变更以及对其它属性或故障域的调整。

未来,我们还希望能够进一步添加--reconfiguration_policy=any 设置选项以允许对代理配置作出任意变更。
#性能改进

此版本还包括对主节点故障转移与v1操作状态查询API性能的改进。主节点故障转移完成时间的缩短,源自数据吞吐量高达450%到600%的显著提升,这意味着整体完成时间将缩短80%到85%。
02.png

除此之外,v1操作状态查询API的性能也得到了极大改进,这要归功于我们消除了过程中不必要的复制操作。具体来讲,目前v1 protobuf GetState调用速度较v0提高了36%。此外,v1 JSON Get Sstate性能亦提升了四倍以上。
03.png

更多详尽基准测试结果,请参阅此电子表格
#资源管理

##配额保障改进

此次发布的新版本当中引入了多项与配额机制相关的改进。如今,Mesos将能够更好地保证角色获取配额以及角色不致超额等等,例如:

* 此前,一个角色可收集未使用的预留配额以“愚弄”配额系统,但如今新版本会在分配资源时对预留配额进行核算,从而防止这种情况的发生。
* 资源如今会以细粒度方式进行分配,以防止角色出现超额状况。
* 无配额角色可能收到保留资源的bug已经得到修复。
* 角色的保留资源高于配额资源时,可能出现配额空间缺失的问题已经得到修复。
* 当把资源分配给某个具有资源配额的角色时,此前的版本亦会将部分超出该角色配额之外的资源移交给它。这意味着不同角色的资源配额可能无法得到正确执行。目前这个问题已经通过在分配资源时计算余量的方式得到解决。

##资源提供方抽象

为了将资源与代理生命周期加以拆毁,我们引入了资源提供方这一抽象机制。其作用在于支持代理资源的动态变化、外部资源供应方整合乃至集群范围内资源管理。作为资源责任分离思路的组成部分,我们引入了一项新的资源分配协议,旨在更明确地就成功或失败结果进行通信,同时实现各集群组件间的协调。我们使用新的资源供应方抽象将代理本地存储资源同CSI通过接口加以整合。
#容器化与多平台支持

##Windows 支持能力得到改善

随着Mesos 1.5版本的发布,Windows支持能力得到了极大改善。现在,您在利用Mesos容器运行任务时,可以通过作业对象(MEOS-6690)立足操作系统层级实现资源限制。在使用windows/cpu与windows/mem隔离器时,您可以对CPU周期与虚拟内存强制加以限制。此外,新版本现在也能够正确支持CPU与内存统计信息收集。Mesos fetcher已经被移植到Windows平台,支持通过TLS自动下载文件并释放ZIP压缩文件。在进行配置时,libprocess现在可配合Windows上的OpenSSL支持能力进行构建,这意味着TLS连接将可立足集群之内实现(请注意,由于Windows本身不提供OpenSSL,因此您需要在外部构建或安装OpenSSL)。第一种验证方法CRAM-MD5此次也正式登陆Windows,因此代理将可借此与主节点进行验证。HTTP与TCP状态检查机制也已经能够作用于Windows代理(可用于shell任务; Docker容器运行状态检查也即将推出)。Meos代理不再需要以管理员身份运行,因为其现在能够像普通用户一样创建符号链接,且此项功能已经被集成于代理当中。最后,虽然在上一版本中已经实现,但这里不妨再提一句——Windows本地长路径支持已经实现,意味着您将能够更轻松地立足Windows运行代理(无需进行注册表配置)。
##容器镜像垃圾收集

Mesos 1.5版本支持容器镜像垃圾收集。目前您可以通过两种方式对未使用的镜像层进行垃圾收集:自动与手动。这项功能允许用户轻松解决磁盘空间被docker镜像大量占用的难题。具体请参阅容器镜像垃圾收集说明文档以了解更多细节信息。
##独立容器

本次新版本包含一组新的操作程序API,用于启动并管理所谓“独立容器”这一新型原语。独立容器类似于由Mesos代理之上的框架所启动的容器,只是独立容器由操作程序在Mesos代理上直接启动。如此一来,这些容器将无需使用Mesos执行器,且具有其它一些限制特性(例如无法使用预留资源等)。与此同时,独立容器几乎与其它容器完全隔离,并与容器镜像类似——能够使用同样的容器化功能集。

此项功能的发布旨在支持CSI工作流,但各API并不限于此用例。未来,此项功能可能将被用于为各代理节点实现守护进程。具体请参阅MESOS-7302以了解更多细节信息。
#Mesos内部

##支持gRPC客户端

此次新版本包含一套gRPC客户端打包器。gRPC是一种PC机制,并作为RESST API的替代性方案在云原生领域愈发受到欢迎。作为将gRPC整合至Mesos的第一步,我们在libprocess当中添加了此客户端打包器以支持CSI。该功能在默认情况下处于禁用状态,您可以在安装有OpenSSL库的集群当中使用--enable-grpc (autotools)加以启用。该包装类负责在内部维护gRPC运行时数据结构,同时提供一个简单接口,以便实现与libprocess的基于actor模式相兼容的异步gRPC调用。我们还利用这项新功能连接CSI插件。除此之外,大家也可以使用这项新功能创建Mesos模块,用以同其基于gRPC的服务进行通信。
##复制日志改进

Mesos复制日志可帮助各类框架(例如Apache Aurora)将自身状态保存为多套副本,从而在故障转移及重新启动时实现状态保留。从1.5版本开始,大家将能够读取来自一套非主导VOTING复制日志副本处以最终一致化方式进行读取。如此一来,您将能够在非主导框架副本之上进行其它处理工作,例如将部分读取任务移交至待命副本,或者将高频复制日志副本 保留在内存内以缩短故障转移时间。
#升级

从Mesos 1.4.0升级至Mesos 1.5.0非常简单。请参阅升级指南以了解更多与升级至Mesos 1.5.0相关的细节信息。
#社区

您是否在本次发布的新版本中受到了启发?您是否希望参与其中?您对此有何见解?我们期待着听到您的声音!请立即加入工作组或在社区中开启对话!
#鸣谢!

感谢Mesos 1.5.0版本项目组的59位贡献者:

Aaron Wood, Adam B, Adam Dangoor, Akash Gupta, Alastair Montgomery, Alexander Rojas, Alexander Rukletsov, Anand Mazumdar, Andrei Budnik, Andrew Schwartzmeyer, Andrey Dudin, Andy Pang, Anindya Sinha, Armand Grillet, Avinash sridharan, Benjamin Bannier, Benjamin Hindman, Benjamin Mahler, Benno Evers, Bob Eckert, Chun-Hung Hsiao, Cynthia Thomas, Deepak Goel, Dmitry Zhuk, Gaston Kleiman, Gastón Kleiman, Gilbert Song, Greg Mann, Ilya Pronin, Jack Yang, James DeFelice, James Peach, Jan Schlicht, Jason Lai, Jeff Coffler, Jiang Yan Xu, Jie Yu, Joerg Schad, John Kordich, Joseph Wu, Julien Pepy, Kapil Arya, Kevin Klues, Megha Sharma, Meng Zhu, Michael Park, Nathan Jackson, Neil Conway, Packt, Pranay Kanwar, Qian Zhang, Quinn Leng, Richard Shaw, ThodorisZois, Till Toenshoff, Tomas Barton, Tomasz Janiszewski, Vinod Kone, Zhitao Li

希望Apache Mesos 1.5能够让您满意!

原文链接:Mesos 1.5: Storage, Performance, Resource Management, and Containerization improvements

去哪儿网OPS基于Mesos/Docker构建的Elasticsearch容器化私有云

尼古拉斯 发表了文章 • 0 个评论 • 2913 次浏览 • 2017-11-16 15:42 • 来自相关话题

【编者的话】本次分享主要介绍一下去哪儿网 OPS 团队利用 Mesos 资源管理平台和 Docker 容器技术所构建的 Elasticsearch 容器化的私有云。主要有四个部分, 第一个部分主要介绍一个我们当初做这个平台的背景,和现在的规模和现状,第二个部分 ...查看全部
【编者的话】本次分享主要介绍一下去哪儿网 OPS 团队利用 Mesos 资源管理平台和 Docker 容器技术所构建的 Elasticsearch 容器化的私有云。主要有四个部分, 第一个部分主要介绍一个我们当初做这个平台的背景,和现在的规模和现状,第二个部分主要简单介绍一下整个平台的技术实现,最后分享是持续构建方面的工作以及监控和报警相关方面的工作。
#背景与现状

2015年底到2016年初的这段时间,公司业务线对 ES 的需求量暴增,传统的使用 ES 的方式逐渐显现出一些弊端,主要有一下几点的内容:
01.jpg

针对上述所列的几点弊端,我们最初制定的几点设计目标如下:
02.jpg

最终,为了达到这几点目标,我们就设计和开发了这个平台。
03.jpg

自从16年3、4月份这个平台上线以来,工作效率得到了很大改进,主要有以下三个方面:
04.jpg

下面这个图是统计的过去传统的使用方式与现在的平台的方式使用 ES 所带来的资源利用率的提升:
05.jpg

这个是我们目前的平台规模:
06.jpg

07.jpg

整个平台支持了很多重要系统后端的数据存储,比如:
08.jpg

#技术实现

刚开始做这个平台的时候,我们主要调研参考了以下三个系统和平台:
9.jpg

第一个 Elastic Cloud 是 Elastic 官方提供的一个公有云的服务,他能够提供快速集群构建的能力,也具备自助化配置,快速扩容能力,比较符合我们的预期功能。第二个 Amazon Elasticsearch Service 同样也是一个公有云服务,能够提供快速的集群构建能力,自助化配置等等,同样也为我们提供了极大的参考价值。第三个是一个开源的基于 Mesos 的一个调度框架,他的设计是一个 Framework 代表一个 ES 集群,Framework 的每一个 Executor 代表一个 ES 节点,但是也有许多不支持,包括不支持多种角色节点的配置,不支持自助化的配置,不支持插件的安装,这与我们的设计初衷是相违背的。结合了上述三个例子,我们设计指定了我们自己的技术方案。
10.jpg

整个平台基于 Mesos,所有组件以 Docker 容器的形式被 Marathon 调度跑起来,这个是一个整体的结构图:
11.jpg

我们底层所有的机器都是被同一个 Mesos 来进行统一管理的,Mesos 之上运行着 Marathon 调度框架,值得注意的是,我们有两层的 Marathon,底层比较大的 Marathon 我们称之为 Root Marathon,上层包含在 Root Marathon 之中的小的 Marathon 我们称之为 Sub Marathon,Root Marathon 只负责调度内层的Sub Marathon,内存的 Sub Marathon 才是真正承载着我们每一个 Es Saas 服务。我们所有的组件都是跑在 Docker 容器里面的。
12.jpg

那么我们平台的资源是怎么分配的呢,这个图是一个分配的结构图,可以看到资源是按照 Marathon 分层的这种方式来分配的,Root Marathon 拥有系统所有的资源,Sub Marathon 是资源分配的最小单位,每一个都有它既定的资源,资源结构如此,当然集群间的逻辑隔离也是如此。
13.jpg

Sub Marathon 不仅有他自己的资源,而且我们将它和业务线做了一一映射,也就是说一个Sub Marathon 唯一的代表一个业务线,同时它也是承载了业务线的所有集群。

下面这个图展示的是 Sub Marathon 内部细节的结构图:
14.jpg

一个 Sub Marathon 可以承载多个 ES 集群,每一个 ES 集群有4个重要的组件,分别是:Bamboo,es-master,es-datanode,es2graphite,这4个组件是组成 ES 集群的基础,他们分别对应着一个 Marathon 的 APP,APP 的 task 是真正的 ES 节点。 下面这个图展示了上述4种基础组件之间的关系:
15.jpg

默认的 ES 有3个 master 节点和3个 datanode 节点,他们分为两个 Marathon APP 独立运行,他们之间互相的服务发现是由 Bamboo + HAProxy 这个组件来完成的,这样他们才能连成一个集群,es2graphite 负责收集 ES 集群指标,它的原理就是调用 ES 内部的接口获取指标,然后聚合打到后端的 Graphite 上分析展示。pyadvisor 这个组件不是存在每一个集群中的,而是 run 在每一个 mesos slave 上的一个服务,他们负责收集容器维度的指标,聚合之后打到后端 Graphite 上实时展示,下面就是一个具体的 slave 机器上的快照:
16.jpg

每个机器上可以跑多个 ES 节点,不同的 ES 节点之间使用端口号来区别。

在每一个 ES 集群中,起着至关重要作用的就是服务发现,而这个服务发现是由 Bamboo + HAProxy 这个组件来完成的。
17.jpg

Bamboo 是一个开源的跑在 Marathon 之上服务发现的工具,它的原理就是注册了 Marathon 的 callback 接口接受 Marathon 事件消息时时解析并 reload haproxy。

ES 集群内部服务发现的配置其实只是用了一句图中的配置项,这个配置项是 ES 的单播地址,是告诉 ES 节点去哪个机器的哪个端口找 master 的,我们只是简单的把他替换成了 Haproxy 的 host 和 port。ES 节点在起来的时候,Bamboo 检测到启动事件,随即通过 Marathon API 获取到真实的 Master 的 host 和 port,然后 Reload Haproxy 建立端口转发关系,同时,ES Datanode 节点在起来的时候,就会通过 Haproxy 的前端 host 和 port 经转发到真实的 Master 地址上,由此实现了服务发现的过程。三个 Master 之间也是同样的道理,他们通过 Haproxy 再“回连”自己。

在数据持久化和可靠性方面我们做了一下几个方面的工作:
18.jpg

#配置和部署

接下来介绍一下我们做的自助配置和持续构建方面的工作,有关所有的 ES 的配置我们都存在了 GitLab 中,包括一个特殊的 pre-run 文件,这个文件定义了在我们启动 ES 节点实例之前我们该做些什么,这个文件是可以修改的,可以由业务线同学自定义。同时一些其他的配置文件也是存在 GitLab 上的,修改之后,只需要重启容器即可生效。
19.jpg

同时我们在自助管理方面也做了一些工作,下图是我们自己做的一个 Web 系统, 用来展示详细的集群信息和做一些自助化配置方面的工作。
20.jpg

21.jpg

22.jpg

在新集群交付的时候,我们也是直接交付这个 Web 页面,业务线同学可以很方便的查到信息,也可以很方便的做一些操作。说到交付,我们在持续构建方面也做了一些工作。
23.jpg

这个是新的 ES 集群从配置到部署到上线的整个过程,都是基于 Jenkins 来做的,一共有三步,第一步是配置的初始化,这一步中会生成部署过程中所有的配置文件,生成之后直接存储到 GitLab 中,到了第二步集群部署的时候,我们会按照顺序读取配置,一一的将各个组件提交到 Marathon,最后一步就是 Marathon 调度运行,等全部完成之后,我们一个完整的 ES 集群也就 work 了。
#监控与报警

最后一部分说一下监控和报警,监控指标的收集,主要有两个方式:
24.jpg

下面是指标聚合之后的一个示例:
25.jpg

26.jpg

关于报警,主要有一下几个方面:
27.jpg

最后,用一张图来总结一下所有的内容:
28.jpg

从 ES 的建立到销毁,我们做到了 ES 集群整个生命周期的管理,建立初我们会做容量预估和参数的配置,等到部署的时候,我们有持续构建部署的工具来做,服务上线之后我们提供了可以自助配置,自助插件的 web 工具,极大的方便了开发人员,同时也有完备的监控和报警。集群下线的时候,统一的回收资源,做一些清理拓补的工作。

原文链接:OPS基于Mesos/Docker构建的Elasticsearch容器化私有云&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=w4%2BKnbJeburqHxw1NITmvjD%2F0Yl2jglryfwheZBsvTHlPo4n1tH5rOO3wR0XQnJj)(作者:马文)

携程容器云优化实践

尼古拉斯 发表了文章 • 0 个评论 • 4134 次浏览 • 2017-11-10 20:54 • 来自相关话题

随着微服务架构的流行,把容器技术推到了一个至高点上;而随着Docker,Kubernetes等容器技术的日趋成熟,DevOps的概念也再次热度上升;面对容器化的大潮趋势,各家公司都在积极地响应和实践,携程也在这方面做了不少工作,形成了自己的容器云平台。 ...查看全部
随着微服务架构的流行,把容器技术推到了一个至高点上;而随着Docker,Kubernetes等容器技术的日趋成熟,DevOps的概念也再次热度上升;面对容器化的大潮趋势,各家公司都在积极地响应和实践,携程也在这方面做了不少工作,形成了自己的容器云平台。

从容器云的打造思路上,携程将其划分成了水上、水下两大部分:

* 水下部分是指容器云服务的基础架构
* 水上部分是指面向容器而产生的一系列工程实践配套

水下部分对Dev来说相对透明,而水上部分则会对Dev工作有直接影响,也就是DevOps概念里所提到“混乱之墙”所在的地方。所以只要水上、水下同时做好了,容器云才能真正落地,并符合DevOps理念的设想。
#一、基础架构

容器云在携程主要经历了以下3个阶段:
01.png

##第一阶段,模拟虚机,通过OpenStack进行管理

在这个阶段,主要的目的是验证携程已有的应用是否能够在Docker容器下正常运行,并提升系统与容器的兼容性。这个过程中系统的主要架构还是使用OpenStack的nova模块,把Docker模拟成虚机的形式进行管理,除了应用实际运行的环境产生了变化,其他任何流程,工具都不变,从而使影响范围控制在最小。
##第二阶段,实现镜像发布,使用Chronos运行Job应用

在这个阶段,主要的目的是通过镜像的方式实现应用的发布和变更。真正实现 Immutable Delivery,即一旦部署后,不再对容器进行变化。并且在这个过程中,架构从比较繁重的OpenStack体系中解脱出来。使用轻量级的Mesos+Chronos来调度Job应用,在这个过程中我们同时去掉了对Long Running的Service类型应用的支持,以方便测试在极端情况下调度的消耗,和整个系统的稳定性。

此时,整个容器云的架构如下图:
02.jpg

实践证明这个架构在应对大量并发Job的调度时,Mesos自身调度消耗过大,因为每启动一次Job都需要拉起一个Docker实例,开销客观。同时也证明在携程这样的应用体量下,直接使用开源Framework是无法满足我们的需求的,这也促使我们开始走向自研Framework的方向。
##第三阶段,自研Framework

在这个阶段,我们主要要解决的问题有:

* 同时支持Job与Service两种类型的应用
* 为每个Docker实例分配独立的IP
* 支持Stateful的应用
* 完善容器的监控体系

此时的总体架构如下图:
03.jpg

与第二阶段的架构不同之处:

* 首先,重新封装了Mesos的Rest API层,使得对外提供的API更丰富(可以与其他已有系统结合,提供更多的功能),同时基于一些规范统一的考虑,收拢了一些个性化参数的使用。除此之外,独立抽象API层也是为了将来能够快速适配其他架构体系,如Kubernetes时,可以做到对上应用透明。
* 其次,对Mesos做了集群化分布,从而提高Mesos本身的可用性。
* 最后,为了应对大量Job类应用的调度,采用了与long running一样的方式,将Executor放置于容器内部。做到Job调度时,不重新启动容器,而是在容器内部调度一个进程。

说完了系统架构后,还有2个比较重要的问题:
##网络

携程对容器实例的要求是,单容器单IP,且可路由,所以网络选项上采用的仍旧是Neutron+OVS+VLan这个模式,这个模式比较稳定,网络管理也比较透明。在实际对每个容器配置网络的过程中,携程自研了一套初始化hook机制,以通过该机制在容器启动后从外部获取对应的网络信息,如网段,或者Neutronport等,在配置到容器内,这样就完成了网络配置的持久化。大致的机制如下图所示:
04.jpg

当然利用这个hook机制还能处理其他一些特殊的case,之后也会有提到。
##监控

05.jpg

监控分为2个部分,一块是对Mesos集群的监控。携程用了很多开源技术,如:Telegraf、InfluxDB、Grafana等,并做了一些扩展来实现Mesos集群的监控,采集mesos-master状态、task执行数量、executor状态等等,以便当Mesos集群出现问题时能第一时间知道整个集群状态,进而进行修复。

另一块是对容器实例的监控,携程监控团队开发了一套监控系统hickwall, 实现了对容器的监控支持。 hickwall agent部署在容器物理机上,通过Docker client 、Cgroup等采集容器的运行情况,包括 CPU 、Memory、Disk IO等常规监控项;由于容器镜像发布会非常频繁的创建、删除容器,因此我们把容器的监控也做成自动发现,由hickwall agent发现到新的容器,分析容器的label信息(比如: appid、版本等)来实现自动注册监控;在单个容器监控的基础上,还可以按照应用集群来聚合显示整个集群的监控信息。
06.jpg

##自研Framework的动机


* 轻量化,专注需求

开源Framework为了普适性,和扩展性考虑,相对都比较重,而携程实际的使用场景,并不是特别复杂,只需要做好最基础的调度即可。因此自研的话更可以专注业务本身的需求,也可以更轻量化。

* 兼容性,适配原有中间件

由于携程已经形成了比较完整的应用架构体系,以及经过多年打造已经成熟的中间件系列。所以自研Framework可以很好地去适配原有的这些资源,使用开源项目反而适配改造的成本会比较大,比如路由系统,监控系统,服务治理系统等等。

* 程序员的天性,改不如重写

最后一点就比较实在了,开源项目使用的语言,框架比较分散,长远来说维护成本比较大

##自研Framework的甜头

正如前面所说,自研Framework能够很方便地解决一些实际问题,下面就举一个我们碰到的实际例子。

我们知道Mesos本身调度资源的方式是以offer的模式来处理的,简单来说就是Mesos将剩余资源的总和以offer的形式发送出来,如果有需求则占用,没有需求则回收,待下次发送offer。但是如果碰到下图这样的情况,即Mesos一直给出2核的资源,并且每次都被占用,那一个需要4核的实例什么时候能拿到资源呢?
07.jpg

我们把这种情况叫做offer碎片,也就是一个先到的大资源申请,可能一直无法得到合适的offer的情况。

解决这个问题的办法其实很简单,无非2种:

  1. 将短时间内的offer进行合并,再看资源申请的情况
08.jpg

  1. 缩短mesosoffer的timeout时间,使其强制回收合并资源,再次offer
09.jpg


携程目前采用的方案2,实现非常简单。

以上大致介绍了一下携程容器云的水下部分,即基础架构的情况,以及自研Framework带来的一些好处。关于Kubernetes,由于我们封装了容器云对外的API层,所以其实对于底层架构到底用什么,已经可以很好的掌控,我们也在逐步尝试将一些stateful的应用跑在Kubernetes上,做到2套架构的并存,充分发挥各自的优势。
#二、工程实践

容器化的过程除了架构体系的升级,对原先的工程实践会带来比较大的冲击。也会遇到许多理念与现实相冲突的地方,下面分别介绍携程遇到的一些实际问题和解决思路。
##代码包到镜像,交付流程如何适配,如何迁移过渡?

DevOps理念提倡“谁开发,谁运行”,借助docker正好很方便的落地了这个概念。携程的CI/CD系统同时支持了基于镜像与代码包的发布。这样做的好处是能够在容器化迁移的过程中做到无缝和灰度。
10.jpg

##能像虚机一样登陆机器吗?SSH?

Docker本身提倡单容器单进程,所以是否需要sshd是个很尴尬的问题。但是对于Docker实例的控制,以及执行一些必须的命令还是很有必要的,至少对于ops而言是一种非常有效的排障手段。所以,携程采用的方式是,通过web console与宿主机建立连接,然后通过exec的方式进入容器。
11.jpg

##Tomcat能否作为容器的主进程?

我们知道主进程挂掉,则容器实例也会被销毁。而Java开发都知道,Tomcat启动失败是很正常的case。由此就产生了一个矛盾,Tomcat启动失败,并不等同于容器实例启动失败,我们需要去追查Tomcat启动失败的原因。由此可见,Tomcat不能作为容器的主进程。因此,携程仍旧使用Supervisord来维护Tomcat进程。同时在启动时会注册一些自定义hook,以应对一些特殊的应用场景。比如:某些应用需要在Tomcat成功启动,或成功停止后进行一些额外的操作,等等。
12.jpg

##JVM配置是谁的锅?

容器上线后一段时间,团队一直被一个JVM OOM的问题所困扰,原来在虚机跑的好好的应用,为什么到容器就OOM了呢?最后定位到问题的原因是,容器采用了cpu quota的模式,但JVM无法准确的获取到cpu的数量,只能获取到宿主机cpu的数量;同时由于一些java组件会根据cpu的数量来开启thread数量,这样就造成了堆外内存殆尽,最终造成OOM。

虽然,找到了OOM的原因,但是对于容器云来说,却面临了一个棘手的问题。容器实例不像虚机,在虚机上,用户可以按需定义JVM配置,然后再将代码进行发布。在容器云上,发布的是镜像,JVM的配置则变成了镜像的包含物,无法在runtime时进行灵活修改。

而且,容器本身并不考虑研发流程上的一些问题。比如,我们有不同的测试环境,不同的测试环境可能有不同的JVM配置,这显然与docker设想的,一个镜像走天下的想法矛盾了。

最后,对于终端用户而言,在选择容器时,往往挑选的是flavor,因此我们需要对应不同的flavor定义一套标准的JVM配置,利用之前提到的容器启动时的hook机制,从外部获取该容器匹配的标准JVM配置。

我们也总结了一些对于对外内存的最佳实践,如下:

Xmx = Xms = Flavor 80%
* Xss = 256K
* 堆外最小800,最大2G,符合这个规则之内,以20%计

##问题又来了,用户需要自定义JVM?

最终,我们将JVM配置划分成了3个部分:

  1. 系统默认推荐部分
  2. 用户自定义Override部分
  3. 系统强制覆盖部分

允许用户通过代码或外部配置系统,对应用的JVM参数进行配置,这些配置会覆盖掉系统默认推荐的配置,但是有一些配置是公司标准,不允许覆盖的,比如统一的JMX服务地址等,这些内容则会在最终被按标准替换成公司统一的值。
13.jpg

##Dockerfile的原罪

Dockerfile有很多好处,但同时也存在很多坏处:

* 无法执行条件运算
* 不支持继承
* 维护难度大
* 可能成为一个后面,破坏环境标准

因此,如果允许PD对每个应用都自定义Dockerfile的话,很有可能破坏已有的很多标准,产生各种各样的个性化行为,使得统一运维变成不可能,这种情况在携程这样的运维体谅下,是无法接受的。
##打造“Plugin”服务平台

所以,携程决定通过 “Plugin”服务的方式,把Dockerfile的使用管控起来,将一些常规的通过Dockerfile实现的功能形成为“Plugin”,在Image build的过程中进行执行。这样做的好处是,所提供的服务可标准化,并且可复用,还可以任意组装。比如:我们分别提供“安装FTP”,“安装Jacoco”等插件服务。用户在完成自己的代码后,进行image build时就可以单选或多选这些服务,那最后形成的image中就会附带这些插件。并且针对不同的测试环境可以选择不同的插件,形成不同的镜像。
14.jpg

对于一个“Plugin”而言,甚至可以定义一些hook(注册supervisord hook),以及一些可exec执行的脚本,从而进一步扩展了“Plugin”的能力。比如可以插入一个Tomcat的启停脚本,从而获取从外部控制容器内Tomcat的能力。
15.jpg

公司内的每个PD都可以申请注册“Plugin”,审核通过后,就可以在平台上被其他应用所使用。注册步骤:

  1. 为服务定义名称和说明
  2. 选择服务可支持的环境(如:测试,生产)
  3. 上传自定义的Dockerfile
  4. 上传自定义的可运行脚本
16.jpg

17.jpg


##“Jacoco Plugin”的实例

Jacoco是一个在服务端收集代码覆盖率的工具,以帮助测试人员确认测试覆盖率。这个工具的使用有以下几个需求:

  1. 需要在代码允许环境中安装Jacoco agent
  2. 只需要在特定的测试环境进行安装,生产环境不能安装
  3. 被测应用启动后,需要往Jacoco后端服务进行注册
  4. 测试过程中可以方便控制Jacoco的启停(通过Tomcat启动参数控制)

针对以上的需求,定制一个“JacocoPlugin”的工作,如下图:
18.jpg


  1. 通过dockerfile安装 jacoco agent
  2. 注册一个supervisord hook,在tomcat启动成功后向Jacoco service进行注册
  3. 利用一个自定义tomcat重启脚本,并在平台的web server上暴露API来控制Jacoco的启停

这样,所有容器云上的应用在image build时就都可以按需选择是否需要开通Jacoco服务了。
19.jpg

利用这样的平台机制,还提供了一系列其他类型的“Plugin”服务,以解决环境个性化配置的问题。
#三、总结


  1. DevOps或者容器化是理念的变化,更需要接地气的实施方案
  2. 基础架构,工程实践和配套服务,需要并进,才能落地
  3. 适合自己的方案才是最好的方案

携程的容器云进程还在不断的进化之中,很多新鲜的事务和问题等待着我们去发现和探索。

作者简介:王潇俊,多年来致力于云平台及持续交付的实践。2015年加入携程,参与携程部署架构的全面改造,主导设计和打造新一代的适用于微服务的发布系统。同时负责基于携程私有云的兼容虚机与容器的持续交付平台。ROR狂热粉丝,敏捷文化的忠实拥趸。

原文链接&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=bWkIjfRZWxqiliz9Dzk6utuzNefKy4zdNZH%2BqVjeYKoc0XKaFb%2FrxpPgrbNrSege)

Mesos容器引擎的架构设计和实现解析

李颖杰 发表了文章 • 0 个评论 • 2923 次浏览 • 2017-09-19 15:14 • 来自相关话题

【编者的话】提到容器,大家第一时间都会想到Docker,毕竟Docker是目前最为流行的容器开源项目,它实现了一个容器引擎(Docker engine),并且为容器的创建和管理、容器镜像的生成、分发和下载提供一套非常便利的工具链,而它的容器镜像格式几乎就是业界 ...查看全部
【编者的话】提到容器,大家第一时间都会想到Docker,毕竟Docker是目前最为流行的容器开源项目,它实现了一个容器引擎(Docker engine),并且为容器的创建和管理、容器镜像的生成、分发和下载提供一套非常便利的工具链,而它的容器镜像格式几乎就是业界的事实标准。但其实除了Docker之外,在容器的开源生态圈中还有其它一些项目也在做自己的容器引擎,这样的项目一般也被称作为容器运行时(container runtime),比如:CoreOS的rkt和Mesos的容器引擎(Mesos containerizer)。

在本文中,我将对Mesos容器引擎进行一个全面的介绍,解释在Docker如此流行的情况下Mesos为什么还要坚持做自己的容器引擎,介绍Mesos容器引擎的总体架构和各核心组件,以及它对容器各相关标准规范的采纳和支持。
#容器和容器引擎的定义

首先我们来了解一下什么是容器。我个人对容器的定义是:一个或一组使用了cgroups做资源限定、使用了namespace做资源隔离、且使用了的镜像文件做根文件系统的进程。如下图1所示:
1.jpg

图 1

由此可见,实现容器的三大核心技术分别是:

  1. Cgroups(Control Cgroups,控制群组):Linux中的Cgroups包含多个不同的子系统,如:CPU、memory、device等。通过这些子系统就可以对容器能够使用的各种资源进行限定,比如:通过CPU子系统可以限定容器使用CPU资源的相对权重和单位时间内能够使用的的CPU时间。
  2. Namespace(命名空间):Linux同样支持多个namespace,如:mount、network、pid等。通过这些namespace可以对容器进行不同维度的资源隔离,比如:通过mount namespace可以让容器具有自己独立的挂载空间,在主机或别的容器中发生的挂载事件对该容器就不可见,反之亦然。通过network namespace可以让容器具有自己独立的网络协议栈,而不必和其所在主机共用同一个网络协议栈。
  3. Layered filesystem(分层文件系统):Linux中的layered filesystem有多种不同的实现,如:AUFS、overlayfs等。通过这些layered filesystem配合mount namespace就可以快速部署出容器自己独立的根文件系统。而且,基于同一个镜像文件创建出来的多个容器可以共享该镜像文件中相同的只读分层,以达到节省主机磁盘空间的效果。

上面这三种技术都是在Linux系统中存在已久且相对成熟的技术,但让终端用户直接使用它们来创建和管理容器显然并不方便。所以,容器引擎就应运而生了,它所做的主要工作就是将这三种技术在其内部有机地结合和利用起来以实现创建容器和管理容器的生命周期,并对外提供友好的接口让用户能够方便的创建和管理容器。Cgroups、namespace和layered filesystem的详细介绍我就不再本文中赘述了,感兴趣的读者可以查阅Linux中这三种技术的相关文档。

需要指出的是,容器引擎对这三种技术的使用往往是有选择且可定制的,比如:用户可以通过容器引擎创建一个使用cgroups memory子系统但不使用CPU子系统的容器,这样的容器对内存资源的使用就会受到相应的限定,但对CPU资源的使用则不受任何限定。用户也可以创建一个使用mount namespace但不使用network namespace的容器,这样的容器就会有自己独立的挂载空间,但和主机共用一个网络协议栈。Mesos容器引擎在这方面的可定制化进行得非常彻底,除了上面所说的对cgroups子系统和namespace的定制之外,Mesos容器引擎还能够支持无镜像文件创建容器,这是其它容器引擎所不具备的。
#Mesos容器引擎产生的背景

在Docker如此流行的情况下,Mesos为什么还要坚持做自己的容器引擎呢?其实Mesos在很早期的版本就和Docker进行了集成,用户可以通过Mesos创建一个Docker容器,在内部实现上,Mesos agent会调用Docker的命令行和Docker engine通信,以让其创建Docker容器。这也就是意味着Mesos对容器的管理严重依赖于Docker engine,而这种做法的问题是:

  1. 稳定性不足:Mesos常常会被用来管理几千甚至上万节点的生产环境,而在如此大规模的生产环境中,稳定性是极其重要的。而在这样的环境中,通过实测我们发现Docker engine的稳定性是有所不足的,有时会出现停止响应甚至一些莫名其妙的bug,而这样的问题反映到Docker社区中后有时又无法及时得到解决。这就促使了Mesos的开发者开始设计和实现自己的容器引擎。
  2. 难于扩展:Mesos的用户常常会提出一些和容器相关的新需求(比如:让容器能够使用GPU资源,通过CNI配置容器的网络,等等),而这些需求都受限于Docker engine的实现,如果Docker社区拒绝采纳这些需求,或有完全不同的实现方式,那Mesos作为Docker engine之上的调用方也无计可施。

众所周知,Mesos的定位是数据中心操作系统,它是一个非常好的通用资源管理和资源调度系统,一开始就是一个“大脑级“的存在,但如果只有“大脑”没有“四肢”(对容器的支持就是“四肢”的一种),或“四肢“掌握在别人手中,那Mesos本身和其生态圈的可持续发展显然是受限的。所以,发展自己的“四肢”是Mesos逐步发展壮大的必然选择。

基于上述这些原因,Mesos社区决定要做自己的容器引擎,这个容器引擎完全不依赖于Docker engine(即:和Docker engine没有任何交互),但同时它又完美兼容Docker镜像文件。这也就意味着,用户可以通过Mesos在一台没有安装运行Docker engine的主机上,基于任意Docker镜像创建出容器。
#Mesos容器引擎的总体架构和核心组件

首先我们来看一下Mesos的总体架构,以及容器引擎在其中的位置。
2.jpg

图 2

上图2中蓝色部分是Mesos自身的组件,可以看到Mesos是典型的Master + Agent架构。Master运行在Mesos集群中的管理节点上,可以有多个(一般设置为三个、五个等奇数个),它们相互之间通过Zookeeper来进行leader选举,被选举成leader的master对外提供服务,而其他master则作为leader master的备份随时待命。Master之上可以运行多个计算框架,它们会调用master提供的API发起创建任务的请求。Master之下可以管理任意多个计算节点,每个计算节点上都运行一个Agent,它负责向Master上报本节点上的计算资源,并接受master下发的创建任务的请求,将任务作为容器运行起来。而Agent内部的一个组件containerizer就是用来管理容器的生命周期的(包括:容器的创建/更新/监控/销毁),它就是Mesos的容器引擎。

我们再来进一步看一下Mesos容器引擎内部的总体架构和核心组件。
3.jpg

图 3

如上图所示,Meoss容器引擎内部包含了多个组件,主要有:Launcher、Provisioner(其内部又包含了store和backend两个组件)和Isolator。下面来逐一介绍这些组件的主要功能和用途。
##Launcher

Launcher主要负责创建和销毁容器,由于容器的本质其实就是主机上的进程,所以launcher在其内部实现上,主要就是在需要创建容器时,调用Linux系统调用fork()/clone()来创建容器的主进程,在需要销毁容器时,调用Linux系统调用kill()来杀掉容器中的进程。Launcher在调用clone()时根据需要把容器创建在其自己的namespace中,比如:如果容器需要自己的网络协议栈,那launcher在调用clone()时就会加入CLONE_NEWNET的参数来为容器创建一个自己的network namespace。

Launcher目前在Mesos中有两种不同的实现:Linux launcher和Posix launcher,上面提到的就是Linux launcher的实现方式,Posix launcher适用于兼容Posix标准的任何环境,它主要是通过进程组(process group)和会话(session)来实现容器。在Linux环境中,Mesos Agent会默认启用Linux launcher。
##Provisioner

为了支持基于镜像文件创建容器,Mesos为其容器引擎引入了Provisioner。这个组件完成的主要工作是通过store组件来下载和缓存指定的镜像文件,通过backend组件基于指定的镜像文件来部署容器的根文件系统。
##Store

Mesos容器引擎中目前已经实现了Appc store和Docker store,分别用来支持Appc格式的镜像和Docker镜像,此外,Mesos社区正在实现OCI store以支持符合OCI(Open Container Initiative)标准格式的镜像。所以基本上,针对每种不同的镜像文件格式,Mesos都会去实现一个对应的store。而以后当OCI镜像格式成为业界容器镜像文件的标准格式时,我们可能会考虑在Mesos容器引擎中只保留一个OCI store。

Store下载的镜像会被作为输入传给backend来去部署容器的根文件系统,且该镜像会被缓存在agent本地的工作目录中,当用户基于同一镜像再次创建一个容器时,Store就不会重复下载该镜像,而是直接把缓存中的镜像传给backend。
##Backend

Backend的主要工作就是基于指定镜像来部署容器的根文件系统。目前Mesos容器引擎中实现了四个不同的backend:

  1. AUFS:AUFS是Linux中的一种分层文件系统。AUFS backend就是借助这种分层文件系统把指定镜像文件中的多个分层挂载组合成一个完整的根文件系统给容器使用。基于同一镜像文件创建出来的多个容器共享相同的只读层,且各自拥有独立的可写层。
  2. Overlay:Overlay backend和AUFS backend非常类似,它是借助Overlayfs来挂载组合容器的根文件系统。Overlayfs也是一种分层文件系统,它的原理和AUFS类似, 所以,AUFS backend所具备的优点Overlay backend都有,但不同的是Overlayfs已经被Linux标准内核所接受,所以,它在Linux平台上有更好的支持。
  3. Copy:Copy backend的做法非常简单,它就是简单地把指定镜像文件的所有分层都拷贝到一个指定目录中作为容器的根文件系统。它的缺点显而易见:基于同一镜像创建的多个容器之间无法共享任何分层,这对计算节点的磁盘空间造成了一定的浪费,且在拷贝镜像分层时也会消耗较大的磁盘I/O。
  4. Bind:Bind backend比较特殊,它只能够支持单分层的镜像。它是利用bind mount这一技术把单分层的镜像以只读的方式挂载到指定目录下作为容器的根文件系统。相对于Copy backend,Bind backend的速度更快(几乎不需要消耗磁盘I/O),且多个容器可以共享同一镜像,但缺点就是只能支持单分层镜像,且根文件系统是只读的,如果容器在运行时需要写入数据,就只能通过额外挂载外部卷的方式来实现。

在用户没有指定使用某种backend的情况下,Mesos Agent在启动时会以如下逻辑来自动启用一种backend:

  1. 如果本节点支持Overlayfs,启用Overlay backend。
  2. 如果本节点不支持Overlayfs但支持AUFS,启用AUFS backend。
  3. 如果OverlayFS和AUFS都不支持,启用Copy backend。

由于Bind backend的局限性较大,Mesos Agent并不会自动启用它。
##Isolator

Isolator负责根据用户创建容器时提出的需求,为每个容器进行指定的资源限定,且指引launcher为容器进行相应的资源隔离。目前Mesos内部已经实现了十多个不同的isolator,比如:cgroups isolator通过Linux cgroups来对容器进行CPU、memory等资源的限定,而CNI isolator会指引launcher为每个容器创建一个独立network namespace以实现网络隔离,并调用CNI插件为容器配置网络(如:IP地址、DNS等)。

Isolator在Mesos中有着非常好的模块化设计,且定义了一套非常清晰的API接口让每个isolator可以根据自己所需要完成的功能去有选择地实现。这套isolator接口贯穿容器的整个生命周期,Mesos容器引擎会在容器生命周期的不同阶段通过对应的接口来调用isolator完成不同的功能。下面是一些主要的Isolator接口:

* prepare():这个接口在容器被创建之前被调用,用来完成一些准备性的工作。比如:cgroups isolator在这个接口中会为容器创建对应的cgroups。
* isolate():这个接口在容器刚刚被创建出来但还未运行时被调用,用来进行一些资源隔离性的工作,比如:cgroups isolator在这个接口中会把容器的主进程放入上一步创建的cgroups中以实现资源隔离。
* update():当容器所申请的资源发生变化时(如:容器在运行时申请使用更多的CPU资源),这个接口会被调用,它用来在运行时动态调整对容器的资源限定。
* cleanup():当容器被销毁时这个接口会被调用到,用来进行相关的清理工作。比如:cgroups isolator会把之前为容器创建的cgroups删除。

借助于这种模块化和接口标准化的设计,用户可以很方便地根据自己的需求去实现一个自己的isolator,然后将其插入到Mesos agent中去完成特定资源的限定和隔离。
#Mesos容器引擎对容器标准规范的支持

容器这项技术在近几年来飞速发展,实现了爆炸式的增长。但就像任何一种成熟的技术一样,在度过了“野蛮生长期”后,都需要制定相应的规范来对其进行标准化,让它能够持续稳定地发展。容器技术也不例外,目前已知的容器相关的标准规范有:

  1. OCI(Open Container Initiative):专注于容器镜像文件格式和容器生命周期管理的规范,目前已经发布了1.0的版本。
  2. CNI(Container Network Interface):专注于容器网络支持的规范,目前已经发布了0.6.0版本。
  3. CSI(Container Storage Interface):专注于容器存储支持的规范,目前还在草案阶段。

标准规范带来的益处是显而易见的:

  1. 对于终端用户:标准化的容器镜像和容器运行时能够让用户不必担心自己被某个容器引擎所“绑架”,可以更加专注于对自身业务和应用的容器化,更加自由地去选择容器引擎。
  2. 对于网络/存储提供商:标准规范中定义的网络/存储集成接口把容器引擎的内部实现和不同的网络/存储解决方案隔离开来,让各提供商只需实现一套标准化接口就可以把自己的解决方案方便地集成到各个容器引擎中去,而不必费时费力地去逐个适配不同的容器引擎。

Mesos容器引擎在设计和实现之初,就持有拥抱和采纳业界标准规范的态度,是最早支持CNI的容器引擎之一,且目前正在积极实现对OCI镜像规范的支持。CSI目前正在由Mesos社区和Kubernets社区一起主导并逐步完善,待CSI逐渐成熟后,Mesos容器引擎自然会第一时间支持。日后,作为同时支持三大标准规范的容器引擎,Mesos容器引擎自然会更好地服务上层应用框架和终端用户,同时更加完善地支持各种主流网络/存储解决方案。

原文链接:Mesos容器引擎的架构设计和实现解析

作者:张乾,目前就职于Mesosphere,担任Mesosphere中国区研发负责人。国内首位Apache Mesos committer,专注于各种容器相关的开源技术。
Mesos是Apache基金会的顶级项目之一,致力于管理和弹性调度集群资源,成为新一代数据中心的操作系统内核。目前已在Twitter、Apple、Uber、Airbnb等公司的生产环境广泛使用。