Dockerfile is a text file that Docker uses to build images, including custom instructions and formats. An image can be built from a Dockerfile using the Docker build command. Users can use unified syntax commands to configure according to requirements. Through this unified configuration file, it can be distributed in different files, and automatic construction can be carried out according to the configuration file when needed, which solves the complex process of image construction for developers.

The use of Dockerfile

A Dockerfile describes the steps for assembling an object, where each instruction is run separately. With the exception of the FROM command, each command is executed based on the image generated by the previous command. After execution, a new image layer is generated, and the new image layer is overlaid on the original image to form a new image. The final image generated by Dockerfile is made up of layers of image layers on top of the base image.

Dockerfile instruction

The basic format of a Dockerfile is as follows:

# Comment

INSTRUCTION arguments

Copy the code

In dockerfiles, instructions are case insensitive, but uppercase is recommended to distinguish them from parameters. Docker executes instructions in Dockerfile sequentially, the first of which must be the FROM directive, which specifies the base image to build the image. Lines starting with # in a Dockerfile are comments, while # elsewhere is treated as arguments.

The commands in Dockerfile include FROM, MAINTAINER, RUN, CMD, EXPOSE, ENV, ADD, COPY, ENTRYPOING, VOLUME, USER, WORKDIR, and ONBUILD. Incorrect commands are ignored. Some of the important Docker directives are covered in detail below.

FROM

FROM or FROM :

The function of the FROM directive is to provide a base mirror for subsequent directives, so Dockerfile must have the FROM directive as the first non-comment directive. Pulling images from the public mirror library is easy, and the base image can select any valid image. The FROM directive can appear multiple times in a Dockerfile, which builds multiple images. The default value of tag is latest, and an error is returned if the parameter image or tag image does not exist.

ENV

ENV


or ENV

=





The ENV directive declares environment variables for containers created by the image. And in Dockerfile, the ENV directive declares environment variables that are interpreted and used by subsequent directives (ENV, ADD, COPY, WORKDIR, EXPOSE, VOLUME, USER).

Other directives that use environment variables use the format $variable_name or ${variable_name}. A variable can be escaped if it is preceded by a slash \. Such as \$foo or \${foo} will be converted to $foo and ${foo} instead of the value held by the environment variable. In addition, the ONBUILD directive does not support environment replacement.

COPY

Format: COPY < SRC >

The COPY command copies the file or directory pointed to and adds it to a new image. The path of the copied file or directory in the image is

. < SRC > can specify multiple sources, but they must be relative paths in the context root directory. Can’t just be like COPY.. /something /something. In addition,< SRC > can use wildcards to point to all files or directories that match wildcards. For example, COPY home* /mydir/ adds all files starting with “hom” to the directory /mydir/.


can be a file or directory, but it must be an absolute path in the target image or a relative path to WORKDIR (WORKDIR is the path specified by the WORKDIR directive in Dockerfile, used to set working directories for other directives). If

ends with a backslash /, it points to a directory. Otherwise point to the file. < SRC > in the same way. If

is a file, the contents of < SRC > will be written to

; Otherwise, the contents of the file or directory pointed to by < SRC > will be copied and added to the

directory. When < SRC > specifies multiple sources,

must be a directory. If

does not exist, a directory that does not exist in the path will be created.






ADD

Format: ADD < SRC >

The ADD command is similar to the COPY command in that it can COPY local files to an image, but the ADD command also supports other functions. < SRC > can be a URL pointing to a network file. In this case, if

points to a directory, the URL must be a full path. In this way, the network filename filename can be obtained, and the file will be copied to

/

. Like the ADD http://example.com/config.property can create a file/config/property.


< SRC > can also point to a local compressed archive that will be extracted when copied to the container, such as ADD sxample.tar.xz /. However, if the file in the URL is an archive file, it will not be extracted.

Although the ADD and COPY directives have similar functions, COPY is generally recommended because it supports only local files and is more transparent than ADD.

EXPOSE

EXPOSE [ / …]

The EXPOSE directive tells Docker that the container listens for a specified network port at run time. You can specify whether the port listens on TCP or UDP. If no protocol is specified, the default is TCP. This directive simply declares what port the container intends to use, and does not automatically map ports on the host. It can be specified at runtime via docker-p.

EXPOSE 80/tcp

EXPOSE 80/udp

Copy the code

USER

Format: USER < USER >[:

[:

]

]>

The USER directive sets the USER name and USER group(optional). The RUN,CMD, and ENTRYPOINT directives that follow it are executed with the set user.

WORKDIR

Format: WORKDIR /path/to/ WORKDIR

The WORKDIR directive sets up the working directory where the RUN, CMD, ENTRYPOINT, COPY, and ADD directives follow. If the working directory does not exist, one will be created automatically. The WORKDIR directive can be used multiple times in a Dockerfile. If a relative path is provided, it will be relative to the path of the previous WORKDIR directive. For example,

WORKDIR /a

WORKDIR b

WORKDIR c

RUN pwd

Copy the code

The output is /a/b/c

RUN

Format 2: RUN [“executable”, “param1”, “param2”] (exec format, recommended)

The RUN command creates a container based on the image created by the previous command, runs the command inside the container, and submits the container as a new image when the command is finished. The new image will be used by the next instruction in the Dockerfile.

The two formats of the RUN directive represent the two ways in which the command can be RUN in a container. When the shell format is used, the command is run through /bin/sh -c. When using the exec format, commands are run directly and the container does not call shell programs, that is, there are no shell programs in the container. Parameters in exec format are parsed by Docker as JSON arrays, so double quotes are required instead of single quotes. Because the exec format is not executed in the shell, the parameters of the environment variable are not replaced.

For example, when RUN [“echo”, “$HOME”] is executed, $HOME does not do variable substitution. If you want to RUN a shell program, you can write the command RUN [“/bin/bash”, “-c”, “echo”, “$HOME”].

CMD

CMD directives come in three formats.

CMD (shell format) CMD [“executable”, “param1”, “param2”] (exec format, recommended) CMD [“param1”, “param2”] (provides parameters for the ENTRYPOINT directive)

CMD directives provide the container’s runtime defaults, which can be directives or parameters. A Dockerfile can have multiple CMD directives, but only the last one is valid. The CMD [“param1”, “param2”] format is used when the CMD command is combined with the ENTRYPOINT command. The parameters in the CMD command are added to the ENTRYPOING command. Using the shell and exec formats, commands RUN in the container the same way as the RUN directive.

The difference is that the RUN command executes commands while building the image and generates a new image; The CMD command does not execute any commands when building the image, but defaults to the CMD command as the first command to execute when the container starts. If the user specified command parameters when running the Docker run command on the command line interface, the commands in the CMD command will be overwritten.

ENTRYPOINT

The ENTRYPOINT directive comes in two formats.

Format 2: ENTRYPOINT [” Executable “, “param1”, “param2”] (exec, recommended)

The ENTRYPOINT directive is similar to the CMD directive in that it allows the container to execute the same command each time it is started, but there are differences. A Dockerfile can have multiple ENTRYPOINT directives, but only the last ENTRYPOINT directive is valid.

When using Shell format, the ENTRYPOINT directive ignores any CMD and docker run arguments and runs in bin/sh -c. This means that the ENTRYPOINT instruction process is a child of bin/ sh-c, its PID in the container will not be 1, and it will not accept Unix signals. That is, when docker stop

is used, the command process cannot receive SIGTERM signals.

The exec format is recommended, in which the command arguments passed by the Docker run overwrite the contents of the CMD directive and append to the parameters of the ENTRYPOINT directive. CMD can be a parameter or an instruction, while ENTRYPOINT can only be a command. In addition, the run command parameters provided by the Docker run command can override CMD, but not ENTRYPOINT.

Dockerfile practice experience

Use a label

Label the image to help you understand the mirror function

Choose base images carefully

When selecting a base image, try to select the shoulder width of the current official image library. Different images have different sizes. The current Size of Linux images is as follows:

busybox < debian < centos < ubuntu

Also, when building your own Docker image, only install and update the required packages. It is also recommended to use the Debian image rather than the Ubuntu image because it is very lightweight (currently under 100MB in size) and is still a full release.

Make full use of caching

The Docker Daemon executes the instructions in the Dockerfile sequentially, and if the cache fails, subsequent commands cannot use the cache. To make effective use of the cache, you need to ensure continuity of instructions, trying to put all the same parts of the Dockerfile in front and different parts in the back.

Use ADD and COPY commands correctly

When different files are needed in different parts of a Dockerfile, don’t add them all to the image at once, but add them as needed, which also helps reuse the Docker cache. In addition, it is not recommended to use the ADD command to retrieve compressed packages from remote urls due to image size issues. Use RUN wget or RUN curl instead. This removes files that are no longer needed after decompression and does not require adding another layer to the image.

Wrong practice:

ADD http://example.com/big.tar.xz /usr/src/things/

RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things

RUN make -C /usr/src/things all

Copy the code

The right thing to do:

RUN mkdir -p /usr/src/things \

    && curl -SL http://example.com/big.tar.xz \

    | tar -xJC /usr/src/things \

    && make -C /usr/src/things all

Copy the code

The RUN command

You can use the backslash \ to separate multiple lines when using longer RUN directives. The most common use of the RUN command is to RUN the apt-wget command. Note the following points in this scenario.

  1. Do not use the RUN apt-get update directive in a single line. This will cause caching problems when the software source is updated, causing the RUN apt-get install command to fail. Therefore,RUN apt-get update and RUN apt-get install should be on the same line. RUN apt-get update && apt-get install -y package-1 package-2 package-3

  2. Avoid using the commands RUN apt-get upgrade and RUN apt-get dist-upgrade. Because in an unprivileged container, some necessary packages will fail to update. If you need to update a package (such as package-1), RUN apt-get install -y package-1.

CMD and ENTRYPOINT commands

The CMD and ENTRYPOINT commands specify the default commands for the container to run. It is recommended to use them together. Fixed default commands and parameters are set using the ENTRYPOINT directive in exec format, and mutable parameters are set using the CMD directive.

Take this example:

FROM busybox

WORKDIR /app

COPY run.sh /app

RUN chmod +x run.sh

ENTRYPOINT ["/app/run.sh"]

CMD ["param1"]

Copy the code

The run.sh content is as follows:

#! /bin/sh

echo "$@"

Copy the code

The command output is param1. The order of CMD and ENTRYPOINT in Dockerfile is not important.

You may encounter this problem when building Dockerfile on Windows

standard_init_linux.go:207: exec user process caused "no such file or directory"

Copy the code

Git bash is installed on your machine. Go to Git bash, edit it using vi, and modify it in command line mode (:set ff= Unix).

Do not do port mapping in Dockerfile

Using Dockerfile’s EXPOSE directive, while it’s possible to map container ports to host ports, it breaks Docker portability, and such an image can only launch one container on a host. So the port mapping should be specified in the docker run command with the -p argument.

# Do not do the following mapping in Dockerfile

EXPOSE 80:8080



Only port 80 is exposed

EXPOSE 80

Copy the code

Practice writing Dockerfile

Java service DockerFile

FROM openjdk:8-jre-alpine

ENV spring_profiles_active=dev

ENV env_java_debug_enabled=false

EXPOSE 8080

WORKDIR /app

ADD target/smcp-web.jar /app/target/smcp-web.jar

ADD run.sh /app

ENTRYPOINT ./run.sh

Copy the code

You can see that the base image is openJDK, and then set two environment variables, the service access port is 8080(meaning server.port=8080 is specified in the SpringBoot application), and the working directory is /app. Using ENTRYPOINT, the command (./run.sh) to start the image is set. The script reads as follows:

#! /bin/sh

# Set debug options if required

if [ x"${env_java_debug_enabled}"! = x ] && ["${env_java_debug_enabled}"! ="false" ]; then

    java_debug_args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"

fi



# ex: env_jvm_flags="-Xmx1200m -XX:MaxRAM=1500m" for production

java $java_debug_args $env_jvm_flags -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar target/smcp-web.jar

Copy the code

If we want to specify some parameters for the JVM, we can do so by setting env_jVM_flags in the environment variable.

Maven Dockerfile

Maven’s Dockerfile is also written very well, here I send up also for your reference

FROM openjdk:8-jdk



ARG MAVEN_VERSION=3.6.3

ARG USER_HOME_DIR="/root"

ARG SHA=c35a1803a6e70a126e80b2b3ae33eed961f83ed74d18fcd16909b2d44d7dada3203f1ffe726c17ef8dcca2dcaa9fca676987befeadc9b9f75996 7a8cb77181c0

ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries



RUN mkdir -p /usr/share/maven /usr/share/maven/ref \

  && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \

  && echo "${SHA}  /tmp/apache-maven.tar.gz" | sha512sum -c - \

  && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \

  && rm -f /tmp/apache-maven.tar.gz \

  && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn



ENV MAVEN_HOME /usr/share/maven

ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"



COPY mvn-entrypoint.sh /usr/local/bin/mvn-entrypoint.sh

COPY settings-docker.xml /usr/share/maven/ref/



ENTRYPOINT ["/usr/local/bin/mvn-entrypoint.sh"]

CMD ["mvn"]

Copy the code

You can see that it is created based on the base image of the OpenJDK. Download maven’s package first and then install it. The environment variables MAVEN_HOME and MAVEN_CONFIG were set, and the boot was started by mvn-entryPoint.sh.

Two-phase build of front-end services

I have a front-end service with the following directory structure:

$ ls frontend/

myaccount/ resources/  third_party/

Copy the code

Myaccount is for js, Vue, etc. Resources is for CSS,images, etc. Third_party hosts third-party apps.

A two-stage build is used here, that is, the build results of the previous stage are used as the build data of the next stage

FROM node:alpine as builder

WORKDIR '/build'

COPY myaccount ./myaccount

COPY resources ./resources

COPY third_party ./third_party



WORKDIR '/build/myaccount'



RUN npm install

RUN npm rebuild node-sass

RUN npm run build



RUN ls /build/myaccount/dist



FROM nginx

EXPOSE 80

COPY --from=builder /build/myaccount/dist /usr/share/nginx/html

Copy the code

Notice at the end –from=builder.

conclusion

I believe that after reading the dockerfile command, you should see any dockerfile should not be too big a problem, do not remember the command back to turn over the line. If you think it’s okay, check it out.