本帖最后由 monicazhang 于 2017-9-13 11:17 编辑 0 \5 a1 L8 |0 M" R. b% e, T
7 K2 L4 o' _/ T6 q: L* e/ B概念介绍
$ q. k0 X3 c+ T% L0 w! ?8 RDockerDocker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app);几乎没有性能开销,可以很容易地在机器和数据中心中运行。最重要的是,它们不依赖于任何语言、框架包括系统。 % q1 X- ]+ d: X- m9 K- j' J& A
ITILxf.com" target="_blank" class="relatedlink">DevOpsDevOps(英文 Development 和 Operations 的组合)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。它的出现是由于软件行业日益清晰地认识到:为了按时交付软件产品和服务,开发和运营工作必须紧密合作。越来越多的企业和项目将整体的代码管理、构建、集成、发布流程通过 DevOps 自动整合在了一起。同时还融入自动化测试等其他技术,使得整个整个软件产品的生命周期实现了可持续的运转。 ; e1 M+ o' b8 s* T' U; t
Docker Image 分层存储为了最大化重用 Image,加快运行速度,减少内存和磁盘的占用,Docker container 运行时所构造的运行环境,实际上是由具有依赖关系的多个 Layer组成的。如图 1 所示,每一串数字 ID 就代表了一个 Docker Image Layer。当我们在 pull 一个 Docker Image 的时候我们会发现所有依赖的 Layer 文件将会被 download。
+ S# T8 C& U. G2 X$ b图 1. Docker Image 分层示意图' V8 h" G7 W& j$ F
例如一个 Docker App Image 的运行环境是在基础的 Docker Base Image 的基础上,叠加了包含例如 JDK 等各种工具的 Image,再叠加包含Liberty 及其相关依赖 Liberty 的 Image,以及包含了 J2EE 应用的 EAR 包的 layer。这些 Image 由 AUFS 文件系统加载合并到统一路径中,以只读的方式存在,最后再叠加加载一层可写的空白的 Layer 用作记录对当前运行环境所作的修改。因此,当 Docker Image 每次由一个基础 Image 创建后,新 Image 就自动增加了一层。如图 2 所示
# X) ]( D6 v9 B; Y2 D {图 2. Docker Image Layer 的叠加; c9 U: U3 \) c2 A. l
Docker Image 在 DevOps 流程中的应用尽管 Puppet、Chef、Salt 以及其它先行者已经在 DevOps 的探索中作出了相当的贡献,但这些工具的主要活动舞台仍然集中在运营团队而非开发者群体当中。
- {5 I d1 j1 f由于 Docker 的可移植性和容器的封装性。开发人员可以在容器机制内部工作,而运营工程师则能够在容器外部以并行处理自己的任务,使其成为了一款能够在开发人员群体中获得与运营工程师同等认可效果的 DevOps 工具。 - W* @5 f' ~6 r7 t0 V% Z9 ]' k6 b
Docker 技术在 DevOps 过程中使用方式并没有特别的规定,但大致可分为两类 * e; \) m9 m# |& |
两种使用方式上并没有本质的差别,完全根据实际情况进行选择。本文下面的章节将主要以将产品封装到 Docker 容器中做成 immutable image 的方式为背景进行介绍。基于 Docker 的 DevOps 流程如图 3 所示:
0 L- w$ [7 S x2 V, M& d2 X图 3. 基于 Docker 的 DevOps 流程图 f$ ^4 r7 j0 @# s
随着项目基于 Docker 的使用逐渐增加,Docker Image 的数量也将逐渐增加。随之而来的问题就是如何维护这些 Docker Image 的升级。如果缺乏规划和设计,每个 Docker Image 均来自一个最基础的 OS Image,那么就需要对于所有的 Docker Image 进行重构。如图 4 所示: / q- @5 m% H' B
图 4. Docker Image 衍生单一 Base Image
9 F% a1 D6 Y2 W
当环境进行更新升级的时候,如果所有的节点均来自一个基础的 OS Image,重复的 layer 层将会被重复更新。也就意味着,这部分重复的内容会被反复的下载。如果一个 Docker Image 达到了 1G 以上的规模,而每个 Docker Host 节点的更新都需要重新下载新的 Image. 这样环境更新所花费的时间将会是成倍的增加。如图 5 所示,Docker Image 2 和 Docker Image3 均是基于 Docker Image 1
6 ?" P9 h! l/ A h图 5. 基于同样 Base Image 的 Docker Image Layer 的叠加; l. B4 b/ P1 X
5 ^1 K, A6 Z( i( @ I( H
图 6. Docker Image Layer 在 Docker Host 上的存储关系0 S2 e" I( j* K7 J& C/ m
' W }2 S0 i2 D. c7 j/ H! o! I6 y
从图 6 可以看出在同一个 Docker host 上 download 来自同样 Base Image 的 Docker Image, Docker 在下载 Image layer 的时候,对于已经存在的 layer 是不会重复下载的。但是如果 layer 不同,即使内部包含的内容一样,也还是会重复下载的。
8 F6 O# S/ a. t利用分层机制优化 Docker Image# y5 C7 }( N0 I D2 K$ \: B
通过上一节的介绍,可以看缺乏良好设计的 Docker Image 会给日后的维护以及 DevOps 的效率带来较大的问题。本文接下来就将重点介绍如何利用分层机制对项目的 Docker Image 进行合理的规划。从而大幅提升 Docker 在 DevOps 过程中的可持续性。并提升 DevOps 的效率。
% m" y' Z) C* @/ o设计基于分层机制的 Docker Image以基于云平台的分布式应用为例. 在分布式系统中我们假设有两个应用 App1 和 App2。 这两个节点所的环境信息如下: * S) \: |" i" U" O) i' {4 o* r; O
表 1. 分布式应用环境配置需求对照表- `9 S' ?6 \/ u
通过表 1 环境信息的对比,我们发现在这两个不同引用的节点上,不同的部分只是 logstash 的 config 文件和最后的 Ear 包。
. t2 N; k4 K; m( I对于其他相同的部分,我们可以考虑通过 Docker Image Layer 的概念将其复用。从而最大限度发挥 Docker 的能力。
( a3 m% v, i' Q8 A0 r8 K将上表中的两部分环境信息以分类为节点名,重新以树状结构组织如图 7 所示。
3 b/ v0 l, U' b& z6 y5 G# O, q: |图 7. 分布式应用环境配置树状图 18 e- R8 H! r. \% Z! R
然后以 Docker Image Layer 最多不超过 4 层的标准,将一些不会经常发生变化或者可以用于其他 Docker Image 的层合并。如图 8 所示:
3 c& q* f- B2 v" {. K2 O图 8. 分布式应用环境配置树状图 23 ^5 G6 J, j& I- k
最后将图中的两个树状结构图进行叠加将重复的节点进行合并,最后得出如下树状结构图: 图 9. 分布式应用环境配置树状图 3
3 e6 N) o( G: | X
到目前为止我们已经基于 Docker Image 的分层存储机制完成了一个基于云平台分布式系统的 Docker Image 的规划。接下来就可以根据上图结构分别制作 Image。最终我们将会有三个 Base Image。如图 10 所示,其中 Base OS Image,将作为项目中所有 Docker Image 的 base,JDK Image 可以在其基础上继续衍生出其他的 Image。 例如以该 Image 为基础创建 Tomcat Image 等。Liberty Image 可以在其基础上创建更多类型的应用 Image。
2 B2 f6 h! g' C! g4 d( F1 ]图 10. 基于分层存储的 Docker Image 树的多版本衍生. u8 R$ o" m/ x9 C2 A& _
如果其中的 Liberty Image 发生变化的时候,例如需要升级 Liberty 版本的时候,只需要重新更新该节点和该节点之后的其他 Image 节点,而不会影响到 Liberty Image 节点的兄弟节点或者父亲节点以及由这些节点衍生出来的其他的 Docker Image。当更新 App Image 的时候,由于其均来自同样的父亲节点 Liberty Image。 所以每次更新的时候只会做 EAR 包的增量更新。 : d+ i0 H* C* j) a5 R
基于分层机制的 Docker Image 的实践4 V0 }3 B: i- i9 ^( y1 A
如图 11 所示, 按照之前介绍的安装 JDK、Logstash、Liberty 的 Docker Image 大小在 1.8 G 左右。以此为基础创建的的 App Image 的大小在 1.9G 左右。 0 \) B9 y) K1 B. f/ s' B
图 11. Docker Image 分层存储实验 1& a2 x# t% v0 o/ ~5 i3 v) F
; E5 g: z# l! G5 w
在一个已经 download 了 Liberty Docker Image 的环境下下载 App Image。如图 12 所示,可以看到已经存在的 layer 已经是 complete 状态。 唯一 download 的部分只有新增加的 EAR 所产生的新的 layer。所需时间仅仅为 1 分 33 秒。 $ O' r) H( X+ A/ `8 {& y& B
图 12. Docker Image 分层存储实验 2
2 K( V. h1 p3 F' X% p- S0 ?/ S' J
2 u X. q" B! q8 L- l
如果直接在一个不存在 Liberty Docker Image 的 server 上去 download App Docker Image, 如图 13 所示,我们可以看到所需要的时间将超过 7 分钟。
/ v: O! C0 a" s4 @- n, K图 13. Docker Image 分层存储实验 3
# g @+ A, w( L
9 e3 B( C* ?) y
通过图 14 可以发现其他 layer 的 download 时间要超过 4 分钟,如果反复对这些重复的 Docker Image layer 进行下载更新,将会严重影响环境更新的效率。随着不同 Image 之间在 Docker Image Layer 上的差异越大,所花费的下载 Docker Image 的代价也将越大。 $ Q. p) @0 O; @) n4 X- `! u9 H+ w
图 14. Docker Image 分层存储实验 44 D9 H$ Y6 n1 X0 r
小结本文通过对 DevOps 和 Docker 基本概念的介绍以及 Docker Image 分层存储的原理和实践结果说明,希望带给您一个思路,从而根据自身项目的实际情况规划和设计自己的 Docker Image。从而将 Docker 技术和 DevOps 更好的结合起来,构建一个可持续的产品生产,测试,发布的生态环境。 . S. N" k1 I( n# y+ `
原创:孔毅/孟洁
! D0 b9 P7 H4 T7 ~ |