A tableau of crimes and misfortunes: the ever-useful `docker history`

栏目: IT技术 · 发布时间: 4年前

内容简介:If you want to understand a Docker image, there is no more useful tool than theLet’s see what this command does, what it can teach us about the construction of Docker images, and some examples of why it’s so useful.Consider the following Docker image:

If you want to understand a Docker image, there is no more useful tool than the docker history command. Whether it’s telling you why your image is so large, or helping you understand how a base image was constructed, the history command will let you peer into the innards of any image, allowing you to see the good, the bad, and the ugly.

Let’s see what this command does, what it can teach us about the construction of Docker images, and some examples of why it’s so useful.

The construction of a Docker image

Consider the following Docker image:

$ docker image ls mysteryimage
REPOSITORY    TAG      IMAGE ID       SIZE
mysteryimage  latest   24e6dd67bf8a   165MB

Given an image, we might have some questions:

  • What does it do?
  • What will happen when I run it?
  • How was it created?

The docker image history command, or it’s older synonym docker history , can help answer all these questions.

$ docker image history mysteryimage 
IMAGE      CREATED  CREATED BY                          SIZE
24e6dd67   2 mins   #(nop)  ENTRYPOINT ["python" "exa…  0B  
59102aef   2 mins   #(nop) COPY file:cc6452cd5813b9d2…  0B  
9d84edf3   7 weeks  #(nop)  CMD ["python3"]             0B  
<missing>  7 weeks  set -ex;   savedAptMark="$(apt-ma…  8MB
<missing>  7 weeks  #(nop)  ENV PYTHON_GET_PIP_SHA256…  0B  
<missing>  7 weeks  #(nop)  ENV PYTHON_GET_PIP_URL=ht…  0B  
<missing>  7 weeks  #(nop)  ENV PYTHON_PIP_VERSION=20…  0B  
<missing>  7 weeks  cd /usr/local/bin  && ln -s idle3…  32B 
<missing>  7 weeks  set -ex   && savedAptMark="$(apt-…  80MB
<missing>  7 weeks  #(nop)  ENV PYTHON_VERSION=3.8.3    0B  
<missing>  7 weeks  #(nop)  ENV GPG_KEY=E3FF2839C048B…  0B  
<missing>  7 weeks  apt-get update && apt-get install…  7MB
<missing>  7 weeks  #(nop)  ENV LANG=C.UTF-8            0B  
<missing>  7 weeks  #(nop)  ENV PATH=/usr/local/bin:/…  0B  
<missing>  7 weeks  #(nop)  CMD ["bash"]                0B 
<missing>  7 weeks  #(nop) ADD file:4d35f6c8bbbe6801c…  69MB

Docker images are constructed in layers, each layer corresponding to a first approximation to a line in a Dockerfile . The history command shows these layers, and the commands used to create them.

So what we have here is more or less the equivalent of the Dockerfile that constructed the image. And we can use this to answer a number of questions.

What is this Docker image going to run?

To figure out what the image will run, we just need to find the topmost ENTRYPOINT or CMD . We can use the --no-trunc argument to show the full, untruncated commands:

$ docker image history mysteryimage --no-trunc | grep ENTRYPOINT
sha256:24e6dd67bf8a   4 minutes ago       /bin/sh -c #(nop)  ENTRYPOINT ["python" "example.py"]

What was in the base image?

We can see what went into constructing the base image: you can differentiate the base image from the current image by the creation time for each layer. The base image was apparently created 7 weeks ago.

You can also see the ID of the base image, in case you want to docker run it.

What commands made the image size larger?

Notice that the output above has a SIZE column, showing you the size of each layer.

That means you can tell which specific steps in the Dockerfile contributed the most to the image size. In this example, 80MB came from one particular step:

$ docker image history mysteryimage --no-trunc | grep 80MB
<missing>    7 weeks ago       /bin/sh -c set -ex   && savedAptMark="$(apt-mark showmanual)"  && apt-get update && apt-get install -y --no-install-recommends   dpkg-dev   gcc   libbluetooth-dev   libbz2-dev   libc6-dev   libexpat1-dev   libffi-dev   libgdbm-dev   liblzma-dev   libncursesw5-dev   libreadline-dev   libsqlite3-dev   libssl-dev   make   tk-dev   uuid-dev   wget   xz-utils   zlib1g-dev   $(command -v gpg > /dev/null || echo 'gnupg dirmngr')   && wget -O python.tar.xz "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz"  && wget -O python.tar.xz.asc "https://www.python.org/ftp/python/${PYTHON_VERSION%%[a-z]*}/Python-$PYTHON_VERSION.tar.xz.asc"  && export GNUPGHOME="$(mktemp -d)"  && gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$GPG_KEY"  && gpg --batch --verify python.tar.xz.asc python.tar.xz  && { command -v gpgconf > /dev/null && gpgconf --kill all || :; }  && rm -rf "$GNUPGHOME" python.tar.xz.asc  && mkdir -p /usr/src/python  && tar -xJC /usr/src/python --strip-components=1 -f python.tar.xz  && rm python.tar.xz   && cd /usr/src/python  && gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"  && ./configure   --build="$gnuArch"   --enable-loadable-sqlite-extensions   --enable-optimizations   --enable-option-checking=fatal   --enable-shared   --with-system-expat   --with-system-ffi   --without-ensurepip  && make -j "$(nproc)"   LDFLAGS="-Wl,--strip-all"  && make install  && ldconfig   && apt-mark auto '.*' > /dev/null  && apt-mark manual $savedAptMark  && find /usr/local -type f -executable -not \( -name '*tkinter*' \) -exec ldd '{}' ';'   | awk '/=>/ { print $(NF-1) }'   | sort -u   | xargs -r dpkg-query --search   | cut -d: -f1   | sort -u   | xargs -r apt-mark manual  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false  && rm -rf /var/lib/apt/lists/*   && find /usr/local -depth   \(    \( -type d -a \( -name test -o -name tests -o -name idle_test \) \)    -o    \( -type f -a \( -name '*.pyc' -o -name '*.pyo' \) \)   \) -exec rm -rf '{}' +  && rm -rf /usr/src/python   && python3 --version   80MB

Apparently this step compiles Python from source.

Not just the Dockerfile

The commands reported by docker image history are even more useful than the original Dockerfile insofar as they also include the values of build arguments in any subsequent RUN commands.

This can be useful for security auditing. For example, you might discover the image made the mistake of using the ARG command for build secrets, thus unintentionally leaking credentials:

$ docker pull itamarst/verysecure
...
$ docker image history itamarst/verysecure
IMAGE        CREATED BY                                   
0b51ddadfcd  |1 ANOTHER_SECRET=oscillation-overthruster /…
<missing>    /bin/sh -c #(nop) WORKDIR /tmp               
<missing>    /bin/sh -c #(nop)  ARG ANOTHER_SECRET        
...

There are of course other, more secure ways to use build secrets in Docker .

Or you might discover the name of an internal server in a commercially-built Docker image, and the fact they’re still using FTP:

$ docker history --no-trunc image_name_elided | grep ftp
<missing>  4 weeks ago    |2 FTP_PATH=ftp://kits-ftp/kits/unreleased_ftp/PRODUCTS//PRODUCT-dockerubuntux64.tar.gz  ....

The primary use case: figuring out why your image is too large

While docker history is useful in understanding how images are built, and occasionally for getting a glimpse into an insecure setup, the thing it’s most useful for is figuring out why an image is too large.

The first thing you should do when you have an overly large image is use docker image history to see which layers are contributing the most to image size. Often that’ll be enough to tell you exactly what’s going on.


以上所述就是小编给大家介绍的《A tableau of crimes and misfortunes: the ever-useful `docker history`》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品经理修炼之道

产品经理修炼之道

费杰 / 机械工业出版社华章公司 / 2012-7-30 / 59.00元

本书由资深产品经理、中国最大的产品经理沙龙Pmcaff创始人费杰亲自执笔,微软、腾讯、百度、新浪、搜狐、奇虎、阿里云、Evernote等国内外20余家大型互联网企业资深产品经理和技术专家联袂推荐。用系统化的方法论和丰富的实战案例解读了优秀产品经理所必须修炼的产品规划能力、产品设计能力、产品执行能力,以及思考、分析和解决问题的能力和方法,旨在为互联网产品经理打造核心竞争力提供实践指导。 全书一......一起来看看 《产品经理修炼之道》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器