如何合并Docker的图像层并缩小图像文件

时间:2019-05-13 17:32:22

标签: docker

docker image inspect <name> 给了我16GB

大约20层

以root身份登录时,此 du -hs / 告诉我只有2GB

仅供参考,Dockerfile中已经有多行RUN命令。

我可以将所有层压缩为一层而无需触摸Dockerfile,重建等吗?

或可能通过向Dockerfile添加额外的操作来清除/改善缓存

Dockerfile

FROM heroku/heroku:18

ENV PYENV_ROOT="/pyenv"
ENV PATH="/pyenv/shims:/pyenv/bin:$PATH"
ENV PYTHON_VERSION 3.5.6
ENV GPG_KEY <value>
ENV PYTHONUNBUFFERED 1
ENV TERM xterm
ENV EDITOR vim

RUN apt-get update && apt-get install -y \
    build-essential \
    gdal-bin \
    binutils \
    iputils-ping \
    libjpeg8 \
    libproj-dev \
    libjpeg8-dev \
    libtiff-dev \
    zlib1g-dev \
    libfreetype6-dev \
    liblcms2-dev \
    libxml2-dev \
    libxslt1-dev \
    libssl-dev \
    libncurses5-dev \
    virtualenv \
    python-pip \
    python3-pip \
    python-dev \
    libmysqlclient-dev \
    mysql-client-5.7 \
    libpq-dev \
    libcurl4-gnutls-dev \
    libgnutls28-dev \
    libbz2-dev \
    tig \
    git \
    vim \
    nano \
    tmux \
    tmuxinator \
    fish \
    sudo \
    libnet-ifconfig-wrapper-perl \
    ruby \
    libssl-dev \
    nodejs \
    strace \
    tcpdump \
    # npm & grunt
    && curl -L https://npmjs.com/install.sh | sh \
    && npm install -g grunt-cli grunt \
    # ruby & foreman
    && gem install foreman \
    # installing pyenv
    && curl https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash

COPY . /app
COPY ./requirements /requirements
COPY ./requirements.txt /requirements.txt
COPY ./docker/docker_compose/django/foreman.sh /foreman.sh
COPY ./docker/docker_compose/django/Procfile /Procfile
COPY ./docker/docker_compose/django/entrypoint.sh /entrypoint.sh

# ADD sudoer user django with password django
RUN groupadd -r django -g 1000 && \
    useradd -ms /usr/bin/fish -p $(openssl passwd -1 django) --uid 1000 --gid 1000 -r -g django django && \
    usermod -a -G sudo django && \
    chown -R django:django /app 

COPY --chown=django:django ./docker/docker_compose/django/fish /home/django/.config/fish
COPY --chown=django:django ./docker/docker_compose/django/tmuxinator /home/django/.tmuxinator
COPY ./docker/docker_compose/django/fish /root/.config/fish

WORKDIR /app

RUN sed -i 's/\r//' /entrypoint.sh \
    && sed -i 's/\r//' /foreman.sh \
    && chmod +x /entrypoint.sh \
    && chown django /entrypoint.sh \
    && chmod +x /foreman.sh \
    && chown django /foreman.sh \
    && chown -R django:django /home/django/ \
    && pyenv install ${PYTHON_VERSION%%} \
    && mkdir -p /app/log \
    && pyenv global ${PYTHON_VERSION%%} \
    && pyenv rehash \
    && ${PYENV_ROOT%%}/versions/${PYTHON_VERSION%%}/bin/pip install -U pip \
    && ${PYENV_ROOT%%}/versions/${PYTHON_VERSION%%}/bin/pip install -r /requirements.txt \
    && chown -R django:django /pyenv/ \
    && ${PYENV_ROOT%%}/versions/${PYTHON_VERSION%%}/bin/pip install -r /requirements/dev_requirements.txt

# this user receives ENVs from the top
USER django

ENTRYPOINT ["/entrypoint.sh"]

到目前为止,我已经尝试过:

--squash实验模式中的docker build选项对我而言不是。该Dockerfile是docker-compose中的其他Dockerfile之一。

我也检查了这个: https://github.com/jwilder/docker-squash

,但似乎docker load无法加载压缩的图像。 此外,壁球还给了我8GB的空间(距离预期的2GB距离还很远)

docker save <image_id> | docker-squash -t latest_tiny | docker load

在回答后更新:

当我添加此内容时:

&& apt-get autoremove \             # ? to consider
&& apt-get clean \                  # ? to consider
&& rm -rf /var/lib/apt/lists/*

apt-get--no-cache-dir到每个点,结果是72GB(是的,甚至更多-docker imagespip命令之前显示36GB,最终大小为72GB )。

我的工作目录是明确的(关于COPY)。 du -hs /(作为根用户)仍然有2GB。并且所有图像在重建之前都已删除。

按照@Mihai的方法,我能够将图像从16GB缩小到9GB。

3 个答案:

答案 0 :(得分:2)

有一个简单的技巧可以摆脱中间层。它也会减小尺寸,但是多少取决于它的构建方式。

创建这样的Dockerfile:

FROM your_image as initial

FROM your_image_base

COPY --from=initial / /

your_image_base应该类似于“ alpine”(高山),因此您的图像及其父级的最小图像。

现在构建图像并检查历史记录和大小:

docker build -t your-image:2.0 .
docker image history your-image:2.0
docker image ls

通过这种方式,您无需触摸初始Dockerfile即可创建新的Dockerfile(如果您的过程可接受)。

让我知道这是否可以解决您的问题。

在查看Dockerfile之后更新:

也许我想念它,但是执行安装后看不到您清理apt-get缓存。您的大型RUN命令应在同一行上以“ && rm -rf / var / lib / apt / lists / *”结尾,以免将整个缓存存储在该层上。

答案 1 :(得分:0)

肯定要在主运行命令的末尾添加&& rm -rf /var/lib/apt/lists/*,就像Mihai所说的那样。可能有帮助的另一件事(取决于依赖项的大小)是使用--no-cache-dir选项通过pip安装。另外,请确保您了解build context并考虑使用.dockerignore或将上下文发送到另一个目录(完全取决于您的目录设置方式)

我也很幸运使用dive浏览图像。老实说,这看起来像一个很大的图像,所以不确定是否可以将它放下来

答案 2 :(得分:0)

很简单,直接用

<块引用>

docker commit YOUR_CONTAINER_ID NEW_IMAGE_ID

docker会扔掉中间层,你丢失了历史但体积很小