导读
- 在这边文章中,主要对Dockerfile里面的各个主要关键字进行解释并且进行演示,给自己做备忘录的同时,也分享给各位大家。
关键字
-
FROM
- FROM关键字为Dockerfile开始的第一个指令,表明即将从后面的基础镜像开始进行构建。如果本地不存在该镜像,则会在docker.io镜像中进行pull。
- 在一个Dockerfile文件中,可以有多个FROM关键字,有这个关键字则表明,接下来会创建出一个镜像,多个FROM在同一个Dockerfile文件中,主要的应用场景为,在第一个FROM中,通常会构建一个开发镜像,包含了编译源代码所需要的环境和软件,通常会比较大、在第二个FROM中,将在第一个FROM构建出来的镜像中,将里面编译好的程序直接拷贝出来进行直接部署。
- 示例:
FROM centos:7 AS builder
LABEL maintainer="xiaojinran@foxmail.com"
RUN echo "Hello Docker!" > /tmp/result.log
FROM centos:7
COPY --from=builder /tmp/result.log /opt
-
ARG
- ARG类似在编程语言中的定义的变量,他可以在其他关键字中被引用进行解析,但是在CMD关键字中无法被解析,这点需要注意,因为CMD关键字属于运行时,ARG的生命周期只有在构建镜像时,并且可以在docker build 时,通过指定–build-arg <varname>=<value>来改变或者赋予值
- 示例:
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
ARG AUTHOR="XIAOJINRAN"
ARG VERSION=1.0
RUN echo "This is created by ${AUTHOR},current version is ${VERSION}"
输出结果
Step 1/5 : FROM centos:7
---> 5e35e350aded
Step 2/5 : LABEL maintainer="xiaojinran@foxmail.com"
---> Using cache
---> 8acea508f4f1
Step 3/5 : ARG AUTHOR="XIAOJINRAN"
---> Using cache
---> 100aecf8a646
Step 4/5 : ARG VERSION=1.0
---> Using cache
---> 23392ac7d722
Step 5/5 : RUN echo "This is created by ${AUTHOR},current version is ${VERSION}"
---> Running in 4ab41d6cd76a
This is created by XIAOJINRAN,current version is 1.0
Removing intermediate container 4ab41d6cd76a
---> 6d297ef2db60
Successfully built 6d297ef2db60
-
ENV
- ENV跟上述的ARG很像,都是dockerfile的变量,不一样的是,ENV的作用范围比ARG要大得多,ENV在构建时和容器运行都有效,因此在CMD关键字中,是可以打印出ENV所定义的值,并且ENV定义的值可以被docker run命令所赋值或覆盖,在ENV变量较多的情况下,也经常用文件的方式进行集体的变量定义,在上述的示例中,可以将ARG关键字换成ENV,并不会有影响,唯一的影响在于不能在docker build 时,通过指定–build-arg <varname>=<value>来改变或者赋予值
- 示例 :
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
ENV AUTHOR="XIAOJINRAN"
ENV VERSION=1.0
CMD echo "This is created by ${AUTHOR},current version is ${VERSION}"
输出结果
[docker@docker mytest]$ docker container run 04f9fb8782f8
This is created by XIAOJINRAN,current version is 1.0
- 通过运行加载变量文件的方式,我们可以把环境变量进行传递到容器里面去,变量文件如下:
cat my.env
AUTHOR="xiaojinran@foxmail.com"
VERSION=3.0
MSG="Hello Docker"
- 运行容器
$ docker container run --env-file=my.env 04f9fb8782f8 env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=f48ec377b710
AUTHOR="xiaojinran@foxmail.com"
VERSION=3.0
MSG="Hello Docker"
HOME=/root
-
CMD
- CMD为在容器运行时需要执行的一条指令,如果该指令执行完成,则该容器就会停止。在每个生成镜像的代码段里,如果存在多条CMD指令,那么只会执行最后一条,并且可以被docker run后面的指令所覆盖
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
CMD echo "First"
CMD echo "Second"
CMD echo "Third"
输出结果
$ docker container run 4f4910f2cba5
Third
覆盖Dockerfile中的CMD
$ docker container run 4f4910f2cba5 echo "cover"
cover
-
ENTRYPOINT
- ENTRYPOINT为容器运行的第一个入口,同CMD一样,在每个生成镜像的代码段里,如果存在多条ENTRYPOINT指令,那么只会执行最后一条,与CMD不同的是不能被docker run命令所覆盖,ENTRYPOINT不会被覆盖,而且是第一条被执行的指令。
- 示例:
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
ENTRYPOINT ["echo","Hello Docker"]
输出结果
$ docker container run 7f8c36642cb3 echo "Hello"
Hello Docker echo Hello
- 这里有一点需要注意,如果我把ENTRYPOINT写成命令行模式,不为数组形式,则CMD的所有指令将被忽略掉,包括docker run传递进去的指令,意味着CMD都不会起作用
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
ENTRYPOINT echo "Hello:"
输出结果
$ docker container run 2c9f788529a9 "Docker"
Hello:
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
EXPOSE 80
CMD sleep 30
容器运行时输出结果
$ docker container run -p 80 -d c22b7fb53471
7447580ff9dbf9a9189d575fdabdefe9a2fedbc98e913145e770d2114ff1339e
$ docker port 7447580ff9d
80/tcp -> 0.0.0.0:32771
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
VOLUME /data
CMD echo "Hello,Docker!" >> /data/test.log
运行两个容器时的结果
$ docker container run -v /tmp:/data 902da181c405
$ docker container run -v /tmp:/data 902da181c405
$ cat /tmp/test.log
Hello,Docker!
Hello,Docker!
可以看到,这个容器共享了同一个卷的同一个文件,这个在需要读取配置和写入持久化数据的场景下非常有用
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
WORKDIR /opt/my/path/can/be/anywhare
CMD pwd
容器运行结果
$ docker container run ff9149266b20
/opt/my/path/can/be/anywhare
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
COPY * /opt/hosted_files/
CMD ls -l /opt/hosted_files
容器运行结果
$ docker container run d26523f325f9
total 8
-rw-rw-r-- 1 root root 110 Jan 10 07:56 Dockerfile
-rw-rw-r-- 1 root root 63 Jan 10 06:37 my.env
drwxrwxr-x 2 root root 22 Jan 10 07:58 test
宿主机目录情况
$ ls -lrt
total 8
-rw-rw-r-- 1 docker docker 63 Jan 10 01:37 my.env
-rw-rw-r-- 1 docker docker 110 Jan 10 02:56 Dockerfile
drwxrwxr-x 3 docker docker 18 Jan 10 02:59 myfiles
可以看到,在容器里面,myfiles文件夹没有了,直接显示myfiles下面包含的内容信息,并且权限也发生了变化
FROM centos:7
LABEL maintainer="xiaojinran@foxmail.com"
ADD * /opt/hosted_files/
CMD ls -l /opt/hosted_files
容器运行结果
$ docker container run 8a9cadc209e0
total 8
-rw-rw-r-- 1 root root 109 Jan 10 08:06 Dockerfile
-rw-rw-r-- 1 1000 994 63 Jan 10 06:37 my.env
drwxrwxr-x 3 1000 994 18 Jan 10 07:59 myfiles
Dockerfile所在目录内容
$ ll
total 8
-rw-rw-r-- 1 docker docker 109 Jan 10 03:06 Dockerfile
-rw-rw-r-- 1 docker docker 280 Jan 10 03:07 my.tar.gz
可见,ADD指令并没有拷贝my.tar.gz这个文件,而是直接解压了放到了目标文件夹之中