Dockerfile syntax and building a simple image

Dockerfile syntax and building a simple image


Previously used docker committo construct the mirrors

Docker does not recommend that users build images in this way . The reasons are as follows:

This is a way to create a mirror manually, which is error-prone, inefficient, and reproducible. For example, if you want to add vi to the debian base mirror, you have to repeat all the previous steps.
More importantly: the user does not know how the image was created and whether there are malicious programs in it. That is to say, the mirror cannot be audited, and there is a security risk.
Since docker commit is not the recommended method, why should we spend time learning?

The reason is: even if you use Dockerfile (recommended method) to build a mirror, the bottom layer will build a new mirror layer by layer. Learning docker commit can help us have a deeper understanding of the build process and the hierarchical structure of the image.

Ready to build the image


Need to create a Dockerfile file, the file name must be this

[root@localhost ~]# vim Dockerfile
# 添加
FROM centos
RUN yum -y install httpd
RUN yum -y install net-tools
RUN yum -y install elinks
CMD ["/bin/bash"]

Build image


Use docker build to build the image, and finally you need to specify the path where the Dockerfile file is located

[root@localhost ~]# docker build -t chai/centos-http-net /root
Successfully built 09266c896243
Successfully tagged chai/centos-http-net:latest

If you see two Successfully output at the end, the build is successful.

It will use the centos image to instantiate a container according to the content written in the file, enter the container and execute three yum commands

View the built image

[root@localhost ~]# docker images
REPOSITORY             TAG       IMAGE ID       CREATED          SIZE
chai/centos-http-net   latest    09266c896243   10 seconds ago   581MB

Instantiate the container with the new image

[root@localhost ~]# docker run -it --rm --name test chai/centos-http-net /bin/bash
[root@50da58a03736 /]# ifconfig  # 命令可以运行即成功

Image build process


In the large amount of information output when the build command is executed, each line in the Dockerfile is executed. The most critical lines of information are as follows

Step 1/5 : FROM centos  # 调用centos
 ---> 5e35e350aded   # centos镜像id

Step 2/5 : RUN yum install httpd -y
 ---> Running in a16ddf07c140  # 运行一个临时容器来执行install httpd
Removing intermediate container a16ddf07c140  # 完成后删除临时的容器id
 ---> b51207823459  # 生成一个镜像

Step 3/5 : RUN yum install net-tools -y
 ---> Running in 459c8823018a # 运行一个临时容器执行install net-tools
Removing intermediate container 459c8823018a # 完成后删除临时容器id
 ---> 5b6c30a532d4  # 再生成一个镜像

Step 4/5 : RUN yum install elinks -y
 ---> Running in a2cb490f9b2f  # 运行一个临时容器执行install elinks
Removing intermediate container a2cb490f9b2f # 完成后删除临时容器id
 ---> 24ba4735814b # 生成一个镜像

Step 5/5 : CMD ["/bin/bash"]
 ---> Running in 792333c88ba8  # 运行临时容器,执行/bin/bash
Removing intermediate container 792333c88ba8  # 完成后删除临时容器id
 ---> 09266c896243  # 生成镜像
Successfully built 09266c896243  # 最终成功后的镜像id就是最后生成的镜像id

Each step generates a mirror, which belongs to the execution result of a docker commit

In this process, a total of three image layers are generated, all of which are stored in the graph, including the relationship between layers. Check whether the image id generated in docker images is the last image id generated. FROM and CMD are not counted. Do mirror layer

[root@localhost ~]# docker images
REPOSITORY             TAG       IMAGE ID       CREATED          SIZE
chai/centos-http-net   latest    09266c896243   10 seconds ago   581MB

You can also see the simple build process through docker history. The size and capacity of these processes add up to the size of the final generated image. You can also compare the image id here with the id in the above process, what we see Three yum is the three mirror layers formed

[root@localhost ~]# docker history chai/centos-http-net:latest 
IMAGE         CREATED          CREATED BY                                      SIZE    COMMENT
09266c896243  17 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
24ba4735814b  17 minutes ago   /bin/sh -c yum install elinks -y                121MB               
5b6c30a532d4  18 minutes ago   /bin/sh -c yum install net-tools -y             112MB               
b51207823459  18 minutes ago   /bin/sh -c yum install httpd -y                 145MB               
5e35e350aded  4 months ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>     4 months ago     /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
<missing>     4 months ago     /bin/sh -c #(nop) ADD file:45a381049c52b5664…   203MB

Mirrored caching features


As mentioned in the previous document, the two mirrors of nginx and httpd are based on the mirrors made by the debian system, so they will use the same part of the mirror layer to install, and this mirror is shared by docker and only needs to be downloaded once.

Or re-download these two mirrors to see how to use them

Download nginx mirror

[root@localhost ~]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
68ced04f60ab: Pull complete 
28252775b295: Pull complete 
a616aa3b0bf2: Pull complete 

Download httpd mirror

[root@localhost ~]# docker pull httpd
Using default tag: latest
latest: Pulling from library/httpd
68ced04f60ab: Already exists  # 已经存在
35d35f1e0dc9: Pull complete 
8a918bf0ae55: Pull complete 
d7b9f2dbc195: Pull complete 
d56c468bde81: Pull complete 

Observe carefully in the downloaded content, there are two IDs that are the same 68ced04f60ab. When downloading httpd, it will report that it already exists because it has already been downloaded when downloading nginx. This is because these two programs are based on debian operations. The mirror made by the system, the mirror of this id is shared and used here, and the cache of the same mirror is used at the same time

The image built by ourselves also has the characteristics of this cache. A mirror chai/centos-http-net was built in the front, then we will make a little modification based on the Dockerfile file used to build this mirror.

Follow the hello-world minimal mirror method, which is to build a document mirror

[root@localhost ~]# vim testfile
# 添加内容
This is a FeiYi's file

Then COPY this file to the Dockerfile and modify it in the previous Dockerfile

[root@localhost ~]# vim Dockerfile
FROM centos
RUN yum -y install httpd
RUN yum -y install net-tools
RUN yum -y install elinks
COPY testfile /   # 将物理机当前目录的testfile文件复制到镜像中的根目录
CMD ["/bin/bash"]

The above Dockerfile is used to build a mirror, and it is found that the build is very fast, and there is not a lot of output information. Besides the newly added copy files, the other three RUN mirror layers have an extra line of Using cache. This is because of their formation. The image layer has been used as a cache for the image that was built

[root@localhost ~]# docker build -t test /root
Sending build context to Docker daemon  4.334MB
Step 1/6 : FROM centos
 ---> 5e35e350aded
Step 2/6 : RUN yum -y install httpd
 ---> Using cache
 ---> f01998ebc3ff
Step 3/6 : RUN yum -y install net-tools
 ---> Using cache
 ---> a3c39d101d8b
Step 4/6 : RUN yum -y install elinks
 ---> Using cache
 ---> 7c705388a610
Step 5/6 : COPY testfile /
 ---> 2111837dd86c
Step 6/6 : CMD ["/bin/bash"]
 ---> Running in 36782884ce16
Removing intermediate container 36782884ce16
 ---> 7b529720bf53
Successfully built 7b529720bf53
Successfully tagged test:latest

Another feature of the mirror layer


If you change the order of the mirror layers in the Dockerfile,

[root@localhost ~]# vim Dockerfile
FROM centos
RUN yum -y install httpd
COPY testfile /
RUN yum -y install net-tools
RUN yum -y install elinks
CMD ["/bin/bash"]

Then build, you will find that all the content has been rebuilt

[root@localhost ~]# docker build -t test2 /root

This feature is the relationship between layers. The order of their first construction can be understood as the hierarchical relationship between them. If the execution order is not the same, then the hierarchical relationship between them is also different, it will not Go build with cache. The relationship between them is stored in graphDB. If the same relationship cannot be read, the cache will not be used.

–No-cache

--No-cache can specify that when you build the image, the existing image layer is not used, that is, the feature of the cache is not used

Use this parameter to rebuild the Dockerfile just now

[root@localhost ~]# docker build -t test3 /root --no-cache

This will re-download and build all the mirror layers in the Dockerfile instead of using the cache.

Dockerfile file troubleshooting method


When an error is reported in the Dockerfile when building a mirror, let’s make an error Dockerfile first.

[root@localhost ~]# vim Dockerfile
FROM busybox
RUN touch tmpfile
RUN /bin/bash -c echo "continue to build..."
COPY testfile /

Use this Dockerfile to build the image

[root@localhost ~]# docker build -t testerror /root
Sending build context to Docker daemon  4.336MB
Step 1/4 : FROM busybox
 ---> 83aa35aa1c79
Step 2/4 : RUN touch tmpfile
 ---> Running in 41a8dad29cd6
Removing intermediate container 41a8dad29cd6
 ---> 8cd5c9a720bb
Step 3/4 : RUN /bin/bash -c echo "continue to build..."
 ---> Running in bc1849fa8144
/bin/sh: /bin/bash: not found
The command '/bin/sh -c /bin/bash -c echo "continue to build..."' returned a non-zero code: 127

Found that an error occurred during the mirroring process /bin/sh: /bin/bash: not found

You can see that the error message starts from the third step, indicating that the first two steps are no problems. You can check the error by entering the mirror id at the end of the first two steps. The mirror id entering the first two layers is a normal In the container environment, run the commands that cannot be executed in the third step in the container, and you will see that the real error is that there is no /bin/bash environment

[root@localhost ~]# docker run -it  8cd5c9a720bb
/ # /bin/bash -c echo "continue to build..."
sh: /bin/bash: not found

Because the image is built using busybox, the environment it uses is /bin/sh

After modification, rebuild is successful

[root@localhost ~]# docker build -t testerror /root
Successfully built ae5870fff063
Successfully tagged testerror:latest

After running the container, you can see the created tmpfile and copy testfile

[root@localhost ~]# docker run -it testerror 
/ # ls
bin       etc       proc      sys       tmp       usr
dev       home      root      testfile  tmpfile   var

Dockerfile file syntax


Commonly used build mirror instructions

FROM  # 指定base镜像
MAINTAINER # 指定镜像作者,后面根任意字符串
COPY # 把文件从host复制到镜像内
  COPY src dest
  COPY ["src","dest"]
  src:只能是文件
ADD # 用法和COPY一样,唯一不同时src可以是压缩包,表示解压缩到dest位置,src也可以是目录
ENV # 设置环境变量可以被接下来的镜像层引用,并且会加入到镜像中
  ENV MY_VERSION 1.3
  RUN yum -y install http-$MY_VERSION
  # 当进入该镜像的容器中echo $MY_VERSION会输出1.3
EXPOSE # 指定容器中的进程监听的端口(接口),会在docker ps -a中的ports中显示
  EXPOSE 80
VOLUME # 容器卷,后面会讲到,把host的路径mount到容器中
  VOLUME /root/htdocs /usr/local/apahce2/htdocs
WORKDIR # 为后续的镜像层设置工作路径
        # 如果不设置,Dockerfile文件中的每一条命令都会返回到初始状态
        # 设置一次后,会一直在该路经执行之后的分层,需要WORKDIR /回到根目录
CMD # 启动容器后默认运行的命令,使用构建完成的镜像实例化为容器时,进入后默认执行的命令
    # 这个命令会被docker run启动命令替代
    # 如:docker -it --rm centos echo "hello"
    # echo "hello"会替代CMD运行的命令
  CMD ["nginx", "-g", "daemon off"]  # 该镜像实例化后的容器,进入后运行nginx启动服务
ENTRYPOINT # 容器启动时运行的命令,不会被docker run的启动命令替代

RUN/CMD/ENTRYPOINT difference


In the syntax, it is said that CMD and ENTRYPOINT are commands that are run after the container is started and when the container is started, and RUN is the command that is run when the image is built. What is the difference between the three, let’s see through an example

Use these three to build a mirror

[root@localhost ~]# vim Dockerfile 
# 添加
FROM centos
RUN yum -y install net-tools
CMD echo "hello chai"
ENTRYPOINT echo "hello mupei"
[root@localhost ~]# docker build -t chai /root
Successfully built 10dec59bba24
Successfully tagged chai:latest

After the build is complete, run the image

[root@localhost ~]# docker run -it chai
hello mupei

Obviously RUN has completed its work in the build composition

RUN: execute commands and create a new mirror layer, mainly used to install software packages

After running the mirror, only hello mupei is output, which is the command executed by ENTRYPOINT

Both of these are counted as startup instructions, that is, instructions that must be started before the container can be executed. They are generally used to start running programs.

Conclusion: When ENTRYPOINT and CMD exist at the same time, ENTRYPOINT takes effect

ENTRYPOINT and CMD use format

Shell and exec two formats

shell format

CMD command、ENTRYPOINT command

The shell format will always call a shell program to execute the command

See through an example

[root@localhost ~]# vim Dockerfile 
FROM centos
RUN yum -y install net-tools
ENV name chai
ENTRYPOINT echo "hello $name"
[root@localhost ~]# docker build -t pei /root
Successfully built cf475e27d587
Successfully tagged pei:latest
[root@localhost ~]# docker run -it pei
hello chai

When the command is executed, the shell will call /bin/bash

exec format

CMD ["Command", "Option", "Parameter"], ENTRYPOINT ["Command", "Option", "Parameter"]

Variables defined by ENV cannot be called in the exec format. If the exec format must be used to read the variables, a shell environment must be used for the location of its commands. Because the variable reading is to use the shell to read.
Such as: ENTRYPOINT ["/bin/sh", "-c", "echo hello, $variable name"]

Look at another example

[root@localhost ~]# vim Dockerfile 
FROM centos
RUN ["yum", "-y", "install", "net-tools"]
CMD ["/bin/echo", "hello chai"]
ENTRYPOINT ["/bin/echo", "hello world"]
[root@localhost ~]# docker build -t feiyi /root
Successfully built 52189c01eaf5
Successfully tagged feiyi:latest

After running the container, only the ENTRYPOINT command is executed normally, and the hello world we need is output.

ENTRYPOINT ["/bin/echo", "hello world"]: In this line, /bin/echo is the command and hello world is the execution parameter

The /bin/echo and hello chai in CMD are both output as results, not as commands

[root@localhost ~]# docker run -it feiyi
hello world /bin/echo hello chai

Conclusion: When using the exec format, the first parameter of ENTRYPOINT is recognized as a command, and the parameters of CMD become the parameters of the ENTRYPOINT command in order.

This conclusion is equivalent to the following two lines in the Dockerfile = echo "hello world /bin/echo hello chai"

CMD ["/bin/echo", “hello chai”]

ENTRYPOINT ["/bin/echo", “hello world”]

which is:

[root@localhost ~]# docker run -it feiyi
hello world /bin/echo hello chai
[root@localhost ~]# echo "hello world /bin/echo hello chai"
hello world /bin/echo hello chai

Guess you like

Origin blog.csdn.net/weixin_46152207/article/details/113600786