Docker持续部署图文详解 | 高效运维最佳实践06

2015 年 7 月 30 日

专栏介绍

“高效运维最佳实践”是 InfoQ 在 2015 年推出的精品专栏,由触控科技运维总监萧田国撰写,InfoQ 总编辑崔康策划。

前言

关于 Docker 的文章铺天盖地,但精品文章往往翻译居多。都说 Docker 天生适合持续集成 / 持续部署,但同样,可落地、实际可操作性的文章也很罕见。

基于这些情况,虽然我们专栏定位为运维管理性文字,但本篇是个特例,实操性的案例讲解——JAVA 项目如何通过 Docker 实现持续部署(只需简单四步),即:

开发同学通过 git push 上传代码,经 Git 和 Jenkins 配合,自动完成程序部署、发布,全程无需运维人员参与。

这是一种真正的容器级的实现,这个带来的好处,不仅仅是效率的提升,更是一种变革:

开发人员第一次真正为自己的代码负责——终于可以跳过运维和测试部门,自主维护运行环境(首先是测试 / 开发环境)。

难者不会,会者不难。通过简单的 4 个配置,即可优雅地实现持续部署。本文依惯例放上目录,请享用。

  1. 持续部署的技术思路
  2. 效果展示
  3. 配置 Git 和 Jenkins 联动
  4. 配置 Jenkins 自动更新代码
  5. 效果图文详解
  6. FAQ

好吧,我们正式开始。

1. 持续部署的技术思路

在本例中,假设我们 JAVA 项目的名称为 hello。简要的技术思路如下。

本案例中假设代码托管在 git.oschina.com 上,Jenkins 和 Docker Registry(类似于 yum 源)各运行在一个 Docker 容器中。JAVA 项目自己也单独运行在一个叫 hello 的容器中。

本文采取的持续部署方案,是从私有的 Docker Registry 拉取代码。有些变通的方案,把代码放在宿主机上,让容器通过卷组映射来读取。这种方法不建议的原因是,将代码拆分出容器,这违背了 Docker 的集装箱原则:

这也导致装卸复杂度增加。从货运工人角度考虑,整体才是最经济的。这样,也才能实现真正意义的容器级迁移。

或者说,容器时代,抛弃过去文件分发的思想,才是正途。本文最后的问答环节对此有更多阐述。

容器即进程。我们采用上述方案做 Docker 持续部署的原因和意义,也在于此。容器的生命周期,应该远远短于虚拟机,容器出现问题,应该是立即杀掉,而不是试图恢复。

2. 效果展示

本文最后实现的效果,究竟有多惊艳呢?且看如下的演示。

2.1 程序代码更新前的效果

我们以时间戳来简洁、显式的表述程序更新情况。

2.2 提交程序代码更新

本例中,我们把首页的时间戳从 201506181750,修改为 201506191410(见如下)。

2.3 上传新代码到 Git

顺序执行如下操作,输入正确的 git 账号密码。

然后呢?

然后什么都不用做了。端杯茶(如果不喜欢咖啡的话),静静地等待自动部署的发生, 旁观一系列被自动触发的过程,机器人似的运转起来(请容稍候再加以描述)。

为什么需要 3~5 分钟?只是因为本案例中的 JAVA 项目,需要从国外 download Maven 程序包,以供 Jenkins 调用和编译 JAVA。正式应用环境中,可以把 Maven 源放在国内或机房。如果仅仅需要对 PHP 项目做持续部署,那就更快捷了。

2.4 查看代码更新后的效果

在静静地等待几分钟后,新的代码确实已经自动部署完毕。

那么,这一切怎么实现的呢?很复杂么?不然。只要按照如下几步,便可快速实现哦。

3. 配置 Git 和 Jenkins 联动

这个过程也是难者不会,会者不难。主要分为如下三步。

3.1 Jenkins 配置 Git 源

Jenkins 中新建项目 java-app,并配置从 Git 拉取程序代码。具体如下:

3.2 Jenkins 配置远程构建

Jenkins 中配置 token,以供 git 远程调用时使用。

3.3 Git 开启钩子

怎么让 Git 在接收到用户更新的代码后,把消息和任务传递给 Jenkins 呢?这借助于 Git 的 hook 功能,配置起来也非常简单,如下。

4. 配置 Jenkins 自动更新代码

Jenkins 的主要工作是配置“远程构建”。在接收到 Git 传递过来的消息后,触发这个远程构建(到目标服务器),按照预定义的任务列表,执行一系列的工作,重建容器等。详见如下:

我们把其中最关键的 Shell 脚本内容摘抄出来。这些 Docker 相关操作,在第 1 部分“技术思路”已经提及,不再赘述。

5. 效果图文详解

在 2.3 这个章节中,我们当时的操作如下,这个目的是向 Git 提交更新代码。

当时并没有细说后续发生的事情,既然上面已经说清楚了原理,那我们就可以接下来说说实际发生的事情啦。

5.1 上传代码到 Git

这里貌似整个过程已经完成并顺利退出。其实,后台的工作才刚刚开始哦。

这时会触发 Git 服务器向相应的 Jenkins 服务器发出一个操作请求,此工作太过迅速,也没啥好说的,我们接下来看 Jenkins 都干啥子了。

5.2 Jenkins 进行的精彩互动

如下这个自动运转的过程,让我们有些许成就感,值得端杯咖啡(如果不喜欢茶的话),静静观赏。

1)Jenkins 会自动"冒出来"一个构建任务。

2)我们点进来,看看具体操作日志。是的,正在接受来自 Git 的任务。

3)下载 Maven 相关的软件包(就是这个过程慢)。

4)下载完成后,就开始利用 maven BUILD 新的 hello 项目包。

5)然后重建 Maven 容器,构建新的 Image 并 Push 到 Docker 私有库中。

6)最后,重新把 Docker 容器拉起来。这样,又新生了。呵呵

6. FAQ

问题 1:采用这么相对复杂的办法(而不是把更新代码放在宿主机然后卷组映射),是因为项目基于 JAVA 么;是否 PHP 项目就可以采用更新代码放在宿主机然后卷组映射这种方式?

回答 1:将代码拆分出容器,违背了集装箱原则。导致装卸复杂度增加。从货运工人角度考虑,整体才是最经济的。一切版本化。抛弃过去的文件分发。这是正途。至于文件大小,大的 war 包也就 50M 或 100M,在现有网络下不成问题,性能问题最好优化。另外建议关注 docker 2 docker,p2p 传输。

问题 2:如果整体代码超过 500m 或者 1g 以上,整体集装箱是否就不太好了?如果容器与代码分离,镜像就 100m 左右(2 层,base+ 服务),然后代码的话,是放到共享存储里,每个代码有更新,比如 svn 的代码,可以直接在共享存储里进行 svn update 就可以控制版本

回答 2:如果你的代码 500M,那只能说明业务开发该打板子了。

问题 3:如果测试环境使用您提供的完整集装箱服务还行,但在生产环境,集群里运行 docker 做应用,如果每个容器都是有完整的代码,是否有点臃肿,不如每个集群节点里就运行基础服务镜像,通过卷组功能绑定共享存储里的代码,加上 Crontab、Python 和 Shell 脚本,这样每次代码更新就 1 次就行了。

回答 3:环境一致性,在过去从来没有解决好。10 年前我们做 paas 时,和这个做法类似。不是说不好,时代变了,用脚本东拼西凑,终究难有好的系统。不能只考虑现在的方便,容器技术和 vm 如果类比,我觉得会让自己下决定时很纠结。

补充 3:脚本一般是典型的运维工程师思维,quick & dirty。一般很难做成一个产品或者系统。整体考虑和扩展性考虑都比较少。现在做 docker 的难点在于到底怎么看待它。到底是拿它做调度的基本单位,还是部署的基本单位考虑清楚?再聊方案。

关于作者

萧田国 ,男,硕士毕业于北京科技大学,触控科技运维负责人。拥有十多年运维及团队管理经验。先后就职于联想集团(Oracle 数据库主管)、搜狐畅游(数据库主管)、智明星通及世纪互联等。从 1999 年开始,折腾各种数据库如 Oracle/MySQL/MS SQL Server/NoSQL 等,兼任数据库培训讲师若干年。

曾经的云计算行业从业者,现在喜欢琢磨云计算及评测、云端数据库,及新技术在运维中的应用。主张管理学科和运维体系的融合、人性化运维管理,打造高效、专业运维团队。

个人微信号:xiaotianguo。如需更多了解,请百度“萧田国”。

张春源,目前任职 cSphere。国内最早期的 Docker 实践者,在生产环境拥有一年多的 Docker 容器管理经历。深刻理解 Docker 对于开发、测试以及运维的价值。擅长利用 Docker 构建整个 DevOps 自动化平台。热爱专研 Dockerfile 这门艺术,并对 CoreOS 有深入研究。


感谢崔康对本文的策划,丁晓昀对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015 年 7 月 30 日 00:10 10998

评论

发布
暂无评论
发现更多内容

免费开源看板软件Wekan安装与使用记录

emuqi

Docker 效率工具 wekan 看板 任务管理

全站加速在互联网媒体应用上的最佳实践

巨侠说

CDN

区块链在新冠病毒爆发中将加速发展

CECBC区块链专委会

区块链技术 供应链 食品追溯

是时候学习Linux了

Simon

Linux

自从有了语音开黑小能手,队友再也不会骂我了!

anyRTC开发者

WebRTC 在线教育 直播 RTC RTMP

写作只是消遣?

Geek_db1689

写作 讨论写作 自我感悟 瞎想乱写

Android |《看完不忘系列》之Retrofit

哈利迪

android

Apache Pulsar 社区周报:08-08 ~ 08-14

Apache Pulsar

Apache Apache Pulsar 消息系统

区块链政策区域特征分明 产业园区渐成聚集效应

CECBC区块链专委会

区块链 新基建

MySQL关于日期为零值的处理

Simon

MySQL

STM32-ADC简单学习笔记

 

局域网文件共享

冰糖雪梨多冰少糖

局域网共享 iPad air3 文件传输

为什么考研,考研能给你带来什么?说说我的感受!

我是程序员小贱

MySQL5.7升级到8.0过程详解

Simon

MySQL

低/零代码干掉了传统的开发模式

代码制造者

编程语言 低代码 零代码 信息化 编程开发

别人家的 DevOps 流水线,价值一个亿

Atlassian速递

DevOps 数字化转型 金融 Jira 数字银行

企业品尝新基建的美酒前,需要名为NetEngine 8000的酒杯

脑极体

枚举算法练习例题(Python版)

罗罗诺亚

Python 算法 枚举

集成学习方法及应用,破解AI实践难题

博文视点Broadview

人工智能 机器学习 深度学习 AI 周志华

量纲分析(Dimensional Analysis)入门

InfoQ_b5c13aa54782

数学 基础 物理 量纲分析 电磁

Dell G7 指纹识别设备 - Goodix fingerprint 失效官方解决办法(图文)

Saint_X

硬件

CentOS7 开启3306端口

暴躁小李K

Centos 7 Firewalld防火墙 Liunx

DB-Engines 8 月数据库排名:Redis悄悄拔高,猛超Elasticsearch

华章IT

MySQL 数据库 redis Clickhouse SQL优化

用python给女朋友做一个歌曲词云图

我是程序员小贱

辗转相除法求最大公约数(C语言实现)

InfoQ_3f366696ed0c

C语言

谈一谈Kuberflow

soolaugust

机器学习 tensorflow kubeflow Kubernetes 云原生

随手记

InfoQ_0d79a8bcf933

数据结构与算法

兄弟,不要偷看人家摄像头

我是程序员小贱

特性预览:Apache 顶级项目 Apache Pulsar 2.6.1 版本即将发布

Apache Pulsar

Apache Apache Pulsar 消息系统

小白程序员成长之路-准备篇

小柚先生不吃辣

盲打练习 在线打字

架构设计篇之云计算服务设计与决策

小诚信驿站

云计算 刘晓成 云计算服务设计 企业架构和云服务 SaaS/IaaS/PaaS

Docker持续部署图文详解 | 高效运维最佳实践06-InfoQ