您的位置:首页 > 运维架构 > Docker

基于OpenStack+Docker设计与实现CI/CD——基于Docker技术的CI&CD实践

2017-07-03 10:49 726 查看


摘要

Docker技术应用广泛,可以将软件与其依赖环境打包起来,以镜像方式交付,让软件运行在“标准环境”中。这一特性可以应用到持续集成中,实现原生支持容器云平台持续交付。本文将概述CI&CD基本工作流程,软件整体框架以及实现原理。


背景概述

持续集成是一种软件开发实践,即团队成员经常集成他们的工作,每次集成都需要通过自动化的构建,包括编译、发布、自动化测试来验证,从而尽早的发现集成错误。持续交付是指频繁地将软件新版本交付质量团队或者用户以供评审,如果评审通过,发布到生产环境。

Docker是一款基于LXC的容器引擎,自2013年开源以来,因为其易用性、高可移植性在开源社区非常火热。Docker将软件与其依赖环境打包起来,以镜像方式交付,让软件运行在“标准环境”中,这非常符合云计算的要求。各大IT巨头纷纷跟进,基于Docker容器技术创业公司也如雨后春笋,Docker创造了一个崭新的容器云行业。

Docker技术应用广泛。如,利用其隔离特性,为开发、测试提供一个轻量级独立沙盒环境进行集成测试。加速本地开发和构建流程,使其更加高效轻量化,开发人员可以构建、运行并分享容器,轻松提交到测试环境中,并最终进入生产环境。Caicloud Circle正是基于Docker这一特性打造的一款容器原生持续集成持续交付Saas产品。




CICD基本流程

Circle提供丰富的rest API供web应用调用;

通过API建立VCS与Circle服务关联后,VCS上的commit等动作会触发Circle构建;

VCS Provider组件从VCS拉取代码库中源码;

基于源码中配置文件CI配置启动需要的CI微服务容器进行集成测试;

集成测试通过后,进入Pre Build阶段在指定编译环境容器中编译可执行文件;

Build阶段中将可执行文件拷贝到指定运行环境容器中,打成镜像推送到Registry中;

Post build阶段会做一些镜像发布后的关联操作,比如推送运行依赖的静态资源文件到CDN中;

镜像发布后可以自动部署应用到Caicloud、K8s、Mesos、Swarm等Paas平台;

构建过程日志可以通过LogServer拉取;

构建结束构建结果可以发邮件通知用户。




整体框架

Circle整体框架如下图所示。Circle运行在容器中,与kafka-zookeeper容器集群通信推送拉取构建过程日志,基础数据信息存储在mongo数据库容器集群中。在Circle内部:API Swagger组件提供在线Circle API说明帮助文档;API Server组件接收用户http请求,生成异步待处理事件记入Async Event Manager组件的事件队列中,并应答用户请求;Async Event Manager组件在检测到新的待处理事件创建后,根据事件具体操作类型调用CI&CD组件提供的工具函数组装拼接成工作流水线,检测到事件完成后更新数据库中文档记录;在容器外运行一组Docker
Daemon队列,各工作流水线独立使用一个Docker Daemon,以实现用户和事件隔离;CD&CD组件会从Docker Daemon Queue中调度取出一个空闲Docker Daemon执行流水线任务,过程日志推送到Kafka指定的topic中;Log Server组件向用户提供一个获取日志的Websocket服务器,从Kafka拉取实时日志推送给用户。

Circle也可以多节点分布式部署,部署图如下所示。每一个立方体代表一个节点,使用Haproxy反向代理实现负载均衡和SSL数据加密,分发API请求到各Circle节点中。




实现原理

在web页面通过OAUTH用户授权拉取用户VCS版本库列表,选择建立与指定版本库相关联的服务。如果VCS使用的git还能调用git API建立webhook,当版本库产生commit、tag、pull request等事件时调用Circle API触发CI&CD。



Circle CI&CD的具体各步骤操作定义在代码库caicloud.yml文件中。分为integration、pre_build、build、post_build、deploy五段。Circle从代码库中拉取文件后,解析caicloud.yml文件,依配置执行具体操作。

integration段执行集成测试,yaml文件中定义了编译可执行文件使用的语言镜像名,运行使用的环境变量,启动指令(可以运行一些测试脚本、测试应用),以及集成测试依赖的微服务容器配置。首先使用Docker remote API调用分配的Docker Daemon启动依赖的微服务容器;然后启动集成容器编译可以文件,执行命令行,完成后容器退出,返回命令行执行结果码标示集成结果。



prebuild段执行编译工作,可以使用Dockerfile也可以使用yaml的K-V值。Yaml文件中可以定义构建使用的Dockerfile路径文件名,prebuild容器启动的基础镜像、环境变量、启动命令行以及编辑结束后,需要输出的可执行文件夹或文件名,如果Dockerfile和容器配置同时被定义,优先使用Dockerfile。CI&CD首先解析指定的Dockerfile或者yaml文件内容,获取容器启动配置,依配置调用容器,执行命令行编译可执行文件后退出容器,如果编译成功,使用Docker copy API拷出指定的输出文件。



在build段中基于指定的Dockerfile构建发布镜像。在该Dockerfile中可以添加prebuild段中输出的可执行文件到发布环境中。Prebuild和build的分步操作实现了软件编译环境与软件运行环境的隔离。构建完成后push镜像到指定的镜像仓库中。



Post build段可以定义一些镜像发布后的关联操作。比如用户可以制作一个包含程序运行依赖的必要静态资源的镜像,在Post build阶段以该镜像启动容器,并通过执行命令行推送到CDN中。



发布完成后进入部署阶段。用户在web界面预先配置好部署方案,指定集群分区应用和容器名,Circle会调用集群提供的应用部署API,将构建好的镜像部署应用中,并查询部署状态,如果失败回滚到上一个成功镜像。




一些亮点feature

a) 多Docker Daemon构建实现用户事件隔离

作为服务器不会在同一时刻仅处理单一请求,在同一节点上同时运行的事件任务可能会相互影响。Circle采用多Docker Daemon隔离实现用户事件隔离。在节点上运行一组Docker Daemon队列,调度分配给单一事件任务使用,使用完成后清理残留容器和镜像,确保构建环境整洁。队列元素个数有限,当没有空闲Docker Daemon时事件任务进入排队等待状态,等待超过2小时,事件任务超时失败。当用户需要取消构建时,仅需kill正在执行当前构建任务的Docker Daemon,然后重启一个新的Docker Daemon加入到空闲队列中。

b) 微服务多模块联合发布

微服务正在博客、社交媒体讨论组和会议演讲中获得越来越多的关注。微服务架构是一种特定的软件应用程序设计方式——将大型软件拆分为多个独立可部署服务组合而成的套件方案。为了管理微服务多模块间的依赖管理,联合集成发布多个模块,Circle实现了联合发布功能。

首先建立多个与单一模块代码库代码关联的服务;然后通过UI拖拽方式设置多个服务间的树形依赖关系,Circle将树形关系转化成线性发布序列存储。当用户点击一键联合发布时,Circle将同时启动多条CI&CD流水线对多个模块分别进行集成测试和构建(Integration+Prebuild+Build+Post Build操作),所有模块构建都完成后依存储线性发布序列依次部署到容器集群应用中(Deploy操作)。



c) 镜像安全扫描

常见的文件分析方法有两种:静态分析和动态分析。我们采用的是静态分析,检阅镜像的文件系统。漏洞是从Linux操作系统的通用漏洞披露(CVE)数据库获取。




今后工作展望

a) 运维

目前Circle实际部署采用的多节点分布式部署方式,各节点上使用Docker compose运行各容器,升级运维都比较麻烦,需要SSH连接到各节点上命令行操作。我们计划近期将Circle部署到Caicloud CLaas技术栈,运用Kubernetes强大的运维功能提高Circle的生产效率。可能会对现有框架做些改造,目前思路如下:



每个立方体表示一个pod。使用nignx做反向代理,TLS加密;Circle-Master中API-server组件向web提供API服务,Log-server组件提供实时日志服务,当调用API构建,会到新建一个构建任务发送给Worker manager组件,Worker manager记录任务信息到etcd中,并新建一个Circle-Worker pod执行任务;Circle-Worker中有之前的CI&CD组件,依次启动容器执行Integration、Prebuild、Build、Post Build和Deploy,中间过程日志推送到Kafka,任务状态同步到etcd,任务结束后pod退出;各组件需要持久化的信息写入mongo。

b) 并发

CI&CD任务需要占用大量的系统资源,Circle服务器资源有限,如何才能支持大量并发的构建任务?我们的思路是可以让用户添加自有工作节点到Circle集群中,由Circle来调度CI&CD任务管理逻辑,由用户自有工作节点来承载执行任务的运算负荷。将CI&CD流水线部分拆分出来,基于Docker in Docker镜像打包制作成Circle-Worker镜像。用户在自有机器上安装运行Docker后,将Docker remote API地址以及机器资源配置告知Circle,Circle验证机器有效性后将该机器拉入集群中。当该用户有需要执行的CI&CD任务时,调度用户节点运行Circle-Worker容器从Circle获取任务信息并执行,完成后返回结果。

QA

Q:感谢分享,请问你们选用circle的而不是jenkins原因吗?个人感觉jenkins还是比较强大的,尤其是它丰富的插件

A:我们目的是研发一套基于容器云原生的CI&CD平台,以便于更好支持今后对接容器集群部署应用和应用管理。

Q:您好!感谢分享,受益匪浅,想请问教:用户在自有机器上安装运行Docker后,将Docker remote API地址以及机器资源配置告知Circle,Circle验证机器有效性后将该机器拉入集群中。这里既然已经手动安装运行了docker还需要做哪些来验证机器有效性?

A:还需要做哪些来验证机器有效性:比如验证docker daemon是否正常运行,安全证书等。

Q:感谢分享,由于CI会涉及到不同的(开发,测试等等)环境,那么对于不同环境的自动编译和部署可能处理机制不同,可以通过同一个yml去定义和识别么

A:没错,整个CI会涉及不同的环境,正是因为环境的问题,也是我们采用容器技术原因之一。在不同的环境上部署同一个容器镜像,确实也会有不同的环境特殊配置,比方说数据库地址,这个时候需要外部来解决配置管理的问题,我们整个容器解决方案中包含配置中心,以环境变量和文件挂载的方式来解决此类问题。

Q:请问:如果使用环境镜像进行编译,那么最终编译后的镜像大小会不会因为有大量的依赖包而很大?

A:不是很清楚您指的环境镜像是什么,最终编译生成的镜像大小基本与应用使用的编程语言、依赖的中间件和本地其它依赖库或文件。

Q:问下代码包是放到镜像里还是放到宿主机上,如何解决镜像分发慢的问题?

A:代码下载到宿主机再挂载到容器中编译可执行文件,完成后从容器中拷出可执行文件,打包到发布环境镜像中。我们在宿主机上有运行一个proxy registry用于加速拉取镜像。宿主机拉取过的历史镜像会缓存在本地proxy registry,下次拉取时先从本地拉取。

【总结】本文所述内容的背景是,基于Docker容器技术的OpenStack研发、测试、运维及其相关的CI/CD、DevOps等活动。思想是相通的,读者可以取其可用部分用于自己的业务需求中。

IaaS云和容器云不是可有可无、相互竞争的关系,而是相互弥补彼此缺陷的关系。容器改变了应用部署和管理的模式,众所周知,IaaS云通过提供基本的计算、存储和网络来运行虚拟机(VM),在IaaS(基础设施即服务)之上,还有PaaS(平台即服务)、SaaS(软件即服务)、CaaS(容器即服务)。OpenStack作为一个IaaS云的基础设施管理平台,为用户提供了创建VM和其他资源的服务,至于具体怎么用这些虚拟机、怎么运行业务应用,如Hadoop大数据、Docker微服务、CI/CD工具链、Cloud Foundry等,用户自己可以按需使用。

Docker的整个生命周期阶段,主要分为:
Build——使用Dockerfile文件或手动方式生成镜像。
Push——将构建好的镜像上传到镜像仓库中。
Pull——从镜像仓库中拉取镜像到使用环境中。
Run——启动镜像为容器服务。
Stop/Remove——停止或删除容器、镜像。

Docker适用于CI/CD的场景,主要是基于:
Docker容器是把应用程序和环境打包在一起的,所以是一次构建,处处运行。比如,当开发人员变更代码后,测试人员和运维人员只需要执行停止旧容器、启动新容器这两个步骤即可。因此,Docker最大的好处就是标准化了应用交付,只要系统能运行Docker,就能无差别地运行应用。
Docker镜像统一封装了软件服务及其依赖环境,可以让镜像成为一个标准的软件交付物。
容器比虚拟机运行效率更高,在开发测试工作日益繁重的CI/CD环境中,Job任务运行的速度是至关重要的。
通过容器云平台如Kubernetes,可以方便地实施集群和容器管理。相关技术也日趋成熟,生态环境丰富。

不同于其他软件应用,OpenStack有着自身固有的特点,既有众多优势,也存在对研发测试带来的诸多挑战。如何运用有效的方法,才是解决问题的关键所在。


一、OpenStack和Docker集成现状

Docker是一种集Namespace、Cgroups等技术于一体的容器技术,可以将应用和环境等进行打包,形成一个独立且隔离的环境,让每个应用彼此相互隔离,并在同一台主机上同时运行多个应用,进行更细粒度的资源管理。Docker和VM(虚拟机)的区别如下图所示:



工欲善其事,必先利其器。Docker是一种具体的容器技术,虽然以REST API形式提供服务,但在实际生产环境中管理大规模集群的Docker镜像和容器仍然是一个巨大的挑战。开源软件项目的成功往往根据其催生的生态系统来衡量,使其日臻完善。

1.Kubernetes

谈论Docker管理,自然不能不提及Kubernetes,这是谷歌开发的一款开源的Docker管理工具,用于跨主机集群部署容器。Kubernetes还提供了让容器彼此互通的方法,不需要手动开启网络端口或执行其他操作。它提出两个概念。
Pods:每个Pod都是一个容器集合并部署在同一台主机上,共享IP地址和存储空间,比如将Apache、Redis之类的应用分为一个容器集合。
Labels:提供服务标签,方便Pod容器之间的调用协作。

2.Docker Compose

Docker Compose 是容器编排工具,让用户可以自定义容器的镜像、容器之间的依赖关系等。定义好这些信息之后,只需要一条命令就可以按照顺序启动容器,然后整个应用就部署好了,这对于自动化来说是一个很好的进步。对于应用编排来说,Compose是一个非常不错的选择。

3.Docker Machine

Docker Machine是一个便捷的容器创建工具,即从0到1地安装Docker,极大地简化了安装过程。使用docker-machine create命令,参数-d指定虚拟化的驱动,即可在相应的平台上创建Docker。

4.Docker Swarm

Docker Swarm 是Docker的集群管理工具,能够通过Master/Slave 的方式管理跨主机的Docker,为Docker集群化部署提供了非常好的支持。

5.Docker Datacenter

Docker Datacenter 是Docker的自动化集群管理工具,并非第三方工具,它其实是一个基于Docker的管理平台。

6.Apache Mesos

Mesos的名气比较大,基于它可以做很好的扩展,开发个性化的Docker集群管理工具。

7.Marathon

Marathon是一个与Mesos结合在一起的Docker集群管理工具,支持在Mesos之外调度容器。

8.Panamax

在众多的集群管理工具面前,如何管理单机的Docker容器也是一个需要解决的问题。因为Docker占用资源少,在单机服务器上部署成百上千个容器也是可能的。Panamax提供了人性化的Web管理界面用来安装软件,让部署变得更简单。并且,Panamax还提供了丰富的容器模板,让在线创建服务成为可能。所有的操作都可以在Web界面上完成,开发者只需要关注开发应用即可。

9.Tutum

Tutum提供了一套非常友好的Dashboard界面,支持创建Docker容器的应用。

10.Harbor

使用Harbor可以管理大规模的Docker镜像,以及基于同步复制功能的HA主备高可用性、细粒度的角色权限和项目管理。

除此之外,还有一些Docker性能监控工具,如Docker Stats、CAdvisor、Scout、Data Dog以及Sensu等。

11.OpenStack集成Docker项目

OpenStack社区为了集成Docker做了很多努力,如开发了Nova+Docker Driver、Heat+Docker Driver等模块,但都存在诸多不足。为了能更好地与Docker集成,社区陆续开发了几个新项目,如Magnum、Murano、Solum和Kolla等。

目前,Kolla是OpenStack集成Docker最火热的一个项目,将大部分的OpenStack服务Docker容器化,便于安装部署升级。其他的如Magnum,则提供了CaaS(容器即服务),Solum、Murano和Docker有些关系。但Solum更偏重于CI/CD,可以理解为一个应用软件的持续集成/持续交付环境,Murano是一个App Store,Solum可以将开发的应用发布到Murano中。


二、基于OpenStack+Docker设计CI/CD

目前,在Docker容器中部署和运行OpenStack云计算服务,已成为主流趋势之一。基于这样的背景,设计和实现OpenStack+Docker环境下的CI/CD应用便成为了必然。

在IT企业中,当我们面对以OpenStack为代表的云计算+以Docker为代表的容器技术这两种可用的基础设施平台时,如何利用二者的关系为产品研发测试带来效益,是至关重要的。对于竞争激烈、快速革新的互联网企业而言,持续创新及快速交付服务是其打造产品核心竞争力的重要因素之一。特别是在产品设计、功能实现、快速发布到可视化管理等方面,无疑都需要自动化测试、敏捷开发、持续集成(CI)和持续交付(CD)等方式进行高效支撑。其中,产品开发和自动化测试等重要环节,对环境的执行能力都提出了更高的要求。

我们深知,仅仅有一些方法和工具是不够的,真正给产品开发带来价值的,是如何完成产品的敏捷创新、降低风险,并根据市场反馈及时变更产品等。在这方面,OpenStack社区的做法是成功的。当然,我们可以借鉴其优势,将其引入到自己的业务环境中。在开发阶段,通过CI对项目进行持续集成、自动化编译和测试,以达到控制代码质量的目的,持续提升开发效率,同时在交付阶段,利用CD帮助在短周期内生产有价值的产品,并且保证能够在任何时间进行发布。

设计与实现基于OpenStack云计算+Docker容器技术的CI/CD服务,其核心是在OpenStack IaaS云计算平台上创建虚拟机,实现基于OpenStack研发测试业务背景下的CI/CD服务。

这里涉及三个重要组成部分:一是基于原生OpenStack研发的云计算产品,以及基于OpenStack基础设施平台构建的CI/CD服务;二是包括诸如Jenkins、GitLab、Gerrit、Harbor等系统在内的CI/CD应用;三是将OpenStack每个服务容器化,并使用Kolla方式部署。

基于云服务的CI/CD服务,可以实现弹性伸缩和横向扩展等。本节将以案例方式进行实践,如下图所示:



首先在物理服务器上搭建好OpenStack IaaS云平台,以及创建数台可用的虚拟机等,以备后续使用。

建议:在生产环境中,通过创建并挂载云硬盘到虚拟机中运行的服务数据目录下,或者通过rsync同步备份数据的方式,以保证数据的高可用性和完整性。对于CI/CD系统的HA(高可用性)等,可以通过计算节点HA或虚拟机HA的方式实现。

所用到的持续集成和持续交付平台如下表所示:
系统IP地址用途
Jenkins172.16.71.235持续集成系统,是整个CI/CD环境的核心任务系统
Jenkins_slave+Tempest172.16.70.199Jenkins Slave节点,用于执行具体的Job任务
GitLab172.16.71.236代码仓库托管系统
Gerrit172.16.71.118代码评审系统
Harbor_test172.16.71.221Docker镜像管理测试系统(Registry)
Harbor_devel172.16.71.222Docker镜像管理开发系统(Registry)
OpenStack all-in-one172.16.71.230OpenStack单节点环境
在实际的企业研发测试和CI/CD环境下,建议使用三个Harbor系统并相互关联,一个是开发系统,用于存放和管理平时开发人员上传的开发Docker镜像,该系统允许存放同一个镜像的不同副本(tag);一个是测试系统,用于存放经过了CI/CD流程验证测试的Docker镜像;一个是生产系统,用于存放发布的Docker镜像,其产出物便是用于交付的最终产品。


2.1 基于Docker的软件持续交付

目前,Docker容器已经在IT软件生产的各个环节中得到了大量的推广和使用,如从软件开发,到持续集成和持续交付,再到生产环境上的微服务应用等。除了Docker技术本身的发展以外,还不断涌现出一系列与容器相关的生态应用,包括容器编排、高可用性、运维监控和日志收集等各个方面。

在基于容器的持续交付实现当中,以镜像为内容传递的单元,通过CI(持续集成)的测试以及验证,完成镜像从开发、测试到可发布的状态转变和软件的交付流程,如下图所示。



开发人员:编写和提交代码,从提交代码起,这一过程均自动化完成,完成所属范围的工作内容,负责输出待测试的镜像。
测试人员:编写测试用例,手动或自动部署环境,执行各种测试,完成所属范围的工作内容,负责输出预发布的镜像。
运维人员:将预发布的镜像部署到预生产环境中,执行验收测试,完成所属范围的工作内容,负责生产环境的部署和运维。

1.持续集成和持续交付流水线

建立持续集成和持续交付流水线的核心问题是如何定义企业的软件交付价值流动。价值流动涉及各个职能团队的高度协同,在以镜像作为不同职能团队之间的价值传递物当中,其基于容器的CI/CD流水线的设计应该遵循如下一些基本原则。
可视化:流水线的运行和停止、成功与失败应对所有人直观可见,以掌握全局变化。
信息反馈:流水线应通过邮件等多种手段,及时将失败信息传达给相关团队成员。
可控制:从开发到生产发布总有一些环节需要人手动验证,比如回归测试、环境配置等,也就需要流水线在某些环节可以暂停,等待手动继续。
门禁:流水线中任何一个环节失败,都应该让流水线停下来,并通知团队解决,比如自动化测试不通过、代码或镜像构建失败等。

持续集成和持续交付(CI/CD)流水线的建立,主要包括开发流水线、测试流水线和生产运维流水线3种,如下图所示:



(1)开发流水线

开发人员:频繁提交代码,通过持续地编译、打包、测试、镜像构建和自动化测试等环节,产生可测试的候选镜像列表(如0.1-dev)。
以源码仓库为起点,开发人员频繁提交代码,每一次代码变更都要立即在流水线中传递;Jenkins持续集成平台支持定时周期触发、代码变更检查以及Webhooks等多种触发方式。
手动测试阶段,当新的代码提交部署到环境中后,开发人员可以快速地进行手动测试,确保新提交的代码在测试环境中是可用的,并且满足相关的功能需求。
自动化测试阶段,该阶段主要是使用JUnit、Pytest、Selenium、Cucumber等自动化测试框架进行单元测试、功能测试等一系列的自动化测试,同时还可以根据需要在持续交付流水线中集成Sonarqube进行代码的质量跟踪和管理。
镜像构建,当所提交的代码通过了整个流水线的持续验证后,就会产生相应版本的Docker镜像。

基于流水线中的持续验证和代码质量数据,团队可以快速处理典型的代码质量问题,避免累积。总而言之,开发流水线可以帮助团队频繁地进行代码集成并通过单元测试、代码静态分析、自动化测试等,有效帮助开发人员及时发现和解决问题,最终输出待测试的镜像列表。

(2)测试流水线

测试人员:从候选测试镜像列表中选择需要测试的目标镜像,标记为测试版本(如将0.1-dev标记为0.1-test),并且将待测试镜像自动部署到验收测试环境中进行测试,对于测试通过的镜像标记为预发布版本(如将0.1-test 标记为 0.1-beta)。

测试阶段,从功能交付断言整个系统是能够满足需求设计或客户规范的,该阶段会进行一系列的手动或自动化测试,同时基于容器技术解决异构环境下的依赖问题。

对于测试人员而言,流水线的起点则变为待测试的镜像列表,基于Jenkins创建类似的流水线,可以支持测试人员快速创建测试环境,并且运行相关的自动化测试脚本,同时满足手动探索性测试的需求。

(3)生产运维流水线

运维人员:从预发布镜像列表中选择镜像部署到预发布环境中,在验证通过后标记为release版本(如将0.1-beta 标记为 0.1-release),最后发布到生产环境中。

与自动化测试流水线相同,运维人员可以建立独立的部署流水线,从待发布的镜像列表中选择镜像发布到生产环境Registry中,并且设置流水线的自动或者手动触发,实现预生产环境的一键部署。


2.2 基于OpenStack+Docker的应用部署

Docker产生应用镜像有两种办法:一种是启动一个基础镜像(比如基于CentOS的Linux镜像),然后在容器中执行各种命令来安装相应的软件包,进行配置后,再通过Docker commit命令把已经更新的容器保存为相应的镜像;另一种方法则是通过编写Dockerfile文件,然后使用Docker build命令自动化构建相应的镜像。

相比第一种手工方式,通过Dockerfile文件的方式可以更好地维护镜像,并将Dockerfile 提交到版本库进行管理。并且通过CI/CD系统的自动化build、push、pull、run等工作流,可以与研发测试业务更紧密地结合起来。维护的不再是一条条零散的命令,而是一个文件集合。这样,Dockerfile文件便如同代码一样,做到随时维护修改和协作开发。

将所有的源码存放在私有仓库GitLab中,Docker镜像则托管在私有Registry中,并使用诸如Ansible之类的自动化工具将容器部署到服务器环境中,这些都是一个完全自动化的过程。Docker典型的应用场景包括:

1.测试

Docker很适合用于标准化场景中,将Docker封装后直接提供给测试人员进行环境搭建与部署,不再需要与运维、开发人员进行协商。同时,还可以很容易地将测试数据与应用服务分离,根据不同的测试场景随时进行镜像—容器切换。

2.开发

开发人员使用同一个Docker镜像,同时修改的源代码都挂载到本地磁盘上,然后映射到容器中。不再为因为环境的不同而造成不同的程序行为而伤透脑筋,同时新人到岗时也能迅速建立起开发、编译环境。

3.PaaS云服务

Docker可以支持命令行封装与编程,通过自动加载与服务自发现,可以很方便地将封装于Docker镜像中的服务扩展成云服务,根据业务请求的规模随时增加或减少容器的运行数量,实现弹性伸缩和横向扩展。


2.3 基于OpenStack+Docker的CI/CD流程设计

构建基于OpenStack+Docker云平台研发测试用的CI/CD系统,其核心组件包括:Jenkins持续集成系统、GitLab代码仓库管理系统、Harbor私有镜像仓库管理系统、Gerrit代码评审系统等。

基于OpenStack+Docker的CI/CD任务分解和流程设计步骤如下图所示。



①开发者准备好一个单节点环境,将开发工具链接到远程开发目录,并使用Git将代码提交到代码评审系统Gerrit中,目的是通过协作发现一些明显的问题,减少把Bug带到软件中的概率。

②当Jenkins持续集成系统检测到Gerrit系统的代码提交事件后,触发相关的Job任务,自动化执行代码编译、打包、构建、部署和测试等工作流。相应地,会执行如下任务:
执行源码编译、打包,如RPM、WAR包等。
构建Docker镜像。
部署环境,如使用Kolla自动化部署OpenStack。
自动化运行测试,如单元测试、集成测试等。测试结果有两种,一种是测试失败,流程返回到步骤1;一种是测试成功,流程继续。

③根据测试结果和其他信息综合决定此次开发人员提交的代码是否合并,这样保证只有通过了测试和审核的代码才能合并到GitLab仓库中。

④ GitLab的Webhooks会触发Jenkins系统中的两个构建任务,一个是源码编译、打包任务;一个是源码打包后的Docker镜像构建任务。Docker镜像构建后,Jenkins系统会自动将镜像推送到私有Registry仓库中。整个流程如下图所示:



围绕以Jenkins系统为中心的自动化测试、集成和发布平台,开发人员可以经常集成自己开发的代码,而每次集成都要通过自动化构建来验证,包括自动化编译和测试,从而尽快地发现集成错误。

同时,以GitLab作为自托管的Git项目仓库平台,配合代码评审系统Gerrit,在代码合并前进行审查。一个团队内的参与者,可以相互审阅各自修改后的代码,决定是否能够提交,或者退回继续修改。

这些应用系统的实现可以满足OpenStack研发测试的日常需求,这样,开发人员和QA测试人员就不需要关心从何处获取代码,寻找环境来做软件打包、环境部署、验证测试等了。相关人员只需要分别编写好各自负责的那部分代码,然后关联到相应的环境中即可。

首先,以Jenkins为核心的任务调度系统,自动触发代码编译、构建和打包;然后,GitLab和Gerrit协作完成代码及软件仓库的管理。由于OpenStack环境的部署对相关资源服务依赖性较强,因此,需要使用自动化部署管理工具。这里选择使用Kolla方式,实现高效的配置管理和持续部署,从代码打包、Docker镜像构建、部署实施到验证测试等环节,自动化实现代码持续集成的一系列任务。

Docker是一种标准化的开发、测试、部署和运维方式,通过Docker镜像,我们可以在开发、测试、线上等各个阶段无差别地使用服务,可以在本地端,也可以在云端运行程序。

很多企业内部都有一套标准化规范,在这套规范中定义了开发所使用的语言、框架、软件包版本及依赖环境等,这样做可以统一开发环境并解决因差异化带来的其他问题。基于此,我们可以根据不同的服务进行逻辑或物理上的分组,如下图所示:



在上图中,把Docker镜像分为了三层:基础镜像层、服务镜像层和应用镜像层。上层镜像的构建依赖于下层镜像,越下层的镜像越稳定,也越不会经常变更。
基础镜像层:负责安装最基本的、所有镜像都需要的软件及环境,例如操作系统等。
服务镜像层:负责构建符合企业标准化规范的镜像,这一层很像SaaS,例如Python环境、某个项目的公共软件包等。
应用镜像层:负责部署和运行应用程序,这个阶段是CI的产出物,例如rpm包、Python源文件等。

分层后,由于下层镜像已经提供了应用所需要的全部依赖环境,因此可以显著加快应用镜像层构建的速度。对于容器而言,它只操作变更的部分,已经存在且没变化的内容则不做任何操作。

典型地,在Dockerfile文件中使用FROM命令构建基础镜像层,如选择CentOS 7作为所有容器的基础操作系统;依据标准化规范,安装Nova计算项目的公共软件包,构建服务镜像层;最后安装指定的软件包,构建应用镜像层。

glance-base镜像的Dockerfile文件内容如下:
FROM {{ namespace }}/{{ image_prefix }}OpenStack-base:{{ tag }}
MAINTAINER {{ maintainer }}

{% block glance_base_header %}{% endblock %}

{% import "macros.j2" as macros with context %}

{% if install_type == 'binary' %}
{% if base_distro in ['centos', 'fedora', 'oraclelinux', 'rhel'] %}
{% set glance_base_packages = [
'OpenStack-glance',
'Python-rbd',
'Python-rados'
] %}
{% elif base_distro in ['ubuntu'] %}
{% set glance_base_packages = [
'glance',
'Python-rbd',
'Python-rados'
] %}
{% endif %}

{{ macros.install_packages(glance_base_packages | customizable("packages")) }}

{% elif install_type == 'source' %}
{% set glance_base_packages = [
'Python-rbd',
'Python-rados'
] %}

{{ macros.install_packages(glance_base_packages | customizable("packages")) }}

ADD glance-base-archive /glance-base-source
RUN ln -s glance-base-source/* glance \
&& useradd --user-group glance \
&& /var/lib/kolla/venv/bin/pip --no-cache-dir install --upgrade -c requirements/upper-constraints.txt /glance[cinder] \
&& mkdir -p /etc/glance /var/lib/glance /home/glance \
&& cp -r /glance/etc/* /etc/glance/ \
&& chown -R glance: /etc/glance /var/lib/glance /home/glance

{% endif %}

COPY glance_sudoers /etc/sudoers.d/kolla_glance_sudoers
COPY extend_start.sh /usr/local/bin/kolla_extend_start

RUN usermod -a -G kolla glance \
&& chmod 750 /etc/sudoers.d \
&& chmod 440 /etc/sudoers.d/kolla_glance_sudoers \
&& touch /usr/local/bin/kolla_glance_extend_start \
&& chmod 755 /usr/local/bin/kolla_extend_start /usr/local/bin/kolla_glance_extend_start

{% block glance_base_footer %}{% endblock %}
{% block footer %}{% endblock %}
{{ include_footer }}


glance-api镜像的Dockerfile文件内容如下:
FROM {{ namespace }}/{{ image_prefix }}glance-base:{{ tag }}
MAINTAINER {{ maintainer }}

{% block glance_api_header %}{% endblock %}

COPY extend_start.sh /usr/local/bin/kolla_glance_extend_start
RUN chmod 755 /usr/local/bin/kolla_glance_extend_start

{% block glance_api_footer %}{% endblock %}
{% block footer %}{% endblock %}
{{ include_footer }}

USER glance
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: