引言
最近的工作中,我应用了很多种容器技术,其中最风行的技术当然是Docker。 除了容许你应用docker run命令轻松运行容器外,Docker还提供了一种构建容器镜像的办法以及生成的镜像的格局。 通过编写Dockerfile并执行docker build命令,能够轻松地创立在装置了Docker的任何地位(在肯定约束条件下)运行的镜像。
比方,这是一个用于运行简略文件服务器的DockerFile。
FROM debian:jessieRUN apt-get updateRUN apt-get install -y pythonRUN mkdir -p /dataVOLUME ["/data"]WORKDIR /dataEXPOSE 8000CMD [ "python", "-m", "SimpleHTTPServer", "8000" ]
是一个非常简单的docker文件,然而如果你构建它并查看理论大小,你会发现它其实很大。
VIRTUAL SIZE167.4 MB
为什么镜像看起来如此之大?
在下面的Dockerfile的第一行,留神到下面写的是FROM debian:jessie,这点很重要,因为这意味着咱们将Docker镜像基于Docker Hub上的debian:jessie镜像。 之所以会如此之大,是因为该镜像蕴含了整个Debian 8.x装置,如果在这之后再装置gcc,g++或其余构建工具之类的货色,镜像将变得更大。
好的,让咱们看一下如何为Redis创立Docker镜像,Dockerfile非常简单,下载redis源码进行编译装置,而后删除所有用于构建它的工具,因为不须要运行它们。
FROM debian:jessieRUN apt-get updateRUN apt-get install -y gcc libc6-dev makeRUN curl -sSL "http://download.redis.io/releases/redis-3.0.5.tar.gz" -oredis.tar.gzRUN mkdir -p /usr/src/redisRUN tar -xzf redis.tar.gz -C /usr/src/redisRUN make -C /usr/src/redisRUN make -C /usr/src/redis install# 全副删除RUN rm -f redis.tar.gzRUN rm -f /usr/src/redisRUN apt-get purge -y --auto-remove gcc libc6-dev make...
Docker应用层layer创立镜像,Dockerfile中每一个命令都会创立一个新的层,每层都蕴含执行命令前后的状态之间镜像的文件系统更改。在下面的例子中即便咱们在最初删除了构建工具,它们仍蕴含在Docker须要构建以后层的上一层中,因而,咱们为放大镜像所做的所有工作都没有任何成果!
怎样才能让镜像变小?
您可能曾经猜到了正确的解决方案,放大镜像的办法是在咱们删除了构建工具和库之后仅创立一个镜像layer,能够通过在Dockerfile中的单个RUN命令中执行以上所有命令来做到这一点。
以下是Docker Hub上Redis Dockerfile(Docker BSD LICENSE)的摘录:
ENV REDIS_VERSION 3.0.5ENV REDIS_DOWNLOAD_URL http://download.redis.io/releases/redis-3.0.5.tar.gzENV REDIS_DOWNLOAD_SHA1 ad3ee178c42bfcfd310c72bbddffbbe35db9b4a6# for redis-sentinel see: http://redis.io/topics/sentinelRUN buildDeps='gcc libc6-dev make' \ && set -x \ && apt-get update && apt-get install -y $buildDeps --no-install-recommends \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /usr/src/redis \ && curl -sSL "$REDIS_DOWNLOAD_URL" -o redis.tar.gz \ && echo "$REDIS_DOWNLOAD_SHA1 *redis.tar.gz" | sha1sum -c - \ && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \ && rm redis.tar.gz \ && make -C /usr/src/redis \ && make -C /usr/src/redis install \ && rm -r /usr/src/redis \ && apt-get purge -y --auto-remove $buildDeps
能够看到它装置了所有构建依赖项,下载了Redis源代码,构建了Redis,而后删除了所有构建工具,并在一个RUN命令中全副革除了apt缓存,这确保了Docker仅在删除所有不必要的资源后才创立镜像层。
这不会解决包含整个操作系统的问题,但至多解决了镜像中蕴含额定的构建依赖项的问题。
依赖的天堂
Docker镜像通常从Debian或Ubuntu镜像继承,须要它们的一个起因是应用程序动静链接到许多库,而这些库是利用程序运行所必须的,造成这种状况的另一个起因是,所有失常的Linux工具都已装置,因而应用apt调试和装置新软件会更加容易。
在Google,数据中心中运行的所有应用程序都在容器内运行,因为须要将二进制文件复制到须要运行它们的计算机上,因而在容器镜像或archive文件中蕴含一堆货色是一种节约,会减少额定的网络开销,为了使应用程序失常工作,它们都被构建为动态二进制文件。 我认为这是一种很棒的解决形式,因为它容许应用程序将所有必须的局部内置到镜像中并升高复杂性。 Go默认状况下动态编译应用程序的形式就是因为受到这种编译云原生应用程序的文化的影响。
在稍后无关该主题的文章中,我将对此进行更多介绍。