«

»

十二 08 2016

使用 GitLab、Jenkins、Docker 建立快速持续化集成交付部署方案(三)

 

上一章节中我们完成了对 Docker 的使用和部署。

本文中我们将完成 GitLab → Jenkins → Docker 的环境,并完成基于 GitLab、Jenkins、Docker 的面向 Web 开发的快速部署方案。

 

我们最终得到的结果,将是部署人员只在部署环境下只敲一句命令,就完成整个部署工作。

最终的目的就是接近一键部署,烧锅炉的大叔都会给服务器部署服务了,开除工程师。

文章索引

  1. GitLab、Jenkins、Docker 初始环境安装
  2. 制作 Docker 镜像 及 Docker Compose 的使用
  3. 使用 Webhook 自动触发 Jenkins 进行 Docker 镜像制作并保存到私有镜像仓库,以及目的机部署(本文)

 

私有 Docker 仓库

为什么要使用私有仓库

我们最终要得到的交付成果,应是一个 Docker Image。

在某种程度上,不少公司在开发测试阶段可能会考虑直接在开发服务器上生成本地镜像,或是使用 docker save 方式导出 tar 镜像包文件,在不同机器上进行部署。这种方式对于公司网络环境比较好的情况下确实可以实行,而且对于线上生产环境,某种意义 上人工验收后部署要比全自动部署更放心。

然而更多的企业,外部网络带宽有限,内部网络优化更是渣的可怜。一个镜像包一般都在百 M 左右,用网络复制可能需要几十分钟甚至半个小时,部署一次环境,等待网络复制的时间,要比 拿一个优盘抱着笔记本乘上几十层电梯钻进机房忍着低温和轰鸣 蛋疼的多。

(已见过不止 3 家公司内部网络是这种情况。而且一般公司的 IT 部也都是所谓的网管,出问题后 重启、重装、换机 三步走的风格与一般小农村网吧网管也没什么区别。这种职位多数都是公司内部解决职工亲属就业问题内推产生的。神州泰岳全公司都在用 12.12.0.0/16 这种公网地址当私网地址用,为服务器申请一个静态 DHCP 地址都会搞得吵架。神州数码这种大公司的网管也在给新员工配置新电脑的时候,装个盗版操作系统都要看手册,还总出错)

所以我们要在这里,充分利用 Docker 镜像的分层文件系统:没有更新的部分不会生成新的镜像,不会浪费硬盘空间,拉取新镜像时旧镜像也不会消耗流量和带宽。

建立私有仓库

你可以直接执行:

来启动一个仓库容器,默认端口 5000,数据将会保存于/var/docker_registry。

注意这是 Version 2,对于其他版本请参考其它文档。

注意这是一个 HTTP 服务,没有加密传输,对于安全性需求,建议自行解决。

相关文档:https://github.com/docker-library/docs/tree/master/registry

本地镜像打 tag

这不是一个移动操作,而是一个复制软链接诶操作,在 docker images 中会新增一个 ID 相同但 tag 不同的镜像,不占用硬盘空间。

推送本地镜像到仓库

会将这个镜像推送到 your_registry_domain/private-docker-registry/

拉取仓库镜像到本地,或直接执行

pull 和 run,不解释

 

配置 GitLab

访问权限

注意,因为 GitLab 是我们自建的仓库,拥有完全的使用权,所以对于仓库的可视权限将要比 GitHub 多出两种选项。

  • Private 私有,只有所有者、组内成员或已分配的用户有查看权限(同 GitHub 收费版的私有仓库)
  • Internal 内部,拥有 GitLab 账号的成员可以查看,无账号用户无法访问(适合于服务器放在公网但不想公开代码的情景,GitHub 没有这个功能)
  • Public 公共,任何人都可以访问(同 GitHub 免费版的公共仓库)

建议公司内部的代码仓库都设置为 Internal。

使用 GitLat Webhook 与 Jenkins 实现持续交付

GitLab 等代码仓库其实也支持 CI/CD 操作,然而我们将要执行的操作对于 GitLab 来讲过于复杂了,所以这些操作要交给 Jenkins 这种专门的持续集成工具。为了能在需要时自动触发 Jenkins 自动操作,我们要使用 GitLab 的 Webhook 进行操作。

Deploy Keys

你可以为 Jenkins 专门制作 Deploy Keys,或者干脆在 GitLab 上增加一个 Jenkins 账户,用户 Jenkins 拉取代码。两种方法都可以。

配置 Webhook

根据我们之前的安装部署,Jenkins 的端口是 8081。假设我们的主机域名(地址)为 your-what-server,项目为 catscarlet/test1.git,则 url 为

触发条件建议选择 Merge Request event,或干脆手动触发。

这里就有 GitLab 安装在宿主机的好处了,端口很标准,不然改个 ssh 端口还要使用 git 的话,会变得很麻烦。至于 https,相信搞得定 Let’s encrypt 的人很多,但搞不到公司域名的人更多。

 

配置 Jenkins

安装必要插件

安装这些插件:

  • Credentials Plugin
  • Git plugin
  • Gitlab Hook Plugin
  • SSH plugin
  • Locale plugin

修改默认语言

Jenkins 默认根据用户系统来显示语言,然而其自身的中文翻译挺糟糕的,所以换成纯英文更好一些。

在安装 Locale plugin 插件之后,点击 Manage Jenkins – Configure System,在 Default Language 处填写 en,保存。

修改并发数

因为接下来我们会把项目代码复制到一个统一的临时目录下进行处理,如果这时候有其他项目也在处理,则这个临时文件夹内可能就会有文件混乱的问题。所以我们要把 Jenkins 的并发数改为 1,参数为 # of executors 。对于需要并发处理的正式环境,您需要手动修改临时目录的位置。

新建 Jenkins 项目

登录到 Jenkins 主页,New Item 新建一个 Freestyle project ,命名为 test1。

在 Source Code Management 这里,选择 Git,并在 Repositories 填写你的 Git 项目地址 catscarlet/test1.git,Credentials 选择你的证书,Branch Specifier 选择对应 Branch。在 Additional Behaviours 中增加 Clean before checkout。

Build Triggers 选择 Poll SCM,激活 Webhook 功能。内容留空,不定时 Build,完全由 Webhook 触发。

在 Build 这里,Add build stemp 增加两个项目:Execute shell 和 Execute shell script on remote host using ssh。

不能选择直接在本地 Execute shell ,因为 Jenkins 目前是运行在 Docker 容器内的,与宿主机完全隔离,除了基本的 Linux Shell 和 JAVA 的 SDK 环境之外,容器内没有任何其他东西了,不能使用 Docker 命令,没有 node 和 npm,不能编译,几乎什么都做不了。

所以我们在这里要分开做两件事:

  • 准备代码,并复制到宿主机环境
  • 登录到宿主机,在宿主机上进行打包。你也可以选择登录到其他主机上,比如一台专用打包服务器。

代码

更改 Jenkins 的启动方式,额外绑定一个数据卷目录。

我们已经在 Source Code Management 选择了 Git,所以在执行 Execute shell 之前,Jenkins 会先用 Git 把代码拉取到本地,不需要自己手动执行 git pull。

Execute shell:

Execute shell script on remote host using ssh:

需要先在 Jenkins – configuration – SSH remote hosts 中添加对应的服务器登录方式。

这里建议调用从 git 仓库上拉下来的脚本,而不是把要执行的命令写在 Jenkins 这里。

project-build.sh

这里建议对每个镜像都手动打包,而不是使用 compose 打包。一方面 compose 无法针对镜像打 tag(compose 更关注于容器而非镜像,容器是 NAME 而镜像是 TAG),另一方面最终部署所需的 docker-compose.yml 中需要编写的是 带仓库路径的 image 而非 build。

我们的理想情况是,部署人员从 GitLab 获取 docker-compose.yml 之后,执行 docker-compose up,便完成容器部署操作。(面向傻瓜的程序设计,一键部署吔)

测试

GitLab 端

在 GitLab 的 Webhooks 页面有一个 Test 按钮,点一下就会触发 Webhooks,如果提示 Hook executed successfully: HTTP 200 那么 GitLab 这端就工作正常。

Jenkins 端

Jenkins 接到 Webhooks 后就会开始打包。

  • 灰色表示正在准备
  • 蓝色表示打包中或打包完成
  • 红色表示打包出错

点击进入后可通过左侧的 Console Output 查看控制台的情况,比如 Shell 执行出错在哪里。

注意 Jenkins 会在 Git 检查代码变更情况,如果 GitLab 那段没有新提交的话,Jenkins 会认为代码相同,没有必要,会忽略这次打包。所以如果要进行测试的话,可能需要删除上一次的打包结果。你可以在 Polling Log 中查看相关信息。

部署

部署人员从 GitLab 获取 docker-compose.yml 并复制到目的机,执行 docker-compose up

这回烧锅炉的大叔都会给服务器部署服务了,终于可以把工程师都开除了。

 

总结

本系列文章简单讲述了基于 GitLab、Jenkins、Docker 的面向 Web 开发的快速部署方案。文章中没有涉及 Docker 1.12 以及 swarn 等相关概念。

Docker 1.11 中,基于 compose 的 DAB 方案,是以在同一服务器上部署所有服务镜像的方式实现的,这是一种容易简单理解的实现方式。在集群中,每个节点都运行相同的容器组合。多个节点运行相同的容器群,容器群之间隔离没有交互,而容器间紧密结合。

但这是一种可能浪费资源的模式。负责某些服务的容器可能负载非常大,但上下游容器则比较空闲。这种情况下,更希望多个节点都能分担压力大的服务,而对比较闲的服务则减少数量。

另外同一节点上可能会有多个项目,而项目间可能会有相同的无擦别服务,比如 php-fpm。更希望复用这一个容器,而不是启用多个相同容器只占内存不干活。

Docker 1.12 中实现了这种需求,将分布式的概念从项目分解到容器应用。但目前仍是试验中,所以没有仔细研究,也不建议使用。阿里云在 Docker 还在 1.11 版本期间,自己也开发了一个阿里版 Docker,实现了 1.12 中的这个功能,但是限制太多,脚本不兼容,不建议使用。

7 comments

Skip to comment form

  1. 王小白

    你好 我最近在研究 jenkins gitlab 结合自动生成 docker 镜像的问题,目前有些问题没有解决,方便给下联系方式向您请教下吗,万分感谢!

    1. 石樱灯笼

      没有联系方式

  2. godtoy

    请问,有 docker-compose 部署的方式么? 因为我的项目只是单机,宿主机就一个 docker,jenkins 泡在容器里面,无法调用宿主机的 docker-compose 进行重启。我想利用这些工具,实现自动部署

    1. 石樱灯笼

      我单机都是手工维护,或者另外创建一个 git 项目维护。

  3. 小艾

    博主你好

    问下你这篇博文代码高亮插件用的 wordpress 的哪一个? 我找了好多都没找到合适的。

    麻烦分享下

    谢谢。

    1. 石樱灯笼

      Crayon Syntax Highlighter

      1. 小艾

        谢谢博主,我也是用的这个, 但是我的为啥那么丑,,,,,,

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据