企业级Docker镜像仓库的管理和运维
DianneBorde
8年前
<p>容器应用的使用越来越广泛,容器技术突出的优点就是开发运维一体化。通过把应用及其所依赖的软件包、操作系统文件等封装在容器镜像中,使得应用在开发、测试和发布过程中都具有相同的运行环境,带来极大的便利。从图1这张经典的Docker容器状态转换图可以看到,容器镜像(images)的关联箭头最多,不言而喻,镜像就是容器技术的核心所在。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/dca1d2ad32c79706288cd99c511c9604.png"></p> <p>图1 Docker容器状态转换图</p> <p>概括地说,容器技术包含一静一动两部分:封装应用的静态镜像(images)和运行应用的动态容器(containers)。相应地,容器的开发运维主要涉及镜像管理和运行时(Runtime)管理两部分。本文主要和大家谈谈容器镜像管理的部分。</p> <p>容器镜像的管理主要围绕镜像仓库(registry)来进行。在应用的生命周期中,无论开发人员或CI系统发布镜像,还是测试人员或运维人员下载镜像,都要通过镜像仓库来完成。镜像仓库可以使用公有的SaaS服务,例如Docker Hub。公有服务的优点是可直接使用,无需自己维护。但考虑到访问效率和镜像安全等方面的原因,大多数公司都建立了自己的私有镜像仓库(Registry),因此也需要有贯穿整个应用生命周期的镜像管理策略。</p> <p>下文主要介绍在开发运维中的管理容器镜像原理和方法,为了便于说明原理,较多地使用Harbor作为例子。Harbor是由VMware中国研发团队负责开发的开源企业级Registry,可帮助用户迅速搭建企业级的registry 服务,提供权限控制、镜像同步、中文管理界面等强大功能,深受广大用户喜爱。有兴趣的朋友可以关注或使用: https://github.com/vmware/harbor 。</p> <p>确保镜像内容的一致性</p> <p>在应用的开发、测试和运行等各个阶段,需要确保都使用同一个应用的镜像。一种做法是在每个阶段都用相同dockerfile去生成所需镜像。通常认为,相同的dockerfile可以构件出相同的镜像,而实际上却并非如此。例如下面的dockerfile 部分:</p> <p>FROM ubuntu</p> <p>RUN apt-get install –y python</p> <p>ADD app.jar /myapp/app.jar</p> <p>首先,FROM的基础镜像隐含使用了latest版本,在不同时间构建的镜像,可能是不同的版本。即使指明了ubuntu:14.04这样的版本号也不保险,因为相同版本的系统可能含有补丁等不尽相同的软件包。</p> <p>再看apt-get这样的命令(类似的还有curl,wget等),往往会从互联网上引入第三方的软件包,版本的一致性就更加无从确定了。还有在ADD语句中添加到镜像里面的文件app.jar,取决于构建时的文件版本,也是一个不确定的因素。</p> <p>从上面的例子可以看到,尽管docker镜像的目的是构造不可更改的应用环境,但由于其构建的时候往往具有不确定的输入,相同dockerfile生成的镜像未必包含相同的内容。因此,最好的方法还是在不同的环境中始终采用相同的镜像(二进制格式),虽然在传输量上比dockerfile要大,但是可以确保镜像的一致性。</p> <p>镜像的传输</p> <p>很多用户在开发、测试和运维中都使用同一个Registry作为镜像仓库,这种方式比较适合小团队或简单的项目。在其他情况下,最好使用多个Registry以区分不同的用途和安全控制要求。容器镜像管理的参考流程(如图2所示)。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/02c4fe0ad6182a6d630434ba68bed2e3.png"></p> <p>图2 应用镜像的管理流程</p> <p>开发环境的Registry: 主要由开发人员使用,镜像变化频繁。当开发完成后,通过CI系统生成稳定镜像,并同步到测试Registry;</p> <p>测试环境的Registry: 主要由测试人员使用,镜像保持不变。当测试通过后,镜像推送到准生产环境的Registry;</p> <p>准生产环境(Staging)的Registry: 主要由测试和运维人员使用,镜像保持不变。当准生产环境试运行后平稳后,再发布到生产环境的Registry;</p> <p>生产环境的Registry: 发布镜像到生产环境的节点运行。</p> <p>从开发到生产的整个过程中,符合要求的容器镜像会逐步进入下一级的Registry,最后到达生产系统,从而实现容器镜像的构建-传输-运行(Build-Ship-Run)过程。</p> <p>Harbor提供Registry之间的镜像自动同步和复制功能,通过配置复制策略,自动化管理镜像传输流程。Harbor的复制策略启动之后,会比较目标Registry和本地源Registry在镜像上的差异,并把目标Registry缺少的镜像从本地推送过去,使得两个Registry实例的镜像完全一致。后续推送到源实例上的镜像,会以增量的形式同步到目标实例上。当在源实例上删除镜像的时候,目标实例上的镜像也会被删除。通过Harbor的复制机制,可实现两个或多个registry实例之间的镜像同步。</p> <p>镜像的权限控制</p> <p>在企业中,通常有不同的开发团队来负责不同的应用项目,和源代码分项目管理一样,镜像也需要按照项目来存放和管理。由于项目团队中有不同的成员,如项目经理、产品经理、开发、测试和运维等人员,每种人员使用镜像的需求不同,因此可以根据角色分配相应的权限。</p> <p>例如,测试人员通常只需要镜像的读权限(pull),开发人员需要读写权限(push/pull),项目经理除了拥有开发人员的权限之外,还可以增加和删除项目成员,设定他们的角色。</p> <p>在Harbor Registry中,每个项目中可有三种角色:项目管理员(project admin)、开发者(developer)和客人(guest)。某些项目,如放在library中的公共镜像, 可以允许匿名访问,即用户不用docker login也可以访问,这样方便某些场景的使用。在整个系统中,还设有系统管理员,具有维护镜像同步策略、用户增删等权限。</p> <p>需要指出的是,在不同的环境中,某个成员的角色可以不同。例如,在开发环境的registry中,运维人员一般不需要权限(或只需要读权限);而在生产环境中的Registry,运维人员就需要有读写权限。</p> <p>大规模镜像发布方式</p> <p>在实际生产运维的中,往往需要把镜像发布到几十、上百台或更多的集群节点上。这时,单个Registry已经无法满足大量节点的下载需求,因此要配置多个registry实例做负载均衡。手工维护多个registry实例上的镜像,将是十分繁琐的事情。Harbor支持一主多从的镜像发布模式,可以解决大规模镜像发布的难题。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/228c155cbe7776a444342a8d6c623419.png"></p> <p>图3 主从模式的镜像分发</p> <p>如图3所示,只要往一台registry上发布,镜像就像“仙女散花”般地同步到多个registry中。</p> <p>如果是地域分布较广的多数据中心或跨云的集群,还可以采用层次型发布方式,如从集团总部同步到省公司,从省公司再同步到市公司(如图4所示):</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/f7a757c0ac8fbe1e122278ad49440107.png"></p> <p>图4 多级主从模式的镜像分发</p> <p>在同步过程中,如果源镜像已删除,Harbor会自动同步删除远端的镜像。在镜像同步复制的过程中,Harbor会监控整个复制过程,遇到网络等错误,会自动重试。</p> <p>同步复制的监控画面如图5所示:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/92f85a520168f7d8e078739e2a0569a9.png"></p> <p>图5 镜像复制策略的监控</p> <p>镜像删除和空间回收</p> <p>Docker命令没有提供Registry镜像删除功能,系统日积月累地运行中,将会产生许多无用的镜像,占用大量存储空间。若要删除镜像并回收空间,需要调用docker registry API来完成,非常麻烦。Harbor提供了可视化的镜像删除界面,可以逻辑删除镜像。在维护状态下可以回收垃圾镜像的空间。</p> <p>Registry高可用性</p> <p>Registry高可用性(HA)是多数生产系统需要关心的问题,基本要求就是没有单点故障。通常需要根据允许服务中断的时间,以及可以承受的成本和损失,来确定采用的技术。下面介绍3种不同的高可用参考方案。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/9f8804d22a6b040a50665c6b6b121ab6.png"></p> <p>图6用共享存储实现多Registry实例</p> <p>一种比较标准的方案,就是多个的Registry实例共享同一个后端存储,任何一个实例持久化到存储的镜像,都可被其他实例中读取。通过前置LB进来的请求,可以分流到不同的实例中去处理,实现了负载均衡,也避免了单点故障(如图6所示)。</p> <p>应该指出,实际中需要考虑的问题远比上述模型复杂。例如,共享存储的选取,用户session在不同的实例上共享等等。用户可根据自己业务要求设计出不同的方案。Harbor将会推出基于swift分布式存储,以及共享session的方案(采用redis)来满足用户的需求。</p> <p>如果没有共享存储,可采用第2种方案,就是在两个节点间采用双主复制策略,互相复制镜像。即使有一个实例失效,另一个实例仍然可以提供服务,从而在一定程度上可以满足HA的需求。在这种场景下,两个实例的用户数据并没有同步,因此需要分别配置相同的用户账号(如图7所示)。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/e6ad042f5213f4e384ecb454169f7f86.png"></p> <p>图7 双主复制实现准HA</p> <p>第3中方案是利用已有的高可用平台,例如vSphere HA,配合分布式存储VSAN,可以实现Registry的高可用性, 具体架构如图8所示:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/c16525c8a7f62b04b95acfe6bb01efdb.png"></p> <p>图8 基于VSAN和vSphere搭建高可用Registry架构</p> <p>节点出现故障的时候,有vSphere自动切换到好的节点上,镜像数据不丢失(如图9所示)。</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/a3a202e7910f7418e51920776b189cfe.png"></p> <p>图9 用VSAN和vSphere实现Registry自动迁移</p> <p>小结</p> <p>本文以开源Harbor Registry为例子,总结了企业中Registry的常见使用场景和要点,希望对大家有所启发。同时也欢迎大家使用Harbor和反馈意见, Harbor的github地址:https://github.com/vmware/harbor 。</p> <p> </p> <p> </p> <p>来自:http://www.chinacloud.cn/show.aspx?id=24271&cid=12</p> <p> </p>