Dockerfile Command Remarks

COPY

format:

  • COPY <源路径>... <目标路径>
  • COPY ["<源路径1>",... "<目标路径>"]

And  RUN command, there are also two formats, similar to a command line, similar to a function call.

COPY Construction of instructions from the context directory  <源路径> copied file / directory into the new layer of the mirror  <目标路径> position. such as:

COPY package.json /usr/src/app/
 

<源路径> It may be a plurality, or even a wildcard, wildcard rules to meet its Go's  filepath.Match rules, such as:

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

<目标路径> Can be absolute in the vessel may be a path relative to the working directory (directory can work  WORKDIRinstruction specified). Destination path does not need to be created in advance, if the directory does not exist will first create the missing directory before copying files.

Also, note that the use of  COPY the instruction, the source file will remain various metadata. Such as read, write, and execute permissions, file change time. This feature is useful for custom image. Especially when the build-related files are managed using Git.

ADD

ADD And instructions  COPY consistent format and properties. However,  COPY on the basis of some added features.

For example,  <源路径> can be a  URL, in this case, Docker engine attempts to download files on this link  <目标路径> to go. After downloading the file permissions set automatically  600, if this is not desired permissions, you also need to add an extra layer of  RUN permissions to adjust. In addition, if you download the compressed package, you need to decompress, the same is also a need for additional layer  RUN instruction decompressed. It is better to use direct  RUN instruction, and then use  wget or  curl tool download, processing authority, decompress, and then clean the useless files more reasonable. Therefore, this feature is actually not practical, but not recommended.

If  <源路径> a  tar compressed file, compressed format  gzipbzip2 and  xz the case, the ADD command will automatically decompress the compressed file to  <目标路径> go.

In some cases, this self-extracting feature is very useful, such as the official image  ubuntu of:

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

However, in some cases, if we really want to copy a compressed file in, and understand compression, then not be able to use the  ADD commands.

In Docker official  Dockerfile 最佳实践文档 requirements, as much as possible to use  COPY, because  COPY the semantics is clear, is to copy files, but rather  ADD contains a more complex function, its behavior is not necessarily very clear. The most suitable  ADD occasion, is mentioned the need for automatic decompression occasions.

Also note that the ADD directive will make the mirrored cache invalidation building, which may lead to image building becomes slow.

So  COPY and  ADD when command is selected, you can follow this principle, all the files are copied using the  COPY instructions, only in the need for automatic decompression occasions  ADD.

#CMD

CMD Format and instructions  RUN similar, are two formats:

  • shell format:CMD <命令>
  • exec format:CMD ["可执行文件", "参数1", "参数2"...]
  • Parameter list CMD ["参数1", "参数2"...]format: . It is specified  ENTRYPOINT after the command with  CMD the specified specific parameters.

Before the introduction of the container, when once said, Docker is not a virtual machine, the container is the process. Since it is a process, so when you start a container, you need to specify the parameters of the program and running. CMD Command is used to specify the default startup command of the vessel master process.

You can specify a new command at run time to replace the default settings in the mirror command, for example, ubuntu mirroring the default  CMD Shi  /bin/bash, if we direct  docker run -it ubuntu it, will directly enter  bash. We can also specify other commands to run at runtime, such as  docker run -it ubuntu cat /etc/os-release. This is a  cat /etc/os-release command replaces the default  /bin/bash command, and the output of the system version information.

On the instruction format it is generally recommended to use  exec format, such format when parsing will be parsed as JSON array, so be sure to use double quotes  "instead of single quotes.

If you use the  shell format, the actual command would be packaged as  sh -c execution of formal parameters. such as:

CMD echo $HOME
 

In actual implementation, it will be changed to:

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

This is the reason why we can use environment variables, because these environment variables will be analyzed and processed shell.

Mentioned  CMD would have to mention container application in question foreground and background execution. This is a confusing beginners often arise.

Docker is not a virtual machine, application containers should be executed before the station, rather than virtual machines, physical machines inside as with upstart / systemd to start the background service, there is no concept of background services in the container.

Some beginners will be  CMD written as:

CMD service nginx start
 

And then found immediately after the execution out of the container. Even within the container to use  systemctl the command only to discover that simply can not be executed. This is because not thoroughly understand the foreground, the background of the concept, did not tell the difference containers and virtual machines, still in the angle of the traditional virtual machines to understand the container.

For containers, the launcher application process is the container, the container is to master process exists, the main process exits, the container would be meaningless existence, and thus exit, it is not something other auxiliary processes need to be concerned.

The use of  service nginx start command, it is hoped upstart to form after Taiwan daemon start  nginx service. And it just said  CMD service nginx start can be understood as  CMD [ "sh", "-c", "service nginx start"], therefore the main process actually  sh. Then when  service nginx start the end of the command sh will be over, sh as the main process exits, it will naturally make the container exit.

The correct approach is to directly execute  nginx the executable file, and requires previous stage in the form of running. such as:

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

#ENTRYPOINT

ENTRYPOINT Format and  RUN instruction format as divided  exec form and  shell format.

ENTRYPOINT The purpose and  CMD , are in the specified container and start the program parameters. ENTRYPOINT It may be replaced at run-time, but compared  CMD to slightly cumbersome, need to pass  docker run parameters  --entrypoint to be specified.

When specified  ENTRYPOINT , the CMD meaning of change occurs, it is no longer a direct operational command, but the  CMD contents as an argument to  ENTRYPOINT the instruction, in other words when the actual implementation, will become:

<ENTRYPOINT> "<CMD>"
 

With so  CMD later, why have  ENTRYPOINT it? This  <ENTRYPOINT> "<CMD>" what good it? Let's look at a few scenarios.

# Scene One: Let the mirror become like to use the same command

Suppose we learned that he needs a mirror image of the current public network IP, it can first  CMD be achieved:

FROM ubuntu:16.04
RUN apt-get update \
    && apt-get install -y curl \ && rm -rf /var/lib/apt/lists/* CMD [ "curl", "-s", "http://ip.cn" ] 
 

If we use  docker build -t myip . to build a mirror, and if we need to query the current public network IP, only need to do:

$ docker run myip
当前 IP:61.148.226.66 来自:北京市 联通
 

Ah, so it looks like a mirror can be directly used as a command, but there is always a command parameters, if we want to add parameters? From the above example  CMD you can see the essence of command  curl, so if we want to display the HTTP header information, you need to add  -iparameters. Then we can directly add  -i parameters to  docker run myip it?

$ docker run myip -i
docker: Error response from daemon: invalid header field value "oci runtime error: container_linux.go:247: starting container process caused \"exec: \\\"-i\\\": executable file not found in $PATH\"\n".
 

We can see that the executable file can not find the error, executable file not found. Before we said, behind the mirror name is  command, will replace the runtime  CMD defaults. So here's  -i to replace the original  CMD, rather than adding in the original  curl -s http://ip.cn behind. But  -i is not a command, so naturally can not be found.

So if we want to join  -i this argument, we must re-enter the complete command:

$ docker run myip curl -s http://ip.cn -i
 

This is obviously not a good solution, but using  ENTRYPOINT it can solve this problem. Now that we use  ENTRYPOINTto achieve this image:

FROM ubuntu:16.04
RUN apt-get update \
    && apt-get install -y curl \ && rm -rf /var/lib/apt/lists/* ENTRYPOINT [ "curl", "-s", "http://ip.cn" ] 
 

This time let's try to use directly  docker run myip -i:

$ docker run myip
当前 IP:61.148.226.66 来自:北京市 联通

$ docker run myip -i
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Tue, 22 Nov 2016 05:12:40 GMT
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding
X-Powered-By: PHP/5.6.24-1~dotdeb+7.1
X-Cache: MISS from cache-2
X-Cache-Lookup: MISS from cache-2:80
X-Cache: MISS from proxy-2_6
Transfer-Encoding: chunked
Via: 1.1 cache-2:80, 1.1 proxy-2_6:8006
Connection: keep-alive

当前 IP:61.148.226.66 来自:北京市 联通
 

You can see, this time succeeded. This is because when there is  ENTRYPOINT , the CMD content will be passed as a parameter  ENTRYPOINT, and here  -i is the new  CMD, and therefore passed as a parameter  curlto achieve our desired results.

# Preparatory work before the application is running: Scene Two

Start container is to start the main process, but sometimes, before starting the main process that requires some preparation.

For example,  mysql such as a database, the database may require some configuration, initialization of work, which should be resolved before the final mysql server is running.

In addition, you may want to avoid using  root the user to start the service, to improve security, but also need to start the service before to  root perform some necessary preparations identity, and finally switch to the service user who started the service. Or in addition to service, the other can still use the command  root executed as to facilitate debugging.

These preparations are container and  CMD has nothing to do, no matter  CMD how, we need to advance the work of a pretreatment. In this case, you can write a script, and then put  ENTRYPOINT in to perform, and this script will be received parameters (that is  <CMD>) as a command, the last execution in the script. For example, the official mirror  redis in is to do so:

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

Which can be seen in order to create a redis redis service user, and finally assigned  ENTRYPOINT to  docker-entrypoint.shthe script.

#!/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" "$@" fi exec "$@" 
 

The script is based on the contents of  CMD the content to determine if it is  redis-server , then switch to the  redis user who started the server, otherwise still use  root the identity of execution. such as:

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

#ENV

There are two formats:

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

This command is very simple, it is to set the environment variable, whether it is behind the other instructions, such as  RUN, or run-time application, you can directly use environment variables defined here.

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

This example demonstrates how to wrap, as well as the values ​​contain spaces enclosed in double quotes way, and this behavior is consistent with Shell.

Defined environment variable, then the subsequent instruction, you can use this environment variable. For example, in the official  node mirror  Dockerfile , there is code like this:

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 
 

Here we define the environment variable  NODE_VERSION, followed by  RUN this layer, use many times  $NODE_VERSION to operate customize. It can be seen in the future when the upgrade image builds, you only need to update  7.2.0 to, Dockerfile build a maintenance easier.

The following instructions can support environment variable ADDexpansion: COPY, ENV, EXPOSE, LABEL, USER, WORKDIR, VOLUME, STOPSIGNAL, ONBUILD, .

You can feel from the command list, environment variables can be used in many places, it is powerful. By environment variables, we can make a  Dockerfile production of more images, just use a different environment variable.

#VOLUME

The format is:

  • VOLUME ["<路径1>", "<路径2>"...]
  • VOLUME <路径>

We have said before, the container should be kept runtime container storage layer does not occur writes for database application classes need to preserve dynamic data, files should be stored in its database volume (volume), the later chapters we will introduce further roll Docker the concept of. In order to prevent run-time dynamic user forgets to save the file directory mounted as volumes,  Dockerfile we can pre-specify certain directories mounted as anonymous volume, so at run time if the user does not specify mount, its application can run normally , does not write data to a container for storing a large number of layers.

VOLUME /data
 

Here  /data directory will be automatically mounted at runtime anonymous volume, to any  /data information will not be written into the container for storing the recording layer, thus ensuring the free state of the container of the storage layer. Of course, you can override this mount runtime settings. such as:

docker run -d -v mydata:/data xxxx
 

In this command line, you use  mydata this name to the roll mount  /data this position, replacing  Dockerfile mount configuration defined volume of anonymity.

#EXPOSE

Format  EXPOSE <端口1> [<端口2>...].

EXPOSE Instruction is to provide services runtime container port statement, this is just a statement, and this statement will not use this service port will open at runtime. In Dockerfile written such a statement has two advantages, a mirror is to help users understand the guardian of this port mirroring services to facilitate configuration mapping; another is to use a random port mapping at run time, that is  docker run -P when, automatically random mapping  EXPOSE port.

In addition, there is a special use in earlier versions of Docker. All containers before running the default bridged network, so all containers have direct access to each other, so there are some security issues. So with a Docker engine parameter  --icc=false, when specified, the default will not be exchange of visits between the container, between each other unless the use of  --links the container argument can communicate, and only the mirror  EXPOSE port declared before they can be accessed. This  --icc=false usage, the introduction of the  docker network post has been basically no, you can easily achieve interconnection and isolation between the container via custom network.

To  EXPOSE and at run time using  -p <宿主端口>:<容器端口> separate. -p, It is a mapping of host ports and container ports, in other words, the container port of the corresponding public service access to the outside world, but  EXPOSE merely a statement of what you plan to use a container port only, and does not automatically port mapping in the host.

#WORKDIR

Format  WORKDIR <工作目录路径>.

Use  WORKDIR command can specify the working directory (or called the current directory), after the current directory of each layer was changed to the specified directory, if the directory does not exist, WORKDIR will help you to create the directory.

Prior to mention some common mistakes beginners is the  Dockerfile equivalent to the Shell scripts to write, this wrong understanding may also lead to the following error occurs:

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

If this  Dockerfile post-build Mirror operation, you will find not find the  /app/world.txt file, its contents or not  hello. The reason is simple, in the Shell, successive two lines is the same process execution environment, so the previous command to modify memory state, it will directly affect after a command; and in  Dockerfile the two rows  RUN execution environment fundamentally different command is two completely different containers. This is for  Dockerfile errors caused by lack of understanding the concept of tiered storage building.

Each said before  RUN is to start a container, execute commands, and then submit the file storage layer changes. The first layer is  RUN cd /appperformed just working directory of the current process of change, a change in a memory of it, the result will not cause any file changes. By the time the second layer, the start of a new container, the container with the first layer is more completely does not matter, naturally can not change memory before the process of building a layer of inheritance.

So if you need to change the position after the layers of the working directory, you should use the  WORKDIR command.

# Reference Document

Guess you like

Origin www.cnblogs.com/wzq-xf/p/11612883.html