Copy copy file

Format:

Copy < source path >... < target path >
Copy ["< source path 1 >",... "< target path >"]

< source path > can be multiple or even wildcard characters. Its wildcard rules should meet the filepath.match rules of go, such as:

COPY hom* /mydir/
COPY hom?.txt /mydir/

< target path > can be an absolute path within the container or a relative path relative to the working directory (the working directory can be specified by the workdir instruction). The target path does not need to be created in advance. If the directory does not exist, the missing directory will be created before copying the file.

In addition, it should be noted that with the copy instruction, all kinds of metadata of the source file will be preserved. For example, read, write, execute permissions, file change time, etc. This feature is useful for image customization. Especially when Git is used to manage the files related to building.

Add more advanced copy file

The format and nature of add and copy are basically the same. However, some functions have been added to copy.

For example, the source path can be a URL. In this case, the docker engine will try to download the linked file and put it in the target path. After downloading, the file permission is automatically set to 600. If this is not the permission you want, you need to add an additional layer of run to adjust the permission. In addition, if you download a compressed package, you need to decompress it. Also, you need an additional layer of run instruction to decompress it.

Note: if the source path is a tar compressed file and the compression format is gzip, bzip2 and XZ, the add instruction will automatically extract the compressed file to the target path.

FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
...

In the official dockerfile best practice document of docker, it is required to use copy as much as possible, because the semantics of copy is very clear, that is, copying files, while add contains more complex functions, and its behavior is not necessarily very clear. The most suitable situation to use add is the one mentioned that needs automatic decompression.

CMD container start command

The format of the CMD instruction is similar to that of run, and it also has two formats:

  • Shell format: CMD < command >
  • Exec format: CMD [“executable”, “Parameter1”, “parameter2″…]
  • Parameter list format: CMD [“parameter 1”, “parameter 2″…]. After specifying the entrypoint instruction, use CMD to specify specific parameters After that, when using docker run, you can dynamically add commands to the specified data

When introducing the container, I once said that the docker is not a virtual machine, but a container is a process. Since it is a process, you need to specify the program and parameters to run when starting the container. The CMD directive is used to specify the start command of the default container main process.

Note: in terms of instruction format, exec format is generally recommended. This type of format will be parsed into JSON array when parsing. Therefore, double quotation marks must be used instead of single quotation marks.

If the shell format is used, the actual command will be executed as a parameter of sh-c. For example:

CMD echo $HOME

In actual implementation, it will be changed to:

CMD [ "sh", "-c", "echo $HOME" ]

That’s why we can use environment variables because they are parsed by the shell.

Note: docker is not a virtual machine. All applications in the container should be executed in the previous platform, instead of using upstart / SYSTEMd to start background services, as in virtual machines and physical machines. There is no concept of background services in the container.

For example, use the CMD service nginx start container to exit immediately after execution

Using the service nginx start command, you want upstart to start the nginx service in the form of a later daemons. As mentioned just now, CMD service nginx start will be understood as CMD [“sh”, “- C”, “service nginx start”], so the main process is actually sh. Then when the service nginx start command is finished, SH will also be finished. If sh exits as the main process, the container will exit naturally.

The correct way is to execute the nginx executable directly, and require the former form to run. For example:

CMD ["nginx", "-g", "daemon off;"]

Note: if docker run specifies another command, the default command specified by CMD will be ignored. If there are multiple CMD instructions in the dockerfile, only the last CMD is valid.

Entrypoint entry point

This method is equivalent to the command that runs when the default container starts

The format of entrypoint is the same as that of run instruction, which is divided into exec format and shell format.

The purpose of entrypoint is the same as that of CMD. It starts programs and parameters in the specified container. Entrypoint can also be replaced at runtime, but it is a little more cumbersome than CMD. It needs to be specified by the parameter of docker run, entrypoint.

When entrypoint is specified, the meaning of CMD changes. Instead of directly running its command, the content of CMD is passed to the entrypoint instruction as a parameter. In other words, when it is actually executed, it will change to:

<ENTRYPOINT> "<CMD>"

Advanced applications are similar to the official redis image, with customized startup effect

FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 6379
CMD [ "redis-server" ]

You can see that the redis user is created for the redis service, and the entrypoint is specified as the docker-entrypoint.sh script at the end.

#!/bin/sh
...
# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
    chown -R redis .
    exec su-exec redis "$0" "[email protected]"
fi

exec "[email protected]"

The content of the script is judged according to the content of the CMD. If it is a redis server, switch to the redis user identity to start the server. Otherwise, it is still executed as root. For example:

$ docker run -it redis id
uid=0(root) gid=0(root) groups=0(root)

RUN vs CMD vs ENTRYPOINT

The three dockerfile instructions, run, CMD, and entrypoint, look similar and are easy to confuse. This section will discuss their differences in detail through practice.

Simply put:

  • Run executes commands and creates a new image layer, which is often used to install packages.
  • CMD sets the command and its parameters that are executed by default after the container is started, but the CMD can be replaced by the command line parameters that follow docker run.
  • Entrypoint configures the commands that are run when the container starts.

Best practices

  • Use the run instruction to install the application and software package and build the image.
  • If the purpose of docker image is to run an application or service, such as running mysql, the enter point instruction in exec format should be used first. CMD can provide additional default parameters for entrypoint and replace the default parameters with the docker run command line.
  • If you want to set the default startup command for the container, use the CMD directive. The user can replace this default command on the docker run command line.

Env setting environment variable

There are two formats:

- ENV <key> <value>
- ENV <key1>=<value1> <key2>=<value2>...

This instruction is very simple. It is just to set environment variables. No matter other instructions, such as run or run-time applications, you can directly use the environment variables defined here.

ENV VERSION=1.0 DEBUG=on \
    NAME="Happy Feet"

In addition, environment variables can also be used when writing docker files, and the technical term variables can be expanded

ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
  && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
  && grep " node-v$NODE_VERSION-linux-x64.tar.xz$" SHASUMS256.txt | sha256sum -c - \
  && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
  && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs

The following instructions can support environment variable expansion: add, copy, env, expose, label, user, workdir, volume, stopsignal, onbuild.

You can feel from this instruction list that environment variables can be used in many places, which is very powerful. Through the environment variables, we can make a dockerfile to make more images, just using different environment variables.

Arg setting environment variable

Build parameters have the same effect as Env, setting environment variables. But Arg can also use related variables in the compilation process

Volume define anonymous volume

The format is:

Volume ["< path1 >", "< path2 >"...]
Volume < Path >

As we said before, we should try our best to keep the storage layer of the container free from write operation when the container is running. For applications where the database class needs to save dynamic data, the database file should be saved in the volume. In the following chapters, we will further introduce the concept of docker volume.

As we said before, we should try our best to keep the storage layer of the container free from write operation when the container is running. For applications where database classes need to save dynamic data, their database files should be saved in volumes

Expose declaration port

The format is expose < port 1 > [< port 2 >…].

There are two advantages to writing such a declaration in the dockerfile:

  • Help image users understand the guard port of the image service to facilitate configuration mapping.
  • When using random port mapping at runtime, that is, when docker run – P, the port of expose will be mapped automatically.

In the earlier version of docker, there was a special use to solve the security problem caused by all containers running in the default bridging network and all containers can directly access each other.

So there is a docker engine parameter — ICC = false

–ICC = false parameter function: when this parameter is specified, containers cannot access each other by default. Only containers with the — links parameter can communicate with each other, and only the ports declared by expose in the image can be accessed. The usage of — ICC = false, which is basically not used after the introduction of docker network, can easily realize the interconnection and isolation between containers through custom network.

Note: to distinguish between expose and using – P < host port >: < container port > at run time. -P is to map the host port and container port. In other words, it is to expose the corresponding port service of the container to the outside world, while expose is only to declare what port the container intends to use, and it will not automatically map the port in the host.

Workdir specifies the working directory

The format is workdir < working directory path >.

This command is to solve the problems caused by the following shell commands

RUN cd /app
RUN echo "hello" > world.txt

Because every run command will produce an easy one, it will lead to different file directories. By using this fame and fortune, the related file directories can be unified

User specifies the current user

Both workdir and workdir are used to solve the problem that a command similar to docker run creates a new container, which results in a different environment, except that workdir is for the directory user and for the user

Health check

Format:

  • Healthcheck [options] CMD < command >: set command to check container health
  • Healthcheck none: if the basic image has a health check instruction, use this line to block its health check instruction

The healthcheck instruction is a new instruction introduced by docker 1.12, which tells docker how to determine whether the state of the container is normal.

Healthcheck supports the following options:

  • –Interval = < interval >: the interval between two health checks, which is 30 seconds by default;
  • –Timeout = < time length >: the timeout time of the health check command. If the timeout time is exceeded, the health check will be considered as a failure. The default time is 30 seconds;
  • –Retries = < times >: after the specified number of consecutive failures, the container state is considered unhealthy, and the default is 3 times.

Like CMD and entrypoint, healthcheck can only appear once. If there are multiple writes, only the last one will take effect.

The command after “healthcheck” CMD has the same format as “entrypoint”. It is divided into shell format and exec format. The return value of the command determines the success of this health check: 0: success; 1: failure; 2: reserved, do not use this value.

Suppose we have an image that is the simplest web service. We want to add health check to judge whether its Web service is working normally. We can use curl to help judge. The healthcheck of its dockerfile can be written as follows:

FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -fs http://localhost/ || exit 1

After running the image, you can see through docker container ls that the initial state is (health: starting):

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                            PORTS               NAMES
03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds (health: starting)   80/tcp, 443/tcp     web

After waiting for a few seconds, docker container LS again will see the health status changes to (Health):

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS               NAMES
03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   18 seconds ago      Up 16 seconds (healthy)   80/tcp, 443/tcp     web
If the health check fails more than the number of retries in a row, the status changes to (unhealthy).

Onbuild makes wedding clothes for others

Format: onbuild < other instructions >.

Onbuild is a special instruction. It is followed by other instructions, such as run, copy, etc., which will not be executed during the current image construction. Only when the current image is used as the base image to build the next level image will it be executed.

Other instructions in the dockerfile are prepared to customize the current image. Only onbuild is prepared to help others customize themselves.

FROM node:slim
RUN mkdir /app
WORKDIR /app
ONBUILD COPY ./package.json /app
ONBUILD RUN [ "npm", "install" ]
ONBUILD COPY . /app/
CMD [ "npm", "start" ]