How to write elegant Dockerfile

REVIEW

Kubernetes from the beginning of the container, and the container they need from Dockerfile start, this article describes how to write an elegant Dockerfile file.

This article mainly includes:

  • Docker container
  • Dockerfile
  • The use of multi-stage build

Thanks We provide a lot of machine resources and time so that we can practice, thanks to the support of some of the projects and staff on this topic continue to practice.

A, Docker container

Features 1.1 container

We all know that the container is a standard software unit, which has the following characteristics:

  • Run Anywhere: container can code and configuration files related to package dependencies to ensure operation in any environment is the same.
  • Resource utilization: a process container provides isolation stages, it is possible to more finely set the CPU and memory usage, and thus better utilization of computing resources of the server.
  • Rapid expansion: Each container can be run as a separate process, and can share system resources underlying operating system, so that the container can speed up the startup and stop efficiency.

1.2 Docker container

Currently on the market mainstream container engines Docker, Rocket / rkt, OpenVZ / Odin, and so on, and dominate the party vessel engine is the most used engine Docker containers.

Docker container is isolated from the rest of the system with a series of processes, all of the files needed to run these processes provided by another mirror, the whole process from development to test to production of, Linux containers portability and consistent sex. Repeat with respect to the development of channels depend on the traditional test environment running speed of the vessel is much faster, and supports a variety of mainstream deployed on cloud platforms (PaaS), and the local system. Docker container solves the "normal development environment can run a variety of on-line collapse" embarrassing.

Docker containers features:

  • Lightweight: container is a resource isolation process level, while the virtual machine is isolated from the operating system level resources, so Docker container relative to the virtual machine, it can save more resource overhead, because Docker containers no longer need this layer operation GuestOS the system.
  • Fast: Start and create a container without starting GuestOS, even millisecond-second start can be achieved.
  • Portability: Docker container application and technology is the dependent libraries and runtime environments of image transformation packet into a container can run on different platforms.
  • Automation: container containers ecology choreography work (such as: Kubernetes) can help us to achieve automated management of the container.

二、Dockerfile

Dockerfile configuration is used to describe a text document file, which contains a combination of all user may invoke Image command, the user can also use continuous Docker build command execution means to automatically build a plurality of lines using this line.

By writing Dockerfile magnetism mirror, can develop, test team to provide a substantially uniform environment, so as to enhance the development, testing team efficiency, no longer need the environment is not uniform and worry, while operation and maintenance can more easily manage our mirrors.

Dockerfile syntax is very simple, commonly used only 11:

2.1 write gracefully Dockerfile

Write elegant Dockerfile main note the following:

  • Dockerfile file should not be too long, the greater the more the level of final production out of the image.
  • Do not include image building out unwanted content, such as logs, install temporary files.
  • Try to use run-time base image, the process does not need to be placed at the building's Dockerfile runtime.

Just remember the above three points will be able to write good Dockerfile.

In order to facilitate understanding, we conducted a simple comparison with two Dockerfile examples:

FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y apt-utils libjpeg-dev \     
python-pip
RUN pip install --upgrade pip
RUN easy_install -U setuptools
RUN apt-get clean
FROM ubuntu:16.04
RUN apt-get update && apt-get install -y apt-utils \
  libjpeg-dev python-pip \
           && pip install --upgrade pip \
      && easy_install -U setuptools \
    && apt-get clean

We look at the first Dockerfile, at first glance clear, reasonable structure, it seems pretty good. Look at the second Dockerfile, compact, easy to read, why you wrote?

  • The first advantage is that Dockerfile: When the process is executing a layer mistakes, correct them after Build again, as already completed execution layer will not be executed again. This can greatly reduce the Build next time, but its problem is due to become a multi-level space occupied by the mirror becomes large.
  • The second Dockerfile all the components are all on the first floor resolved to do so less space mirrors to a certain extent, but in the production of base image if one of these groups compiler error, as amended Build equivalent to start over again , in front of the compiled components in one layer, the have to recompile all over again, more time-consuming.

It can be seen out of two Dockerfile compiled image size from the following table:

$ docker images | grep ubuntu      
REPOSITORY      TAG     IMAGE ID    CREATED     SIZE                                                                                                                                   
ubuntu                   16.04       9361ce633ff1  1 days ago 422MB
ubuntu                   16.04-1   3f5b979df1a9  1 days ago  412MB

Uh ... as if no special effects, but if Dockerfile very long, then you can consider reducing the level, because there are only 127 Dockerfile highest level.

Third, the use of multi-stage build

Docker Docker will be able to upgrade to support multi-level building after 17.05, in order to make the image more compact, we use multi-step way to build packaged mirror. Before construction of multi-stage build appears to mirror we usually use a Dockerfile or more Dockerfile.

3.1 Construction of single-file

Using a single file to build before the multi-stage build out, single file is all the build process (including project dependencies, compile, test, package process) all contained under a Dockerfile in:

FROM golang:1.11.4-alpine3.8 AS build-env
ENV GO111MODULE=off
ENV GO15VENDOREXPERIMENT=1
ENV BUILDPATH=github.com/lattecake/hello
RUN mkdir -p /go/src/${BUILDPATH}
COPY ./ /go/src/${BUILDPATH}
RUN cd /go/src/${BUILDPATH} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install –v

CMD [/go/bin/hello]

This approach will bring some problems:

  • Dockerfile file will be particularly long, maintainability will decrease exponentially as more and more things need time;
  • Excessive levels of mirroring, mirrored volume will gradually increase, the deployment will become more and more slowly;
  • Code there is a leak risk.

To Golang example, it does not rely on any runtime environment, just to have a build environment, then this compilation environment in the actual run-time is not the role of the task, the compilation is complete, and that the source code compiler has no mandate use of it no need to stay in a mirror image.

On the table you can see, the final build single-file takes up 312MB of space.

More than 3.2 build file

Before the multi-stage build out there is no good solution? There are, for example, multi-file build or install the compiler on the build server, but this method is to install a compiler on the build server we have not recommended, because the installation on the build server compiler will lead to the build server to become very bloated, adapter required multiple versions of each language, dependence, error-prone, high maintenance costs. So we only covers how to build multi-file.

Construction of multi-file, in fact, the use of multiple Dockerfile, then the script by combining them. Suppose there are three documents are: Dockerfile.run, Dockerfile.build, build.sh.

  • Some Dockerfile components Dockerfile.run is necessary to run the program required, it contains the most streamlined library;
  • Dockerfile.build only used to build, to build complete useless;
  • build.sh function is to Dockerfile.run and Dockerfile.build be composed of the Dockerfile.build build good things out, and then perform Dockerfile.run, regarded as a dispatcher role.

Dockerfile.build

FROM golang:1.11.4-alpine3.8 AS build-env
ENV GO111MODULE=off
ENV GO15VENDOREXPERIMENT=1
ENV BUILDPATH=github.com/lattecake/hello
RUN mkdir -p /go/src/${BUILDPATH}
COPY ./ /go/src/${BUILDPATH}
RUN cd /go/src/${BUILDPATH} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install –v

Dockerfile.run

FROM alpine:latest
RUN apk –no-cache add ca-certificates
WORKDIR /root
ADD hello .
CMD ["./hello"]

Build.sh

#!/bin/sh
docker build -t –rm hello:build . -f Dockerfile.build
docker create –name extract hello:build
docker cp extract:/go/bin/hello ./hello
docker rm -f extract
docker build –no-cache -t –rm hello:run . -f Dockerfile.run
rm -rf ./hello

Construction of execution build.sh to complete the project.

You can see from the table, to build multi-file greatly reduces the footprint of the mirror, but it has three documents need to be managed, maintenance costs are also higher.

More than 3.3 build order

Finally, we look at the long-awaited multi-level building.

Complete the multi-stage build we only need to use the FORM statement several times in Dockerfile, each FROM instruction can use different base image, and each FROM command will build a new beginning, we can choose to copy the results of a phase of the building to another a stage, in the final image left will result in the last build, so you can easily solve the problems mentioned above, and only need to write a Dockerfile file. It is worth noting: the need to ensure version Docker in 17.05 and above. Below us, that specific operation.

Can be used as in Dockerfile where to stage an alias for a "build-env":

FROM golang:1.11.2-alpine3.8 AS build-env

And copying files from the stage mirror, the mirror can also copy the file to any of:

COPY –from=build-env /go/bin/hello /usr/bin/hello 

Look at a simple example:

FROM golang:1.11.4-alpine3.8 AS build-env
 
ENV GO111MODULE=off
ENV GO15VENDOREXPERIMENT=1
ENV GITPATH=github.com/lattecake/hello
RUN mkdir -p /go/src/${GITPATH}
COPY ./ /go/src/${GITPATH}
RUN cd /go/src/${GITPATH} && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install -v
 
FROM alpine:latest
ENV apk –no-cache add ca-certificates
COPY --from=build-env /go/bin/hello /root/hello
WORKDIR /root
CMD ["/root/hello"]

Docker build -t -rm hello3 execution after execution docker images, and then we look at the size of the mirror:

Multi-level building has brought us a lot of convenience, the biggest advantage is to ensure that in the case of run-time image small enough to also reduce the maintenance burden Dockerfile, so we strongly recommend the use of multi-stage build your code to be packaged into Docker image.

Author: Cong

Content Source: CreditEase Institute of Technology

Guess you like

Origin yq.aliyun.com/articles/709431