让我们创建一个更小的Docker镜像

我将我的博客文章进行了交叉发布:https://www.ianlewis.org/jp/small-docker-images

最近,容器技术很流行,我对各种工具都感兴趣地去探索。其中最受欢迎的是大家都喜爱的Docker。Docker可以通过docker run轻松创建容器的执行环境,同时可以通过docker build轻松构建容器镜像。Docker的镜像构建是基于类似于Makefile的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,这是为了将整个Debian 8.x映像包含进去,所以映像变得很大。此外,如果Dockerfile中需要构建gcc或g++之类的工具,则会将构建所需的工具和库添加到映像中,尽管这些在运行应用程序时是不必要的,这会增加相当大的体积。

那么,如果我们要创建一个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的RUN命令时,都会保存图像的”层”,并将其状态缓存到图像中。即使最后删除了这些层,但由于在中途提交了层,最终图像的大小仍然保持不变。

如何将其缩小?

由于每次执行RUN命令都会进行提交,所以必须用一个RUN命令来执行所有的操作。

以下是从实际的Redis Dockerfile中提取出的代码片段。

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

用这个运行命令,可以安装、构建、清理建筑用库,所有操作都在一个命令中完成。这样做可以避免镜像变得过大。

依存关系的地狱

大部分的Docker映像是从Debian或Ubuntu映像继承而来的,它们变得很大的原因是,当我们在容器中执行应用程序时,如果该应用程序所依赖的动态链接库没有全部包含在内,那么就会自然崩溃。因此,在构建映像时使用apt-get等工具会很方便。

在谷歌中,所有应用程序都以容器方式运行。为了执行容器应用程序,将不必要的内容放入容器之外并构建为静态二进制文件,只将该二进制文件和必要的文件放入镜像中,这是谷歌的做法。这种方式使镜像更小,对依赖库的管理更加简单,我认为这相当聪明。这也是Go默认编译为静态二进制文件的原因之一。

广告
将在 10 秒后关闭
bannerAds