Docker持续集成 之 Jenkins on Mesos 实践

开篇简要介绍几个基本概念。

Docker不多介绍,如果还不了解Docker推荐阅读 Docker定义 Docker入门教程 ,大神请忽略!

Mesos简介

20160715171249 20160715171249

Apache Mesos是一款开源集群管理软件。Mesos经过了Facebook,Twitter这些大型公司的万台主机验证,在国内,爱奇艺、去哪网,小米网等公司也拥有大规模的Mesos集群应用。Mesos实现了两级调度架构,可以管理多种类型的应用程序。第一级调度是Master的守护进程,管理Mesos集群中所有节点上运行的Slave守护进程。集群由物理服务器或虚拟服务器组成,用于运行应用程序的任务,比如Hadoop和MPI作业。第二级调度由被称作Framework的“组件”组成。Framework包括调度器(Scheduler)和执行器(Executor)进程,其中每个节点上都会运行执行器。Mesos能和不同类型的Framework通信,每种Framework由相应的应用集群管理。图中只展示了Hadoop和MPI两种类型,其它类型的应用程序也有相应的Framework。Mesos支持多种Framework,比如说Hadoop,Spark,Storm等等,各类型的Framework在它上面都可以运行。

Marathon简介

Marathon是Mesosphere为Mesos生态圈打造的一个轻量级管理服务APP框架,它可以用RESTful API方便地进行操作。

Marathon 协调应用和Frameworks

下图是在Marathon上发布各种的服务,它们都可以通过Marathon发到Mesos的集群资源中。

20160715171627

Jenkins简介

介绍

Jenkins是Java开发的一种持续集成的工具,我们在它的基础上做了一些重复的工作,比如版本发布、测试代码,以及调用外部接口。Jenkins支持很多插件,可以很方便地选择使用适合自己团队的插件工具。

Jenkins On Mesos

Jenkins 分为Master 节点和Slave 节点,Master 进行调度,Slave节点负责负责执行Job任务。

问题

Jenkins为我们提供了便利,当然Jenkins本身也有它自己的问题,比如传统的Jenkins是单点的,任务大多是需要排队的,如果每个任务都自己建一套Jenkins的话,资源会非常浪费。为了解决这些问题,我们引入了Jenkins On Mesos。

Jenkins Slave

20160715171746

Jenkins Master做的是调度,Jenkins Slave则是真正执行构建任务的地方。Jenkins Master会在Mesos Master上注册一个它自己的Framework,如果有任务需要构建的话,Jenkins Master 会通知 Jenkins Framework 调用 Mesos Master构建一个任务。之后Mesos Master 再调用 Mesos Slave去起一个Jenkins Slave的节点去构建任务,它是实时的,用户资源可能被分配到各个机器上,在不同的机器上并行存在。此外,Jenkins还具备动态调度功能,也就是说,当任务运行完后一定时间,资源会再返还给Mesos,实现合理地利用整个集群的资源,提高集群的资源利用率。

Jenkins master

20160715171736

首先我们把Jenkins的Master通过Marathon发布,Marathon 去调用 Mesos Master,之后Mesos Master再去Slave节点起Jenkins的Master。这个机制保证了Jenkins Master的高可用,Marathon会监控Jenkins Master的健康状态,当Jenkins Master出现崩溃挂掉,Marathon会自动再启动一个Jenkins Master的任务。Jenkins Master使用Mesos整个大的资源池,Mesos的资源池是一个资源共享的状态,资源利用率也会更高一些。

Mesos 整体流程
20160715171939

这张图是Mesos整体的调度流程。第一步,它的集群有三个Mesos Slave节点资源,资源上报到Mesos Master,Mesos Master收集到这些资源之后把这些资源再提供给Marathon,Marathon如果要发任务,它确认一个Offer1,Offer1足够任务来运行,就拒绝其他的Offer,并把这个任务发送给Mesos Master,之后Mesos Master去找Slave1起Marathon的任务。这是Marathon的任务启动过程。Mesos本身可以和多框架进行通信,Jenkins Master要跑一个任务,Mesos Master同样提供资源给Jenkins,提供的资源包括了Marathon 任务使用剩下的资源,比如Task1 确认的 Offer1没有用完和没有使用的资源,Mesos也会它提供给Jenkins。而Jenkins也会选择,比如Jenkins选择了Offer3,拒绝了其他的Offer,把Jenksin的任务再通过Mesos Master去Mesos Slave中起起来。

Jenkins On Mesos Docker

Jenkins部署起来非常麻烦,需要安装各种依赖,如果代码是从Git上下载的,那么还需要安装一些Git包。而动态调度需要每台机器上都装这些依赖,为了解决这种问题,我们把服务全部进行了Docker化,主机上只需要有Docker环境就可以运行我们的服务。

遇到的坑

我们遇到的第一个问题是Jenkinson Mesos需要调度Mesos的Lib库,如果Docker化之后是隔离的,就调不到Mesos Lib。

进行Docker化之后就会面临Docker化的问题,因为Docker和 Mesos都是比较新的技术,我们遇到了很多坑,也需要去解决。

第二个问题是Jenkins需要升级,插件也需要升级,而镜像本身没办法自动升级。

第三个问题是Docker化的数据,因为Jenkins是没有数据库的,数据都是存在本地的JENKINS_HOME目录中,如果Jenkins Master挂掉之后,相应的数据就没有了。

解决

为了解决这些问题,首先我们将Mesos打成一个基础镜像,在这个基础镜像上安装Jenkins的服务制作成一个Jenkins的镜像,这样就可以调用Mesos的Lib库文件了。

第二是数据备份,我们在Jenkins上安装了一个插件,就是SCM Sync Configuration Plugin 这个插件,它会同步数据到Github。如果这个Jenkins Master挂掉了,迁移到另外一台主机上,它会从Github上面把数据克隆下来,数据是不会丢失的。此外,如果插件出了故障,或者因为网络问题导致Github访问不了,我们把JENKINS HOME目录挂在主机上进行备份,进行恢复的时候也会很方便。用以上这两点来保证数据的完整性。

第三对于Jenkins升级或其插件的升级,我们现在的做法是把它重新打一个镜像,重新在Mararhton发布Jenkins Master。

Jenkins Job List

20160715172618

这是我们运维平台一些Job List,左下角是Mesos各个Slave的节点,每一个节点上都有任务,这些任务都是并行的。因为我们的服务模块比较多,可能一个模块一天提交十几次,这么多的模块在一天提交几十次或者上百次的情况也出现过。手动更新、构建的话是非常难做到的。现在,做成Jenkins 分布式执行Job的模式,一天构建几百上千次也没有问题,它会把构建的任务均匀的分布在主机资源里。

Jenkins Slave On Docker 工作流程

20160715172610

首先Jenkins Master如果要构建一个Job,让Mesos Slave起一个Jenkins Slave这样的容器,容器里面是没有Docker环境的,因为容器里面再装一个Docker环境就太重了。我们现在的做法是把Jenkins Slave用到的命令挂载,其中包括 /usr/bin/docker /var/lib/docker /sys/fs/cgroup /var/run/docker.sock ,这样在容器内部就可以操作主机上的Docker环境,Jenkins Slave 可以在容器内部进行一些Docker Build,Docker Run,Docker Push等工作。

数人云运维平台持续集成实践

 

20160715172631

数人云运维平台的持续集成实践。首先讲几个组件,比如Github,它是存储代码的,第二个组件是我们自己开发了的一个Configserver的API,第三个组件是Jenkins和Marathon。第四个组件是我们的私有Registry,是Docker的一个存储镜像的镜像仓库。最右下角是CDN,安装包传送到达的地方。

首先Jenkins触发任务,Jenkins调用Configserver提供的API,这个API就去Github上获取最新代码的Tag,并对比现有的已经更新过的Tag。如果不需要更新,这个任务就完成了,结束了。如果需要更新的话,就进行第三步,把从Github拉的代码放到Configserver上,Jenkins Slave的节点会从Configserver去拉取代码到Slave的容器之中。把代码下载之后再去Pull一个我们编译环境的镜像,然后再用这个镜像去编译我们的代码。比如编译出来一个二进制代码,我们把这个二进制重新打一个运行时的镜像。这个Runtime镜像打好之后我们再使用Docker Push把它推到私有的Registry,镜像Push到Registry后,就可以发布到各种的环境,比如说Dev Demo生产环境,调用Marathon API直接发布就可以了。同样在Jenkins Slave,推完镜像之后就可以去调用。这样一个整体构建镜像再部署的任务就构建完成了。

如果有一些安装包,比如我们的Agent包,它不需要发布Marathon,需要上传到CDN,也是在Jenkins Slave 中执行的。

配置管理

问题

因为我们引入了Docker,而且是分布式动态调度的,传统的配置工具如Ansible、Puppet 、SaltStack都已经不适用了,没办法去管理Docker内部的东西。这些配置文件修改起来非常麻烦。

配置中心一期

20160715172645

讲一下如何进行配置的更新。首先我们做了一个配置中心的一期,把镜像嵌入自己的脚本,这个脚本实现的功能就是 根据传入的ENV CONFIG_SERVER和 SERVICE ,访问 Configserver的API,API返回的数据就是这个服务需要下载的配置文件的列表,以及它需要下载到哪个目录底下。Configserver也非常简单,起一个Nginx,去Vim手动修改。容器一重启,就会自动拉这些配置文件,把配置进行更新。

 

配置中心二期

20160715172657

为了解决这些问题,我们做了ConfigCenter的二期。其中有我们自己开发的一个运维平台,以及Github和Gitlab。Github是个存储项目的代码,Gitlab是用了存储配置模板和最终配置文件的。我们用Jenkins把它们整体的串起来,我们的第一个工作是把所有的配置文件抽象化,各种环境的文件抽象出来一个模板,放在Gitlab上。它的数据是放在数据库里面,这样组合起来是一个完整的配置文件。各个环境的值是不一样的。 我们的运维平台触发Jenkins,Jenkins去调度我们的ConfigCenter API,它传入两个参数,一个是需要更新的环境,第二个是更新哪个服务。之后API去做对比,从数据库去读现有的配置文件的模板Tag,再去读新模板的Tag进行对比。如果这个文件需要更新,把它从数据库拉过来,数据做匹配,渲染成我们最终的配置文件,再传到Gitlab上。剩下的通过Jenkins 触发 Configserver去调Gitlab下载最新的配置文件到Configserver服务器,Jenkins再去调用Marathon去重启服务,服务就会成功更新配置文件。

 

 

K8S中文社区微信公众号
分享到:更多 ()

评论 抢沙发

评论前必须登录!