dockerfile详解

dockerfile详解


docker的镜像分层

  • 分层

    • Cow
    • 联合挂载
    • base image ,app image = base image
  • docker里的镜像绝大部分都是在别的镜像的基础上去进行创建的,也就是使用镜像的分层结构。

  • 那么为什么会有两个镜像呢?这是由于docker的镜像分层结构所导致的,如下图所示。

  • 一个docker镜像由多个可读的镜像层组成,然后运行的容器会在这个docker的镜像上面多加一层可写的容器层,任何的对文件的更改都只存在此容器层。因此任何对容器的操作均不会影响到镜像。

  • 至于容器如何获取镜像层文件而又不影响到是镜像层的呢?docker是这样实现的?

  • 如果需要获取某个文件,那么容器曾会从上到下去下一层的镜像层去获取文件,如果该层文件不存在,那么就会去下一镜像层去寻找,直到最后一层。
  • 对于用户而言,用户面向的是一个叠加后的文件系统。
  • 而任何对于文件的操作都会记录在容器层,例如说修改文件,容器层会把在镜像层找到的文件拷贝到容器层然后进行修改,删除文件则会在容器层内记录删除文件的记录。

About Dockerfile

  • Dockerfile只不过是建造码头工人的源代码自动图像码头工人可以构建图像读取指令从Dockerfile。
    • Dockerfile是一个文本文件,包含所有的命令在命令行用户可以叫组装一个图像型码头工人建立用户可以创建一个自动构建执行一些命令行指令

Dockerfile

  • Dockerfile其实可以看做一个命令集。每行均为一条命令。每行的第一个单词,就是命令command。
  • 后面的字符串是该命令所要接收的参数。
  • 比如ENTRYPOINT /bin/bash。ENTRYPOINT命令的作用就是将后面的参数设置为镜像的entrypoint。
  • 至于现有命令的含义,这里不再详述。
  • DockOne上有很多的介绍。

一、Docker Image building

  • 宿主机指定工作目录:

    • 1.此文件中仅用于放置Dockerfile以及Dockerfile文件中指定要被依赖到的文件,不要放置其他文件或目录。
    • 2.此宿主机的工作目录相当于隐式运行的容器的卷,仅能从此卷中复制文件到容器中。
  • Dockerfile的文件名也只能叫做Dockerfile,放置在宿主机上的工作目录中。

二、Dockerfile文件格式

  • 格式(Format)
    • #注释
    • 指令参数
  • 该指令本身不区分字符大小
    • 惯例要求的指令要写成纯大写
    • 以便更容易地与参数区分开来
  • dockerfile文件本身没有循环、选择等分支,也没有跳转语句
    • 一般来讲在dockerfile文件中的第一条指令是“FROM”(新版的dockerfile有松动,早期的dockerfile把第一条执行的第一条指令必须是“FROM”),因为“FROM”就是我们用来指定基础镜像的。

三、Dockerfile的镜像层构建

  • 在dockerfile中构建镜像,与我们手动的显式的启动一个容器构建镜像不同的是dockerfile文件中的每一条指令都会生成一个新的单有的镜像层。
    • 分层过多会导致在读写访问过程中的效率降低,因为首次访问镜像一定是Cow机制完成
    • 镜像分的过于精细的好处是可以其他让镜像让享同一层底层的镜像即镜像层越精细越多越容易共享,越容易共享代表在镜像仓库与客户端和dockerhost之间传输时可以单独传输,传输的过程越易控,起码在打包、分发。
    • 应该把关系比较紧密的操作放置在一层操作当中。

docker镜像制作的两种运行场景

  • 制作新镜像的过程
  • 运行新镜像的阶段

dockerfile

环境变量

  • 环境变量(用ENV语句声明)也可以在某些指令中使用,因为Dockerfile将解释的变量在Dockerfile中以$variable名或${variable_name标记
    • ${variable_name} 语法还支持一些标准的bash修饰符
      • $ivariable:-word} 表示如果设置了变量,则结果将是该值。 如果变量没有设置,那么结果将是word
      • ${variable:+word} 表示如果设置了变量,则word为结果,否则结果为空字符串

.dockerignore file

在docker CLI将上下文发送给docker守护进程之前,它将查找一个名为。如果该文件存在,CLI将修改该上下文以排除与其模式匹配的文件和目录。dockerignore file是一个以新行分隔的模式列表,类似于Unix shell的文件全局

Dockerfile指令

build阶段Dockerfile文件中的指令

(build阶段:做很多设定以便于在目标镜像文件中可以打包进入所期望的文件或者程序文件)

  • FROM

    • FROM指令是最重的一个且必须为Dockerfile文件开篇的第一个非注释行,用于 为映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运 行环境
    • 实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会在 docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry 上拉取所需的镜像文件
      • 如果找不到指定的镜像文件,docker build会返回一个错误信息
    • Syntax(语法)(repository仓库、tag标签、digest唯一标识id即镜像校验码)
      • FROM <repository>[:<tag>] 或
      • FROM <resository>@<digest>
        • <reposotiry>:指定作为base image的名称;
        • <tag>:base image的标签,为可选项,省略时默认为latest;
  • LABEL

    • 用于让Dockerfile制作者提供本人的详细信息(支持提供此镜像的任何制作的附加介绍信息以及附加的元数据)
    • Syntax: LABEL <key>=<value> <key>=<value> <key>=<value> ...
  • COPY

    • 用于从Docker主机复制文件至创建的新映像文件
    • Syntax(语法)
      • COPY <src> ... <dest> 或
      • COPY ["<src>",... "<dest>"]
        • <src>:要复制的源文件或目录,支持使用通配符
        • <dest>:目标路径,即正在创建的image的文件系统路径;建议为<dest>使用绝对路径,否则, COPY指定则以WORKDIR为其起始路径;
      • 注意:在路径中有空白字符时,通常使用第二种格式
    • 文件复制准则
      • <src>必须是build上下文中的路径,不能是其父目录中的文件
      • 如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制
      • 如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以/ 结尾
      • 如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径
  • ADD

    • ADD指令类似于COPY指令,ADD支持使用TAR文件和URL路径
    • Syntax
      • ADD <src> ... <dest> 或
      • ADD ["<src>",... "<dest>"]
    • 操作准则
      • 同COPY指令
      • 如果<src>为URL且<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest> ;如果<dest>以/结尾,则文件名URL指定的文件将被直接下载并保存为<dest>/<filename>
      • 如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于 “tar -x”命令;然而,通过URL获取到的tar文件将不会自动展开
      • 如果<src>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径 ;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>;
  • WORKDIR

    • 用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD指定 设定工作目录
    • Syntax
      • WORKDIR <dirpath>
      • 在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过,其是相对此前 一个WORKDIR指令指定的路径
      • 另外,WORKDIR也可调用由ENV指定定义的变量
    • 例如
      • WORKDIR /var/log
      • WORKDIR $STATEPATH
  • VOLUME 存储卷

    • 用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的 卷
    • Syntax
      • VOLUME <mountpoint> 或
      • VOLUME ["<mountpoint>"]
    • 如果挂载点目录路径下此前在文件存在,docker run命令会在卷挂载完成后将此 前的所有文件复制到新挂载的卷中
  • EXPOSE

    • 用于为容器打开指定要监听的端口以实现与外部通信
    • Syntax
      • EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...]
        • <protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议,空格分隔可以创建多个
    • EXPOSE指令可一次指定多个端口,
      • 例如
      • EXPOSE 11211/udp 11211/tcp
  • ENV

    • 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令 (如ENV、ADD、COPY等)所调用
      • 调用格式为$variable_name或${variable_name}
      • Syntax
        • ENV <key> <value> 或
        • ENV <key>=<value> ...
        • 第一种格式中,<key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只 能设置一个变量;
        • 第二种格式可用一次设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果 <value>中包含空格,可以以反斜线(\)进行转义,也可通过对<value>加引号进行标识;另 外,反斜线也可用于续行;
        • 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能
  • ARG

    • ARG指令定义了一个变量,用户可以在构建时将该变量传递给然后使用 `–bulis-arg= flag
    • 如果用户指定了一个没有在dockerfile中定义的构建参数,构建输出一个警告.`

    • syntax

      • ARG<name>[<default value>]

1.使用FROM、LABEL、COPY制作镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#############################################################
##########################创建docker的工作目录#################
##############################################################
[root@centos7 ~]# mkdir /docker/
[root@centos7 ~]# cd /docker/

##############################################################
#########################编写dockerfile#######################
##############################################################
[root@centos7 docker]# vim Dockerfile

FROM busybox:latest #对宿主机上已有的哪个镜像进行创建

LABEL maintainer="daizhe<daizhe@9527dz.top>" #作者描述

COPY index.html /data/web/html/ #将宿主机上docker目录下的index.html文件复制到容器中的/data/web/html/目录。如果写为/data/web/html则代表将 index.html改名为html,在容器中的/data/web/html/获取并未存在,可以自动创建。

###############################################################
##################查看宿主机上的dockerfile的工作目录#############
###############################################################

[root@centos7 ~]# cd /docker/
[root@centos7 docker]# echo "123456" > index.html
[root@centos7 docker]# ls
index.html

################################################################
#########################构建新的镜像############################
################################################################
dicker image build = docker build
[root@centos7 docker]# docker image build -h
Usage: docker image build [OPTIONS] PATH | URL | -
Options:
--add-host list 添加自定义主机到ip映射(主机:ip)
--build-arg list 设置构建时变量
--cache-from strings 将图像视为缓存源
--rm 成功构建后删除中间容器(默认为true)
-t, --tag list 制定的新的镜像设置新的仓库名和标签'name:tag'

[root@centos7 docker]# docker image build /docker/ -t mybox:v0.1 #执行命令的目录,要求写dockerfile文件所在的目录中
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM busybox:latest
---> 3a093384ac30
Step 2/3 : LABEL maintainer="daizhe<daizhe@9527dz.top>"
---> Running in 746880c7205c
Removing intermediate container 746880c7205c
---> 7ccdca9907ce
Step 3/3 : COPY index.html /data/web/html/
---> 7062cd4f08e0
Successfully built 7062cd4f08e0
Successfully tagged mybox:v0.1

[root@centos7 docker]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
mybox v0.1 7062cd4f08e0

################################################################
############基于创建的镜像启动容器查看COPY的文件是否存在############
################################################################
[root@centos7 docker]# docker run --name pc1 -it --rm mybox:v0.1 /bin/sh
/ # cat /data/web/html/index.html
123456

2.COPY本身也是可以是可以支持通配符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
##############################################################
####################使用.dockerignore限制copy的文件#############
###############################################################
[root@centos7 docker]# pwd
/docker
[root@centos7 docker]# mkdir /docker/data/
[root@centos7 docker]# cd !$
cd /docker/data/
[root@centos7 data]# echo "123" > test1.html
[root@centos7 data]# echo "123" > test2.html
[root@centos7 data]# echo "123" > test3.html
[root@centos7 docker]# tree
.
├── data
│   ├── test1.html
│   ├── test2.html
│   └── test3.html
└── Dockerfile

#################################################################
##打算将/docker/data/目录下的文件全部复制到容器中排除test3.html文件##
#################################################################
[root@centos7 docker]# vim .dockerignore #定义的.dockerignore 文件要写Dockerfile的相对路径,文件内也支持通配符
data/test3.html

#################################################################
######################编辑Dockerfile文件##########################
#################################################################
[root@centos7 docker]# vim /docker/Dockerfile
FROM busybox:latest
LABEL maintainer="daizhe<daizhe@9527dz.top>"
COPY data /data/web/html/ #如果源是目录会cp源目录下的文件不会cp目录本身

################################################################
##########################创建新的镜像###########################
################################################################
[root@centos7 docker]# docker image build /docker/ -t mybox:v0.4
Sending build context to Docker daemon 5.632kB
Step 1/3 : FROM busybox:latest
---> 3a093384ac30
Step 2/3 : LABEL maintainer="daizhe<daizhe@9527dz.top>"
---> Using cache
---> 7ccdca9907ce
Step 3/3 : COPY data /data/web/html/
---> Using cache
---> 5b5cd427fb81
Successfully built 5b5cd427fb81
Successfully tagged mybox:v0.4

###############################################################
##############################创建容器查看######################
###############################################################
[root@centos7 docker]# docker run --name pc1 -it --rm mybox:v0.4 /bin/sh
/ # ls /data/web/html/*
/data/web/html/test1.html /data/web/html/test2.html

3.Dockerflie文件中ADD指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[root@centos7 docker]# pwd
/docker
[root@centos7 docker]# ls
Dockerfile wordpress-4.9-zh_CN.tar.gz

[root@centos7 docker]# vim Dockerfile
FROM busybox:latest
LABEL maintainer="daizhe<daizhe@9527dz.top>"
ADD http://nginx.org/download/nginx-1.14.2.tar.gz /data/ #将网上的url打入镜像中,并运行容器是自动下载此压缩包放置在容器中的/data目录中
ADD wordpress-4.9-zh_CN.tar.gz /data2/ #此压缩包是放置在docker的工作目录中,会在容器运行时解压到容器中/data2目录中。

[root@centos7 docker]# docker image build /docker/ -t mybox:v0.3
Sending build context to Docker daemon 10.13MB
Step 1/4 : FROM busybox:latest
---> 3a093384ac30
Step 2/4 : LABEL maintainer="daizhe<daizhe@9527dz.top>"
---> Using cache
---> 7ccdca9907ce
Step 3/4 : ADD http://nginx.org/download/nginx-1.14.2.tar.gz /data/
Downloading 1.015MB/1.015MB
---> 62b1d80179e4
Step 4/4 : ADD wordpress-4.9-zh_CN.tar.gz /data2/
---> 6bfaa9b46d21
Successfully built 6bfaa9b46d21
Successfully tagged mybox:v0.3

[root@centos7 docker]# docker run --name pc1 -it --rm mybox:v0.3 /bin/sh
/ # ls /data
data/ data2/
/ # ls /data
nginx-1.14.2.tar.gz
/ # ls /data2
wordpress

4.Dockerfile文件中WORKDIR指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
################################################################
###########################定义工作目录##########################
################################################################
[root@centos7 docker]# vim Dockerfile
FROM busybox:latest
LABEL maintainer="daizhe<daizhe@9527dz.top>"
WORKDIR / #定义工作目录,表示/data/
ADD http://nginx.org/download/nginx-1.14.2.tar.gz data/
WORKDIR /data/ #定义工作目录,表示/data/haha/
ADD wordpress-4.9-zh_CN.tar.gz haha/

################################################################
###########################制作镜像并运行查看######################
################################################################
[root@centos7 docker]# docker image build /docker/ -t mybox:v0.4
Sending build context to Docker daemon 10.13MB
Step 1/6 : FROM busybox:latest
---> 3a093384ac30
Step 2/6 : LABEL maintainer="daizhe<daizhe@9527dz.top>"
---> Using cache
---> 7ccdca9907ce
Step 3/6 : WORKDIR /
---> Running in a9ef74256526
Removing intermediate container a9ef74256526
---> 89e2798cf96c
Step 4/6 : ADD http://nginx.org/download/nginx-1.14.2.tar.gz data/
Downloading 1.015MB/1.015MB
---> 653df7aeb99b
Step 5/6 : WORKDIR /data/
---> Running in 55e4223e543c
Removing intermediate container 55e4223e543c
---> 471c356643dc
Step 6/6 : ADD wordpress-4.9-zh_CN.tar.gz haha/
---> c1d30647ca27
Successfully built c1d30647ca27
Successfully tagged mybox:v0.4

[root@centos7 docker]# docker run --name pc1 -it --rm mybox:v0.4 /bin/sh
/data # ls /data/
haha nginx-1.14.2.tar.gz
/data # ls /data/haha/
wordpress

5.Dockerfile文件中VOLUME指定存储卷指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
docker管理的卷(要是想要指定绑定在宿主机的某个目录进行映射关联关系的存储卷继续使用-v选项指定)
######################################################################
##############################docker管理的卷#############################
######################################################################
[root@centos7 docker]# vim Dockerfile
FROM busybox:latest
LABEL maintainer="daizhe<daizhe@9527dz.top>"
WORKDIR /
ADD http://nginx.org/download/nginx-1.14.2.tar.gz data/
WORKDIR /data/
ADD wordpress-4.9-zh_CN.tar.gz haha/
VOLUME /data/web/html #指定容器中的此目录与宿主机上的某一个目录做存储卷映射关系

######################################################################
###############################打镜像--运行容器########################
######################################################################
[root@centos7 docker]# docker image build /docker/ -t mybox:v0.5
Sending build context to Docker daemon 10.15MB
Step 1/7 : FROM busybox:latest
---> 3a093384ac30
Step 2/7 : LABEL maintainer="daizhe<daizhe@9527dz.top>"
---> Using cache
---> 7ccdca9907ce
Step 3/7 : WORKDIR /
---> Using cache
---> 89e2798cf96c
Step 4/7 : ADD http://nginx.org/download/nginx-1.14.2.tar.gz data/
Downloading 1.015MB/1.015MB
---> Using cache
---> 653df7aeb99b
Step 5/7 : WORKDIR /data/
---> Using cache
---> 471c356643dc
Step 6/7 : ADD wordpress-4.9-zh_CN.tar.gz haha/
---> Using cache
---> c1d30647ca27
Step 7/7 : VOLUME /data/web/html
---> Running in 388c0312f897
Removing intermediate container 388c0312f897
---> 54cf9694d119
Successfully built 54cf9694d119
Successfully tagged mybox:v0.5
[root@centos7 docker]# docker run --name pc1 -it --rm mybox:v0.5 /bin/sh
/data # ls /data/web/html/
/data #

#######################################################################
##########################宿主机上查看对应的随机的存储卷##################
#######################################################################
[root@centos7 ~]# docker image inspect mybox:v0.5
"Volumes": {
"/data/web/html/": {}
},
[root@centos7 ~]# docker container inspect pc1
"Mounts": [
{
"Type": "volume",
"Name": "177fd037174ad4af75866df8d07c575f1e4dbee2ee65613c6e36842b4e6de49e",
"Source": "/var/lib/docker/volumes/177fd037174ad4af75866df8d07c575f1e4dbee2ee65613c6e36842b4e6de49e/_data",
"Destination": "/data/web/html",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}

6.Dockerfile中EXPOSE指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#######################################################################
#########################编写Dockerfile端口暴露tcp80####################
#######################################################################
[root@centos7 docker]# vim Dockerfile
FROM busybox:latest
LABEL maintainer="daizhe<daizhe@9527dz.top>"
WORKDIR /
ADD http://nginx.org/download/nginx-1.14.2.tar.gz data/
WORKDIR /data/
ADD wordpress-4.9-zh_CN.tar.gz haha/
VOLUME /data/web/html
EXPOSE 80/tcp

#######################################################################
#########################创建镜像并运行查看端口是否暴露###################
#######################################################################
[root@centos7 docker]# docker image build /docker/ -t mybox:v0.6
[root@centos7 docker]# docker run --name pc1 -it --rm mybox:v0.6 /bin/sh
[root@centos7 ~]# docker container inspect pc1
"Config": {
"Hostname": "b8bb78bbe2fb",
"Domainname": "",
"User": "",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"ExposedPorts": {
"80/tcp": {}
},
[root@centos7 _data]# docker container port pc1
#默认没有端口暴露,虽然在Dockerfile文件中已经定义,由于网络风险需要在启动容器是指定端口暴露
这种暴露和存储卷相同,都是宿主机随机动态
########################################################################
#####################此时可以手动指定开始端口暴漏##########################
########################################################################
[root@centos7 docker]# docker run --name pc1 -it -P --rm mybox:v0.6 /bin/sh
[root@centos7 ~]# docker container port pc1
80/tcp -> 0.0.0.0:32768

7.Dockerfile文件中ENV指令

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@centos7 docker]# vim Dockerfile 
FROM busybox:latest
ENV webhome="/data/web/html/"
LABEL maintainer="daizhe<daizhe@9527dz.top>"
WORKDIR ${webhome}
ADD http://nginx.org/download/nginx-1.14.2.tar.gz ${webhome}
WORKDIR ${webhome}
ADD wordpress-4.9-zh_CN.tar.gz ./
VOLUME ${webhome}
EXPOSE 80/tcp

[root@centos7 docker]# docker image build /docker/ -t mybox:v0.7
[root@centos7 docker]# docker run --name pc2 -it --rm mybox:v0.7 /bin/sh

8.Dockerfile文件中ARG指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
build的时对变量传值的做法
#Dockerfile中定义了创建容器时的变量参数。如果想临时修改参数可以在命令行中使用ARG定义变量,--build-arg,在执行docker image buil 命令命令行选项可以改变变量的值(docker新版本中支持)
##########################################################################
##############################使用ARG定义变量##############################
##########################################################################
[root@centos7 ~]# cd /docker/
[root@centos7 docker]# vim Dockerfile
FROM busybox:latest
ARG webhome="/data/web/html/"
LABEL maintainer="daizhe<daizhe@9527dz.top>"
WORKDIR ${webhome}
ADD http://nginx.org/download/nginx-1.14.2.tar.gz ${webhome}
WORKDIR ${webhome}
ADD wordpress-4.9-zh_CN.tar.gz ./
VOLUME ${webhome}
EXPOSE 80/tcp

#########################################################################
#############打镜像,并使用--build-arg指定新的便令再次打镜像################
#########################################################################
[root@centos7 docker]# docker image build /docker/ -t mybox:v0.8
#这个镜像执行与EVN执行的镜像一样
#使用--build-arg指定新的变量的值
[root@centos7 docker]# docker image build --build-arg webhome="/var/www/html" /docker/ -t mybox:v0.7
[root@centos7 docker]# docker run --name pc2 -it --rm mybox:v0.7 /bin/sh
/var/www/html #

run阶段Dockerfile文件中的指令

(run阶段:指明在bulid时做一些通过运行shell命令来达到去设定目标镜像的目的)

  • RUN

    • 用于指定docker build过程中运行的程序,其可以是任何命令(run的任何命令代表基础镜像支持的命令)
    • Syntax
      • RUN <command> 或 #以shell解释运行
      • RUN ["<executable>", "<param1>", "<param2>"] #不以shell解释运行
    • 第一种格式中,<command>通常是一个shell命令,且以“/bin/sh -c”来运行它,这意味着此进程 在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器 时,此进程接收不到SIGTERM信号;
    • 第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的 <paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起 ,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令 依赖于此shell特性的话,可以将其替换为类似下面的格式。
      • RUN ["/bin/sh", "-c", "<executable>", "<param1>"]
        • 注意:json数组中,要使用双引号
  • CMD

    • 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者 的运行时间点不同
      • RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像 文件启动一个容器时
      • CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也 将终止;不过,CMD指定的命令其可以被docker run的命令行选项所覆盖
      • 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
    • Syntax
      • CMD <command> 或 #以shell运行
      • CMD [“<executable>”, “<param1>”, “<param2>”] 或 #不以shell解释运行
      • CMD ["<param1>","<param2>"]
    • 前两种语法格式的意义同RUN
    • 第三种则用于为ENTRYPOINT指令提供默认参数
  • ENTRYPOINT

    • 类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个 单独的可执行程序
    • 与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的 参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定 指定的程序
      • 不过,docker run命令的–entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序
    • Syntax
      • ENTRYPOINT <command>
      • ENTRYPOINT ["<executable>", "<param1>", "<param2>"]
    • docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到 ENTRYPOINT命令最后做为其参数使用
    • Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效

Dockerfile文件中RUN指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#运行起来的命令还是shell
[root@centos7 dockerlamp]# pwd
/dockerlamp
[root@centos7 dockerlamp]# cat Dockerfile
FROM centos:7
LABEL maintainer="daizhe<daizhe@9527dz.top>"
ARG root=/var/www/html/
RUN yum makecache && \
yum -y install httpd php php-mysql && \
yum clean all && \
rm -rf /var/cache/yum/* #删除yum生成的缓存不免刻录至镜像中

[root@centos7 dockerlamp]# docker run --name pc1 --rm -it lamp:v0.1 /bin/sh
sh-4.2# rpm -q httpd php
httpd-2.4.6-88.el7.centos.x86_64
php-5.4.16-46.el7.x86_64

Dockerfile文件中CMD指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#RUN在bulid阶段
#CMD在run阶段
#实现容器运行起来不是shell而是httpd,实现httpd运行在前台
###################################################################
如何实现将httpd实现前台运行
cat /usr/lib/systemd/system/httpd.service
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
####################################################################
[root@centos7 ~]# cd /dockerlamp/
[root@centos7 dockerlamp]# cat Dockerfile
FROM centos:7
LABEL maintainer="daizhe<daizhe@9527dz.top>"
ARG root=/var/www/html/
RUN yum makecache && \
yum -y install httpd php php-mysql && \
yum clean all && \
rm -rf /var/cache/yum/*
CMD ["usr/sbin/httpd","-DFOREGROUND"]

[root@centos7 dockerlamp]# docker image build /dockerlamp/ -t lamp:v0.2
[root@centos7 dockerlamp]# docker run --name pc2 -it --rm lamp:v0.2

#烟验证
[root@centos7 ~]# docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6b5dd3c9664 lamp:v0.2 "usr/sbin/httpd -DFO…" About a minute ago Up About a minute pc2
[root@centos7 dockerlamp]# docker exec -it pc2 /bin/bash
[root@f6b5dd3c9664 /]# netstat -tnl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN


###########################################################################
####################################改进###################################
##################制作Dockerfile文件并添加测试页打包至镜像###################
[root@centos7 dockerlamp]# pwd
/dockerlamp
[root@centos7 dockerlamp]# vim php.php
<?php
phpinfo();
?>
[root@centos7 dockerlamp]# vim Dockerfile
FROM centos:7
LABEL maintainer="daizhe<daizhe@9527dz.top>"
ARG root=/var/www/html/
RUN yum makecache && \
yum -y install httpd php php-mysql && \
yum clean all && \
rm -rf /var/cache/yum/*
ADD php.php ${root}
CMD ["usr/sbin/httpd","-DFOREGROUND"]

##########################################################################
###############################打镜像并运行容器测试########################
##########################################################################
[root@centos7 dockerlamp]# docker image build /dockerlamp/ -t lamp:v0.3
[root@centos7 dockerlamp]# docker run --name pc3 -it --rm lamp:v0.3

#测试
[root@centos7 dockerlamp]# docker exec -it pc3 /bin/bash
[root@b1da3c0ce6d8 /]# curl 172.17.0.2

##########################################################################
###############################说明#######################################
##########################################################################
此时也可以用户在命令行中运行指定使用/bin/bash运行的
##可以手动指定命令来覆盖镜像Dockerfile文件中CMD的
##上一个镜像文件中默认已经定义运行容器默认运行的进程为httpd的,可以手动运行/bin/bash
[root@centos7 dockerlamp]# docker run --name pc3 -it --rm lamp:v0.3 /bin/bash
[root@97ef0a13d4fc /]#
[root@97ef0a13d4fc /]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.1 11820 1884 pts/0 Ss 07:48 0:00 /bin/bash
root 16 0.0 0.0 51740 1732 pts/0 R+ 07:49 0:00 ps aux

#Dokcerfile文件中定义的运行httpd已经被覆盖,查看进程httpd进程未被启动,如果想要CMD不被覆盖则此时应该用到ENTRYPOINT

Dockerfile文件中ENTRYPOINT指令( --entrypoint )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#ENTRYPOINT单独使用情况下作用于CMD大致相同除了不可被用户命令行运行容器时任意被覆盖
##########################################################################
###########################常见Dockerfile文件##############################
##########################################################################
[root@centos7 dockerlamp]# pwd
/dockerlamp

[root@centos7 dockerlamp]# vim Dockerfile

FROM centos:7
LABEL maintainer="daizhe<daizhe@9527dz.top>"
ARG root=/var/www/html/
RUN yum makecache && \
yum -y install httpd php php-mysql && \
yum clean all && \
rm -rf /var/cache/yum/*
ADD php.php ${root}
EXPOSE 80/tcp
VOLUME ${root}
ENTRYPOINT ["usr/sbin/httpd","-DFOREGROUND"]

[root@centos7 dockerlamp]# ls
Dockerfile php.php

##########################################################################
###########################打镜像运行容器##################################
##########################################################################
[root@centos7 dockerlamp]# docker image build /dockerlamp/ -t lamp:v0.4
[root@centos7 dockerlamp]# docker run --name pc1 -it -P --rm lamp:v0.4

##########################################################################
###########################宿主机检测######################################
##########################################################################
[root@centos7 dockerlamp]# docker container ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0031f963fce6 lamp:v0.4 "usr/sbin/httpd -DFO…" 41 seconds ago Up 41 seconds 80/tcp pc1

[root@centos7 dockerlamp]# docker container port pc1
80/tcp -> 0.0.0.0:32769
[root@centos7 dockerlamp]# curl 172.18.135.1:32769

##########################################################################
############测试试图覆盖Docker文件中定义的执行的ENTRYPOINT指令###############
##########################################################################
[root@centos7 dockerlamp]# docker run --name pc1 -P -it --rm lamp:v0.4 /bin/bash
Usage: usr/sbin/httpd [-D name] [-d directory] [-f file]

#报错拒绝覆盖Docker文件中定义的执行的ENTRYPOINT指令
#命令行运行时添加的/bin/bash则当作了Docker文件中定义的执行的ENTRYPOINT指令后面的参数(httpd不支持/bin/bash当作参数)

##########################################################################
########用户执行命令时如何指明强制覆盖Docker文件中定义的执行的ENTRYPOINT指令##
##########################################################################
[root@centos7 dockerlamp]# docker run --name pc1 -P -it --rm --entrypoint "/bin/bash" lamp:v0.4
[root@5de1663077eb /]#

Dockerfile文件中ENTRYPOINT指令于CMD指令同时使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#CMD定义的命令都要统统作为ENTRYPOINT的参数
#一下两种格式意义相同
CMD ["usr/sbin/httpd","-DFOREGROUND"] #CMD作为ENTRYPOINT的参数执行
ENTRYPOINT ["/bin/bash","-c"]
=========================================================================
CMD /usr/bin/httpd -DFOREGROUD


##########################################################################
ENTRYPOINT与CMD分隔开来写的意义:
在ENTRYPOINT运行一个脚本,CMD的指令会被当作脚本的参数传递给脚本,脚本作为传统应用程序和容器化运行的中间层,来处理配置文件的,同时此配置文件是可以接受环境变量为参数来设置配置文件。


##########################################################################
###############Dockerfile文件中ENTRYPOINT指令于CMD指令同时使用############
##########################################################################
[root@centos7 dockerlamp]# vim Dockerfile
FROM centos:7
LABEL maintainer="daizhe<daizhe@9527dz.top>"
ARG root=/var/www/html/
RUN yum makecache && \
yum -y install httpd php php-mysql && \
yum clean all && \
rm -rf /var/cache/yum/*
ADD php.php ${root}
ADD ent.sh /bin/
EXPOSE 8080/tcp
VOLUME ${root}
CMD ["usr/sbin/httpd","-DFOREGROUND"]
ENTRYPOINT ["/bin/ent.sh"]


#编写的脚本的解释器一定是基础镜像中所被支持解释的类型
[root@centos7 dockerlamp]# vim ent.sh
#!/bin/bash
#
#如果用户没定义此为默认的变量
listen_port=${LISTEN_PORT:-8080}
server_name=${SERVER_NAME:-localhost}
doc_root=${DOC_ROOT:-/var/www/html}

cat > /etc/httpd/conf.d/myweb.conf <<EOF
listen $listen_port
<VirtualHost *:${listen_port}>
ServerName "$server_name"
DocumentRoot "$doc_root"
<Directory "$doc_root">
Options none
AllowOverride none
Require all granted
</Directory>
</Virtualhost>
EOF
#引用一个脚本的所有参数,默认的httpd进程/bin/bash的子进程>,要想使得httpd作为init下的一级进程则如下写法(目标进程替换shell进程,让shell自动退出)
exec "$@"

[root@centos7 dockerlamp]# chmod +x /dockerlamp/ent.sh
[root@centos7 dockerlamp]# docker image build /dockerlamp/ -t lamp:v0.5
[root@centos7 dockerlamp]# docker run --name pc1 -it --rm lamp:v0.5(可以在命令行中使用-e选项对容器中的环境变量传值 使用printenv命令可以查看传入变量的值
)
[root@centos7 ~]# docker container port pc1
[root@centos7 ~]# curl 172.18.135.1:32777
[root@centos7 ~]# docker exec -it pc1 /bin/bash
[root@5b32b59d73ef /]# cat /etc/httpd/conf.d/myweb.conf
listen 8080
<VirtualHost *:8080>
ServerName "localhost"
DocumentRoot "/var/www/html"
<Directory "/var/www/html">
Options none
AllowOverride none
Require all granted
</Directory>
</Virtualhost>
#httpd的进程号为1
[root@2967451fc4a9 /]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.7 408092 13436 pts/0 Ss+ 09:19 0:00 usr/sbin/httpd -DFOREGROUND
apache 8 0.0 0.3 408092 6748 pts/0 S+ 09:19 0:00 usr/sbin/httpd -DFOREGROUND
apache 9 0.0 0.3 408092 6748 pts/0 S+ 09:19 0:00 usr/sbin/httpd -DFOREGROUND
apache 10 0.0 0.3 408092 6748 pts/0 S+ 09:19 0:00 usr/sbin/httpd -DFOREGROUND
apache 11 0.0 0.3 408092 6748 pts/0 S+ 09:19 0:00 usr/sbin/httpd -DFOREGROUND
apache 12 0.0 0.3 408092 6748 pts/0 S+ 09:19 0:00 usr/sbin/httpd -DFOREGROUND

##########################################################################
###############run是使用-e选项对容器进行变量复制############################
##########################################################################
(可以在命令行中使用-e选项对容器中的环境变量传值 使用printenv命令可以查看传入变量的值 )
[root@centos7 dockerlamp]# docker run --name pc1 -it --rm -P -e LISTEN_PORT=1010 lamp:v0.10
[root@centos7 ~]# docker exec -it pc1 /bin/bash
[root@067566aa1878 /]# printenv
LISTEN_PORT=1010
[root@centos7 dockerlamp]# docker run --name pc1 -it --rm -P -e hi=hehe lamp:v0.10
[root@centos7 ~]# docker exec -it pc1 /bin/bash
[root@2967451fc4a9 /]# echo $hi
hehe

  • USER

    • 用于指定运行image时的或运行Dockerfile中任何RUN、CMD或ENTRYPOINT 指令指定的程序时的用户名或UID
    • 默认情况下,container的运行身份为root用户
    • Syntax
      • USER |
      • 需要注意的是,可以为任意数字,但实践中其必须为/etc/passwd中某用户的有效 UID,否则,docker run命令将运行失败
  • HEALTHCHECK健康状态检测(新版支持)

    • HEALTHCHECK指令告诉Docker如何测试一个容器,以检查它是否仍在工作。这可以检测出一些情况,比如web服务器陷入无限循环,无法处理新连接,即使服务器进程仍在运行。
    • HEALTHCHECK指令有两种形式:

      • HEALTHCHECK [OPTIONS] CMD命令(通过在容器内运行命令来检查容器的健康状况)
      • HEALTHCHECK NONE(不做任何健康检测)
    • HEALTHCHECK(2)

    • 在CMD之前可以出现的选项有:
      • –interval=DURATION (default: 30s) #每隔多久检测一次,检测频率默认为30秒
      • –timeout=DURATION (default: 30s) #相对方发起检测请求,等待超时时长默认为30秒
      • –start-period=DURATION (default: 0s) #在什么时间开始进程健康检测,0表示容易以启动立刻做第一次健康检测
      • –retries=N (default: 3) #检测失败,重试检测多少吃后失败再判定为失败,默认为检测3次
    • 命令的退出状态指示容器的健康状态。可能的值是:
      • 0: success 成功
      • 1: unhealthy 不健康
      • 2: reserved 保留
    • 范例:

Dockerfile文件中HEALTHCHECK健康状态检测指令(新版支持)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
##########################################################################
##########################定制健康检查计划##################################
##########################################################################
[root@centos7 ~]# vim /dockerlamp/Dockerfile
FROM centos:7
LABEL maintainer="daizhe<daizhe@9527dz.top>"
ARG root=/var/www/html/
RUN yum makecache && \
yum -y install httpd php php-mysql curl && \
yum clean all && \
rm -rf /var/cache/yum/*
ADD ok.html php.php ${root}
ADD ent.sh /bin/
EXPOSE 8080/tcp
VOLUME ${root}
HEALTHCHECK --interval=3s --timeout=3s --start-period=2s CMD curl -f http://localhost/ok.html || exit 1
CMD ["usr/sbin/httpd","-DFOREGROUND"]
ENTRYPOINT ["/bin/ent.sh"]

[root@centos7 dockerlamp]# ls
Dockerfile ent.sh php.php
[root@centos7 dockerlamp]# echo "ok" > ok.html

##########################################################################
######################打镜像测试健康计划##################################
##########################################################################
[root@centos7 dockerlamp]# docker image build /dockerlamp/ -t lamp:v1.0
[root@centos7 dockerlamp]# docker run --name pc1 -it --rm lamp:v1.0
#查看状态健康的
[root@centos7 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
763a1536b62d lamp:v1.0 "/bin/ent.sh usr/sbi…" 6 seconds ago Up 5 seconds (healthy) 8080/tcp pc1

##########################################################################
####################删除文件查看是否不健康##################################
##########################################################################
[root@centos7 ~]# docker exec -it pc1 /bin/bash
[root@763a1536b62d /]# rm -rf /var/www/html/ok.html
[root@centos7 dockerlamp]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
763a1536b62d lamp:v1.0 "/bin/ent.sh usr/sbi…" 3 minutes ago Up 3 minutes (unhealthy) 8080/tcp pc1

#一旦发现容器出错时,手动将容器杀死重新构建,此功能是容器引擎做不到的,需要借助容器编排工具

#如果再构建镜像的时候未构建也可以再运行命令行运行容器时手动指定(人为的在外部定义)

[root@centos7 dockerlamp]# docker run --help

Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
--health-cmd string Command to run to check health
--health-interval duration Time between running the check (ms|s|m|h)
(default 0s)
--health-retries int Consecutive failures needed to report unhealthy
--health-start-period duration Start period for the container to initialize
before starting health-retries countdown
(ms|s|m|h) (default 0s)
--health-timeout duration Maximum time to allow one check to run

  • SHELL

    • 指令允许覆盖命令的SHELL形式所使用的默认SHELL。
    • Linux上的默认shell是[“/bin/sh”, “-c”]
    • Windows上的默认shell是[“cmd”, “/S”, “/C”]
    • SHELL指令必须以JSON格式写入Dockerfile中
    • 语法:SHELL[“可执行”,”参数”]
    • 外壳指令可以出现多次。每个SHELL指令覆盖前面的所有SHELL指令,并影响后面的所有指令。
  • STOPSIGNAL

    • 指令设置将发送到容器的系统调用信号以退出
    • 这个信号可以是一个有效的无符号数字
    • 它匹配内核的syscall表中的一个位置,例如9
    • 也可以是SIGNAME格式的一个信号名,例如SIGKILL。
    • Syntax:
      • STOPSIGNAL signal
  • ONBUILD

    • 用于在Dockerfile中定义一个触发器
    • Dockerfile用于build映像文件,此映像文件亦可作为base image被另一个Dockerfile 用作FROM指令的参数,并以之构建新的映像文件
    • 在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会“触发”创 建其base image的Dockerfile文件中的ONBUILD指令定义的触发器
    • Syntax
      • ONBUILD
      • 尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和 MAINTAINER指令
      • 使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如ruby:2.0-onbuild
      • 在ONBUILD指令中使用ADD或COPY指令应该格外小心,因为新构建过程的上下文在缺少指 定的源文件时会失败

Dockerfile文件中的ONBUILD指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
当别人利用自己的镜像做基础镜像
你自己先前定义好的dockerfile,当别人拿自己镜像做基础镜像再次创建的dockerfile文件,自己填写的ONBUILD指令在自己run的时候不会运行,当别人拿自己镜像在此基础上创建的dockerfile执行的时候才会运行自己定义的ONBUILD指令。

#定义ONBUILD,当别人拿自己的镜像做基础镜像再次做dockerfile执行时则在/data/data目录中下载URL,自己run时则不执行
[root@centos7 ~]# mkdir /test
[root@centos7 ~]# cd /test/
[root@centos7 test]# vim Dockerfile

FROM busybox:latest
LABEL maintainer="daizhe<daizhe@9527dz.top>"
RUN mkdir -p /data/data
ONBUILD ADD http://nginx.org/download/nginx-1.2.9.tar.gz /data/data
#打镜像
[root@centos7 test]# docker image build /test/ -t haha:v0.1

#在自己制作的基础上再次制作
[root@centos7 ~]# mkdir /test1
[root@centos7 ~]# cd !$
cd /test1
[root@centos7 test1]# vim Dockerfile
FROM haha:v0.1
RUN mkdir -p /data/haha

#此时第一次制作的镜像定义的ONBUILD 会执行
[root@centos7 test1]# docker image build /test1/ -t hehe:v0.1

如何将自己本地制作的镜像分享给别人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
此场景适用于内部临时是使用、本地间的节点间共享

将本地的镜像文件打包,剥离远程镜像仓库的格式,打包未tar文件,实现节点共享

#####################抽取本地上的镜像######################
[root@centos7 ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hehe v0.1 e75cb1954996 7 minutes ago 1.93M
[root@centos7 ~]# docker image save hehe:v0.1 -o ./jingxiang.tar
[root@centos7 ~]# ls
jingxiang.tar

#####################复制到其他节点,使用此镜像#################
[root@centos7 ~]# docker image load -i jingxiang.tar
-------------------码字不易尊重原创转载标注不胜感激-------------------
Yes or no?
0%