introduction
In my recent work, I have used many container technologies, the most popular of which is of course Docker. In addition to allowing you to use the docker run command to easily run containers, Docker also provides a method for building container images and the format of the generated images. By writing a Dockerfile and executing the docker build command, you can easily create an image that runs anywhere (subject to certain constraints) where Docker is installed.
For example, this is a DockerFile for running a simple file server.
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" ]
It is a very simple docker file, but if you build it and check the actual size, you will find that it is actually quite large.
VIRTUAL SIZE
167.4 MB
Why does the mirror look so big?
In the first line of the Dockerfile above, notice that it says FROM debian:jessie. This is important because it means that we base the Docker image on the debian:jessie image on Docker Hub. The reason why it is so big is because the mirror contains the entire Debian 8.x installation. If you install gcc, g++ or other build tools after that, the mirror will become larger.
Okay, let's take a look at how to create a Docker image for Redis. The Dockerfile is very simple. Download the redis source code, compile and install, and then delete all the tools used to build it, because there is no need to run them.
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 uses the layer layer to create a mirror. Each command in the Dockerfile creates a new layer, and each layer contains the file system changes of the mirror between the states before and after the command is executed. In the above example, even if we delete the build tools at the end, they are still included in the layer above the current layer that Docker needs to build. Therefore, all the work we have done to shrink the image has no effect!
How can I make the mirror smaller?
You may have guessed the correct solution. The way to shrink the image is to create only one image layer after we delete the build tools and libraries. This can be done by executing all the above commands in a single RUN command in the Dockerfile.
The following is an excerpt from the 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
You can see that it installed all the build dependencies, downloaded the Redis source code, built Redis, then deleted all the build tools, and cleared all the apt caches in a RUN command, which ensures that Docker is only removing all unnecessary The mirror layer is created only after the resources.
This will not solve the problem of including the entire operating system, but at least it will solve the problem of including additional build dependencies in the image.
Dependent hell
Docker images are usually inherited from Debian or Ubuntu images. One reason for their need is that applications are dynamically linked to many libraries, and these libraries are necessary for the application to run. Another reason for this is that all normal Linux tools Are already installed, so it's easier to debug and install new software with apt.
At Google, all applications running in the data center run in containers. Since binary files need to be copied to the computer that needs to run them, including a bunch of things in the container image or archive file is a waste and will increase With additional network overhead, in order to make the application work properly, they are all built as static binary files. I think this is a great way to deal with it, because it allows the application to build all the necessary parts into the image and reduce complexity. By default, Go statically compiles applications because of the influence of this culture of compiling cloud-native applications.
I will cover this more in a later article on this topic.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。