通过Docker容器运行持续集成/持续部署

jopen 9年前
 

对于docker主流的应用场景:持续集成和持续部署(CI/CD)大家也许并不陌生.这篇文章从独特的视角阐述了如何利用各种云平台构建属于自己的CI/CD容器,笔者还自己扩展了Gitlab CI引擎,对CI感兴趣的同学对这个文章应该很感兴趣.

我曾经使用Docker了一段时间,在过去的一年里伴随着众多的Docker容器涌入,帮助用户们更容易的部署Docker容器到生产环境中。一 些工具是第三方公司提供,当然也包括Docker公司自己的容器工具(例如:Docker Swarm, Docker Machine, 和 Docker Compose)。尽管如此,最近我在测试一种新的Docker工作流,它可以允许我推送代码并测试, 构建项目,并且部署在生产环境下的Docker宿主机中。

接下来隆重介绍我的新工具 bar service, ThreeBar ①,一个可以在Heroku上运行持续集成/持续部署(CI/CD)系统。通常情况下,新开发的代码部署到服务器遵循下面的流程:

  1. 创建一个本地组件
  2. 推送代码到git仓库的feature/development分支
  3. Shippable ,一个持续集成引擎,一旦检测到有的提交(commit),通过pull获取最新的代码并且运行相关的测试
  4. 如果测试全都通过了等着被部署到生产环境中,就会创建一个合并(merge)分支的请求并且执行该合并(merge)
  5. Shippable 一旦检测到有新的提交到远程master分支,同时会执行测试,并且推送源码到Heroku的git仓库中
  6. Heroku 将会自动构建这个应用程序并且部署它。

这个工具真的可以方便、快捷的部署项目并且保证所有部署到生产环境的代码都经过了测试而且是可靠的。

尽管如此,还是由一个问题,那就是大规模部署Heroku需要花费高昂的费用。选择使用heroku,你将会获得heroku提供的免费使用优惠 ②,一个标准的512内存的由heroku提供的Dyno容器只需要35$。公平的说,heroku提供的虚拟主机服务已经够实惠了,但是一些应用的复杂 程度要求heroku提供更灵活的定制化需求,收取一定费用也无可厚非。

Docker,当然可以替代heroku,提供相应的代码部署服务。但是上面谈到的问题仍旧存在。当你的代码需要部署的时候,频繁手动启动和关闭服务是得不偿失的。让我们来比较一下不同持续集成/持续部署引擎和docker相比有什么不同。

寻找解决方案

Docker并不是第一个也不是最后一个端到端的持续集成工作流解决方案。因此我们需要将众多不同的技术组合到一起用来完成我们想要的功能。下面将会介绍三个主流的提供构建引擎的服务:一个CI/CD的测试运行引擎,一个web容器,一个容器适配器。

CI/CD 服务器,测试运行引擎

当我们选择一个CI/CD服务,你必须确定他们必须支持Docker容器的构建。下面的这些服务都包含了这一功能:

当然还有一些其他的服务,包括大名鼎鼎的Jenkins CI server。这里你可以自己去搜索这些服务。一些服务在容器上运行构建,但是他们相互之间是完全独立的。稍后你就会看到,你可以在Docker-in- Docker上运行服务,同时可以使用在Docker 容器中运行的其他服务。

在我的试验中,我选择了和Gitlab 版本管理服务器端同时运行GitLab CI 系统。通过Gitlab版本管理服务器,我可以很清楚的看到每次commit。选择Gitlab不仅是因为他是一个免费的开源源码 托管仓库 和对托管在上面的项目提供的 持续部署引擎 ,同时也是一个通过安装gitlab运行你自己的服务的开源软件。

如果你选择使用Gitlab CI System搭建你的持续集成框架,你必须提供属于自己的测试运行服务。宿主机的持续集成软件只能运行特定的测试服务,实际上它自己并不能自己执行测试任 务,通常都是启动由本机提供相应的测试服务来执行的,你不光可以通过服务提供商启动引擎或者你直接运行你本机上的服务(虚拟机VM或Docker容器).

服务器托管提供商

当然你同时也需要一个服务器托管提供商让Docker守护进程可以在它之上运行。不幸的是,使用Docker意味着经常需要运行和管理自己的服务 器,也就是你将要负责这个主机的运维。但是,我想通过下面的内容说明,你可以在Docker运行一个高可用、多数据中心架构,这意味着即便是停机一个小时 也不会像以前那样对业务影响那么巨大。

常用的服务器托管提供商包括下面的几个③:

业务流程

即是你有了一套构建好了的Docker容器和能够运行docker守护进程的服务器。你还是需要一个能够被轻易启动的容器并且能够在构建一个新镜像的时候能重复部署他们。正如我最近正在使用的名叫 Tutum 的业务流程服务。

目前, Tutum 是一个能帮助你管理你的容器部署工作流的服务形式。与此同时,你还能在各种云平台上快速动态增加节点,创建新服务,通过一个私有的register来部署你的应用。

此外, Tutum 还为你的容器创建了一个私有网络,意味着可以通过你的Tutum账户你的Docker容器拥有自己的私有固定IP地址并且通过路由来访问其他容器。无论你 的物理机是否在同一个数据中心,还是通过世界各地的不同的服务器托管提供商。它都将允许你创建一个基于多服务器、多云平台的弹性的解决方案。如果你之前见 过 Flannel by CoreOS , Tutum 的私有网络和它差不多。

我一直在寻找类似上面谈到的这种服务。就在前不久,我刚做了一个实验:在多容器docker之间通过V*N创建一个P2P网络。这是很久之前的docker网络配置达不到的需求,但是现在 Tutum 做到了。

Tutum 同时也整合了CI/CD组件,并且支持git推送(push)。当Tutum 完成功能的时候,它可能成为唯一的你需要包含的到源码仓库中的其他服务。

Tutum 拥有我们需要进行CI/CD的几个关键组件:

  • 一个私有的为容器镜像准备的注册中心
  • 当新的镜像推送到注册中心的时候重新部署容器
  • 简便的容器扩容(在界面视图上,可以通过滑动N或M的方式调整容器大小)
  • 在Tutum的界面上添加节点

其他我们值得关注的组件:

*在对一个web应用容器缩放后,基于自省的方式的DNS动态解析。举个例子,你的haproxy路由会自动发现新增容器并且添加到路由列表中。

  • 私有的网络覆盖
  • 不再受不同云供应商的限制,创建自己的节点

给所有东西组装到一起

下面就挑干货说下我的实验过程:

  • 宿主机使用Gitlab搭建的源码远程仓库
  • 宿主机使用Gitlab CI搭建的CI/CD引擎
  • RunAbove作为服务器提供商对所有CI/CD运行引擎的容器托管④
  • Tutum 作为业务流程和服务的管理服务提供

当所有的事情结束,也组装完毕,git的提交记录活动图,如下图所示:

通过Docker容器运行持续集成/持续部署

部署Tutum 代理

正因为如此,我们事实上是使用Tutum 去部署GitLab CI runners。我给你的建议是,先安装Tutum agents。启动所有你希望使用的服务,这样在 Tutum 的仪表盘上就能看到Bring your own node字样的按钮。点击它,你将会收到一个如下面所示的命令行:

curl -Ls https://get.tutum.co/ | sudo -H sh -s XXXXXXXXXXXXXXXXXXX

通常在某一个节点运行上述命令自动添加到你的Tutum账户,与此同时进程也会自动添加到其他节点(每次当你点击Bring your own node按钮的时候)。

一旦Tutum agent 安装到你的所有节点上,你将会在仪表盘上看到它. 在这一点上,你也许想给这个节点贴上适当的标签. 允许对应的服务器在哪个节点上运行。举个例子,你可能有一组节点标记为tag或production目的是为了创建一套环境,亦或者是用来做持续集成的一个节点标记,这些只能在宿主机上运行。

你可以通过点击节点名称来标记一个节点,添加的标记将会显示在左侧边栏。

部署一个Gitlab CI 运行引擎

现在你可以通过Tutum 来部署一个Gitlab CI 运行引擎.然而,我们需要一种特殊类型的持续运行引擎-需要能够在这个容器中运行Docker并且能够构建我们自己的Docker镜像.

你可能想,这怎么可能呢?假如我们使用Tutum运行Gitlab CI 引擎,它只能运行在容器里。那么问题来了,如何在Docker容器里运行Docker呢?

其实这完全可以做到。事实上,我们可以运行在你能想象到的更深层Docker中. 我们的Docker容器架构如下图所示:

通过Docker容器运行持续集成/持续部署

正如你所看到的,在我们的节点的Docker容器里Tutum运行GitLab CI引擎。此外,该GitLab CI引擎实际上使用Docker构建镜像并运行测试,这意味着我们有两个嵌套层次.

通过fork GitLab CI Runner,我已经建立了相应功能的分支.这样就可以有效的跟踪在 github 和官方Docker注册中心的变更.

在建立你的GiLab CI runner前,确保你已经存在一个GitLab的实例仓库,并且能够同时运行GitLab CI 引擎.正如前面提到的,你可以建立自己的实例,或者直接使用gitlab官方提供的免费托管仓库和持续部署服务.

一旦你注册了gitlab仓库。你所做的只需要通过点击链接你的Gitlab CI 账号.在你关联了Gitlab CI账号之后,你将会通过Gitlab的仪表盘看到你的gitlab仓库列表,并且通过点击"Add project to CI" 按钮来添加你的项目到Gitlab CI 引擎中.点击完毕后,你就会在gitlab的仪表盘上看到你新添加的项目信息了.如下图所示:

通过Docker容器运行持续集成/持续部署

如果你轻戳gitlab的用户界面,你将会注意到一个菜单标题为"Runners".在这个页面有一个注册标记,同时还有如何创建一个新 的"Runner"的功能说明. 在下面的例子中,我将会使用Tutum部署我们的Gitlab CI 镜像.确定你已经复制了注册标记和Gitlab CI的url地址-一会你将会用到他们.

在你的Tutum界面上,创建一个新的服务.在Tutum中服务的概念是一个Docker容器组,他们使用相同的软件并运行着相同配置.

每个服务可以有零个或者多个容器在同一时间运行,并且Tutum将会管理你所有节点的协调和缩放工作.

在启动向导的第一个界面,你将会看到几个标签,让你选择不同来源的Docker镜像源.Tutum拥有一个内置的,私有的注册中心,通过搜索其他 注册中心同时支持一些具有特定功能的镜像,当然这里也包括Docker的官方镜像.切换到"公共镜像"选项卡,搜索"wizardapps/dind- gitlab-ci-runner"镜像,这就是我前面描述的在github上fork的GitLab CI 引擎源码仓库中我自己建立的分支.

你一旦确定选择了镜像,你将会看到一个界面上面你对两个容器之间调度的功能选项和一些基本配置。对于部署策略,虽然默认的设置也可以运行持续集 成,但是我建议还是通读下Tutum官方的说明文档。You also will likely want to leave the number of containers at 1 unless you wish to do parallel builds.如果你先前已经对部署在Tutum的节点打了对应的标签,请确保在"Delpoy Tags"输入框输入了正确的标签名称.从本质上讲,Tutum会努力寻找所有满足你要求"Delpoy Tags" 中声明的标签,并且部署他们到一个节点.

下图说明当你第一次必须要改动的一个重要的配置信息,这是在"Advanced Options"部分的"Privileged Mode"选项,Docker需要选中这个选项,这样保证Tutum可以很容易的获得该信息.

通过Docker容器运行持续集成/持续部署

在配置好私有模式后,你将会看到下一个屏幕-有关环境变量配置信息.

像Docker命令行一样,Tutum允许你声明一个环境变量使之可以在你的Docker容器里使用.

不仅如此,在Tutum中,每一个部署的容器都可以使用这个环境变量.尽管我们不会再Gitlab CI 引擎上使用link功能,我们使用的是Tutum提供的动态link,容器依然允许使用其他容器中的环境变量.

下面是三种需要设置的重要的环境变量:

  • REGISTRATION_TOKEN: 注册信息就是之前我们在Gilab CI 中拷贝的"Runner".
  • CI_SERVER_URL: 在Gitlab CI页面上之前提供给我们的url地址.如果你使用的是官方提供的gitlab CI服务,直接填写" https://ci.gitlab.com/".
  • GITLAB_SERVER_FQDN:这里声明的是gitlab 的域名,这是用来执行一个ssh-keyscan.如果你用的是官方的托管服务,请填写 "ci.gitlab.com".

在配置完这些变量之后,终于可以"创建并部署"我们的服务了.

一旦你的容器启动完毕, 你可以返回GitLab CI的 "Runners" 页面并且你看到一个新的入口. 现在你可以着手准备建立 GitLab CI 任务吧.

创建一个GitLab CI 任务

终于到最后一步了,我们在Gitlab CI 上添加一个实际的脚本目的是建立一个 持续集成/持续部署的工作流.现在,这将取决于你的实际项目的种类,但大体方向应该是相同的,你会使用Docker镜像来构建Docker容器,然后上传 到你的镜像库.在这种情况下,将会上传到Tutum提供的私有镜像库.

在"工作"选项卡中,Gitlab CI工作可以进行修改.在这个部分,有两个不同的子选项-"test"和"deploy".正如他们名字所暗示的,测试脚本通常用来运行单元和集成测试. 部署脚本只运行一旦测试完成后的特定分支.这样就可以允许你在每次提交(commit)后运行你的测试脚本,与此同时部署脚本当且仅当所有测试全部通过的 时候部署远程master分支.

下面是脚本实例:

```

docker login-u[USERNAME]-e[EMAIL]-p="[PASSWORD]"tutum.co

Build the Docker image and tag it for Tutum

docker build-twizardapps/app.

docker tag-fwizardapps/app tutum.co/wizardapps/app:latest

```

上面的测试脚本并没有实际运行任何测试,但是他确能为我们的应用程序构建Docker镜像并打上对应的标签.如果你在初始化阶段使用自己的脚本, 请确保你的用户名,邮箱,密码和Tutum上的注册信息报纸一致.因为Tutum提供的是一个私有Docker注册中心,确保你的测试脚本能通过相应的校 验⑤.

然后,我们还可以创建一个部署脚本,实际上是推送我们的镜像到Tutum的注册中心,并开始构建.

docker push tutum.co/wizardapps/app

自动部署

到了这一步,你的系统应该已经构建成功并运行,新代码应该可以持续集成并上传到Tutum的注册中心.剩下的工作就是在Tutum上创建你自己的服务,确保重启后还可以继续使用.

这和我们创建Gitlab CI 服务类似,所不同的是我们让服务"私有化",我们只需要打开"Auto Redeploy"开关即可.配置所有的服务端口,环境变量,链接和卷标,然后点击一下部署即可.

恭喜你,你现在已经拥有了只有在经过测试后,可以快速进行持续部署,自动化部署的Docker 应用程序.

其他资源

GitLab CI Multi-Runner 地址: https://github.com/ayufan/gitlab-ci-multi-runner

我们通过在Tutum里建立每个项目上都需要的持续集成 "服务",可以很快上手.作为一种替代方案,你可以尝试使用GitLab CI Multi-Runner,这个项目通过一个配置文件允许多个项目同时进行构建。

①. 我有一些很酷的东西和大家分享,这就是ThreeBar-一个远远超出你想象的工具.一旦你做好准备加入,你将会发现Docker持续-部署-应用的强大功能。

②. Heroku 运营模式,您只需要按小时支付使用费.每一个"虚拟机"运行你的代码被称之为"Dyno",你可以仅仅通过运行一个命令就可以做到一键部署,例如web服 务器或者其他请求队列服务.你将会每个月获得750小时的"Dyno"免费使用权.这意味着如果你愿意的话可以在Heroku上运行一个免费的web服务 器.

③. 我个人使用了以下所有的服务器提供商,我也通过博客链接点击获得了一些收入.但是,很可惜,任何一个服务器提供商都不会允许你在创建你自己Docker服务并运行在Linux实例上.

④. RunAbove的沙箱是一个伟大的实验,因为在它上面有大量的RAM,SSD存储,并且花费极低-每月只有3美金在一个2G内存的服务器上.尽管如此,在那个时候他们不被SAL所接受,因此你只能选择其他的服务提供商.

⑤. 此时此刻,你必须把你的Tutum的账号和密码直接扔到脚本中.很不幸的是,Tutum不提供这样的单独密码注册表API,所以这个方案也因此留下一个潜在的安全漏洞.