共计 2478 个字符,预计需要花费 7 分钟才能阅读完成。
引言
最近的工作中,我应用了很多种容器技术,其中最风行的技术当然是 Docker。除了容许你应用 docker run 命令轻松运行容器外,Docker 还提供了一种构建容器镜像的办法以及生成的镜像的格局。通过编写 Dockerfile 并执行 docker build 命令,能够轻松地创立在装置了 Docker 的任何地位(在肯定约束条件下)运行的镜像。
比方,这是一个用于运行简略文件服务器的 DockerFile。
FROM debian:jessie
RUN apt-get update
RUN apt-get install -y python
RUN mkdir -p /data
VOLUME ["/data"]
WORKDIR /data
EXPOSE 8000
CMD ["python", "-m", "SimpleHTTPServer", "8000"]
是一个非常简单的 docker 文件,然而如果你构建它并查看理论大小,你会发现它其实很大。
VIRTUAL SIZE
167.4 MB
为什么镜像看起来如此之大?
在下面的 Dockerfile 的第一行,留神到下面写的是 FROM debian:jessie,这点很重要,因为这意味着咱们将 Docker 镜像基于 Docker Hub 上的 debian:jessie 镜像。之所以会如此之大,是因为该镜像蕴含了整个 Debian 8.x 装置,如果在这之后再装置 gcc,g++ 或其余构建工具之类的货色,镜像将变得更大。
好的,让咱们看一下如何为 Redis 创立 Docker 镜像,Dockerfile 非常简单,下载 redis 源码进行编译装置,而后删除所有用于构建它的工具,因为不须要运行它们。
FROM debian:jessie
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN curl -sSL "http://download.redis.io/releases/redis-3.0.5.tar.gz" -o
redis.tar.gz
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
# 全副删除
RUN rm -f redis.tar.gz
RUN rm -f /usr/src/redis
RUN 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.5
ENV REDIS_DOWNLOAD_URL http://download.redis.io/releases/redis-3.0.5.tar.gz
ENV REDIS_DOWNLOAD_SHA1 ad3ee178c42bfcfd310c72bbddffbbe35db9b4a6
# for redis-sentinel see: http://redis.io/topics/sentinel
RUN 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 默认状况下动态编译应用程序的形式就是因为受到这种编译云原生应用程序的文化的影响。
在稍后无关该主题的文章中,我将对此进行更多介绍。