Makisu:Uber开源的快速Docker镜像生成工具

640

为了保证业务平稳发展,我们引入了一种使得工程师们可以动态高效快速部署上千台服务的微服务架构,这种服务大大提高了我们平台上的乘客司机的使用体验。
尽管这种模式支撑了我们快速增长的应用环境,但是由于业务规模太大也带来了痛点。为了容易维护和升级微服务,2015年采用了Docker技术,确保资源和服务被打包成一个单元。
随着Docker的发展,核心架构团队开发了一套快速高效为Apache Mesos和基于Kubernetes的容器生态产生Dockerfiles配置文件并将应用代码打包在Docker image中的技术。考虑到微服务技术的快速发展,我们开源了核心模块,Makisu[1],以便其它用户能够收到同样的效果。


Uber的Docker之路

640

2015年早期,我们在裸服务器上部署了大约400个服务,他们共享主机上的依赖包和配置文件,仅有很少资源限制。随着工程师规模扩大,依赖管理和资源隔离成为一个问题。为了解决这个问题,核心架构团队开始将服务移植到Docker中,随之建立了标准化和流程化的容器创建流程自动化机制。
新容器化运行环境在服务生命周期管理的运行速度和可靠性方面带来很大提高。然而,访问服务依赖的密钥被打包进image,带来了潜在的安全隐患。简单说,一旦一个文件被放入Docker image中,就会永久存在。尽管可以通过其他这种手段隐藏这些密钥,但是Docker并不提供真正将他们从image中移除的功能。
其中一个解决方案是docker-squash[2],一个删除Docker image中间步骤所需文件的开源工具,但是带来的问题就是创建image的时间翻倍,这个问题基本抵消了采用微服务架构带来的好处。
为了解决这个问题,我们决定分叉Docker自研我们需要的功能。如果在创建image时候,把所需的密钥以volume方式挂载,这样最终的Docker image中就不留任何密钥的痕迹。因为没有额外延迟,而且代码更改也很少,因此这方法很有效。架构团队和服务团队都满意了,容器架构被更好地利用起来。


大规模编译容器image

640

到了2017年,这种架构不再能满足需求。随着Uber的增长,平台规模也同样受到很大挑战。每次创建超过3000个服务,每天有若干次,大大增加了消耗时间。有些需要2个小时,大小超过10GB,消耗大量存储空间和带宽,严重影响开发者生产率。
此时,我们认识到创建可以扩展的容器image是很重要的。为此提出了三个需求:无特殊权限创建,支持分布式cache,image大小优化。
无特殊权限创建
2017年,核心架构团队开始将Uber的计算负载迁移到提供自动化、可扩展和更加弹性化的统一平台上。随之而来,Dockerfile也需要能够运行在共享集群上的容器中。
不幸的是,Docker创建逻辑依赖于一种通过对比创建时间来决定不同层次之间不同的copy-on-write文件系统。这个逻辑需要特权挂载或者卸载容器内部的目录,以便给新系统提供安全机制。也就意味着,Docker无法做到无root权限创建。
支持分布式缓存(cache)
通过分层缓存(cache)技术,用户可以复用之前的创建版本和层级,可以减少执行时候的冗余。Docker为每个创建提供分布式缓存,但是并不支持不同分支和服务。需要依靠Docker本地缓存层,但是因为集群内的生成新版本要求不断清空缓存,造成缓存命中率大大降低。
过去,Uber采用指定机器创建指定服务的方式提高命中率,然而,这种方法对于多种服务构成的系统来说显然是不够的。考虑到我们每天会使用上千种服务,这个过程也增加了调度复杂性。
显然一个好的缓存策略对我们的方案更加重要,最终分布式缓存方案既可以解决性能问题,也能够解决创建系统时的调度问题。
优化image大小
小images节省空间,并且可以节省转换、压缩和启动时间。
为了优化image大小,我们计划采用多阶段步骤。在众多方案中并不很特别:通过中间态image,将运行时所需文件拷入瘦身的最终image。尽管需要比较负杂的Dockerfiles,但可以减小image大小,因此可以很好地弹性部署。
另外,通过减少image中的层数也可以减少image大小,image比较大有可能是某些文件被中间层创建,删除或者更新的结果。如前所述,即使后续步骤删除了临时文件,但是在开始层中仍然存在,占据相应空间。减少层数可以大大减少删除或更新的文件在之前层中依然存在的可能性,因此可以减小image大小。


介绍Makisu

640

为了实现以上想法,我们开发了自己的image工具,Makisu[1],实现更加动态,更快容器创建,更加弹性等功能。其特点包括:
  • 不需要特殊权限,开发过程更加容易移植;

  • 开发集群内部使用分布式层间缓存提高性能;

  • 提供灵活层间管理,减少images中不必要文件;

  • 与容器Docker兼容;支持标准和多阶段开发命令。


下面详细介绍这些特性。
不需要特殊权限
与其它虚机相比Docker image更加轻量是因为中间层只包括运行开发步骤前后文件系统的差别。Docker计算差别,并使用需要特权的CoW文件系统生成中间层。
为了实现不需要特权生成中间层,Makisu在内存中进行文件系统扫描。运行开发步骤后,在此扫描文件系统,更新内存视图,将变化文件添加到新一层。
Makisu也对压缩速度进行了优化,这对弹性部署非常重要。Docker使用Go中默认gzip库压缩层级,当遇到带有大量text文件的image层来说性能很慢。文件扫描阶段后,即使没有缓存,Makisu在很多方面比Docker要快,其中P90开发时间将近节省50%。
分布式缓存
Makisu用key-value数据库映射Dockerfiles中操作行到存放在Docker镜像仓库中的层数。key-value数据库可以用Redis或者文件系统。Makisu也用缓存TTL确保缓存内容不会存放太久。
缓存key用当前开发命令和前一条命令的key一起生成。缓存值是生成层内容的哈希值,也用来定位当前层在Docker镜像仓库中的位置。
在Dockerfile的初始化阶段,层生成并且异步推到Docker镜像仓库和key-value库中。后续同样步骤可以从缓存层中获取并解压获取,避免冗余操作。
灵活层间操作
为开发过程对iamge层进行控制,Makisu映入了新的操作注释:#!COMMIT,指代Dockerfile中可以生成新层的行。这一简单机制对减少容器image大小很关键( 后续操作要删除或者更新文件 ),解决了密钥跨层存取的问题。每个commit层在分布式缓存中得以体现,集群中其它开发者也可以使用这一更新结果。
以下是一个Dockerfile的实例,其中使用了Makisu的操作注释:


 
 
  1. FROM debian:8 AS build_phase

  2. RUN apt-get install wget #!COMMIT

  3. RUN apt-get install go1.10 #!COMMIT

  4. COPY git-repo git-repo

  5. RUN cd git-repo && make


  6. FROM debian:8 AS run_phase

  7. RUN apt-get install wget #!COMMIT

  8. LABEL service-name=test

  9. COPY from=build_phase git-repo/binary /binary

  10. ENTRYPOINT /binary


本例中,安装了运行时需求包(wget和go1.10),并在相应层内commit,后续创建服务代码。当这些committed层创建后,在分布式缓存中得以更新,其它开发这可以使用,大大提高了开发工作冗余操作的速度。
第二阶段,开发再次安装wget,这次Makisu重用了之前生成的代码。最后,服务代码从开发阶段拷贝到最终image,并生成最终image。这一示例生成一个瘦身的最终image,具体结构如图一所示:

640

图一:Docker为每一步启动一个新容器并生成三层,Makisu在一个容器中编排所有步骤并跳过不必要的层生成

Docker兼容
Docker image一般是由一些明文按顺序展开的tar文件和两个配置文件构成,Makisu生成的image跟Docker Daemon和镜像仓库完全兼容。
Makisu也支持多阶段开发,通过#!COMMIT的引入,可以实现不必要步骤跳过,并节省空间。
另外,因为#!COMMIT格式化为注释,Makisu使用的Dockerfiles可以被Docker完全兼容。
如何使用Makisu

640

如果想使用Makisu,用户可以直接下载二进制代码,并且不带RUN地运行简单Dockerfiles。用户可以下载Makisu,运行在Docker容器内部,或者作为Kubernetes/Apache Mesos持续集成的工作流。
  • 本地使用Makisu二进制代码,https://github.com/uber/makisu#building-makisu-binary-and-build-simple-images

  • 本地使用Makisu image,https://github.com/uber/makisu#makisu-anywhere

  • 作为Kubernetes工作流运行Makisu,https://github.com/uber/makisu#makisu-on-kubernetes


相关链接:
  1. https://github.com/uber/makisu

  2. https://github.com/jwilder/docker-squash


原文链接:https://eng.uber.com/makisu/?amp=


基于Kubernetes的DevOps实践培训

640?


基于Kubernetes的DevOps实践培训将于2019年1月18日在上海开课,3天时间带你系统掌握Kubernetes本次培训包括:容器特性、镜像、网络;Kubernetes架构、核心组件、基本功能;Kubernetes设计理念、架构设计、基本功能、常用对象、设计原则;Kubernetes的数据库、运行时、网络、插件已经落地经验;微服务架构、组件、监控方案等,点击下方图片查看详情。
640?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由网站热图生成工具ClickHeat 1.4版本开源软件制作而成的Docker镜像导出文件,仅需要本机可以运行docker容器即可,无需下载ClickHeat源码,紧需要执行下面步骤即可运行ClickHeat系统,然后在系统中针对要生成热图的网站页面做配置即可。 ClickHeat Docker镜像导出文件使用步骤: 1. 将本资源下载文件clickheat-1.0-docker.zip 拷贝到可以运行docker的环境中 2. 执行下面命令加载clickheat镜像导出文件 docker load --input clickheat-1.0-docker.zip 运行docker images 会发现多了一个叫 dugwood/clickheat 1.0版本的Docker 镜像文件,没错加载镜像成功 3.执行下面命令运行clickheat容器,映射端口到docker宿主机的80端口,后面可以直接通过docker宿主机的80端口来访问clickheat服务了 docker run -it -p 80:80 dugwood/clickheat:1.0 4.在浏览器地址栏输入http://docker宿主机IP地址 访问clickheat系统。第一次访问clickheat系统会自动检查clickheat系统环境配置,并提示用户做基础配置,包括设置管理员账户名和密码,访客用户名和密码等。设置完成后,可以进入页面对要监控和绘制网页热区的的具体页面做配置即可。 如果需要进入到已运行的clickheat容器的shell中做操作,可以执行下面命令: 1. 运行docker ps 查找你正在运行clickheat服务的容器的container ID 2. 运行下面命令获取正在运行clickheat服务所在容器的shell docker exec -it CONTAINER_ID bash 希望本资源可以帮到您。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值