文章目录
一、基本结构
Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。
Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。
Docker分为四部分:
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时默认要执行的指令
例如:
# This dockerfile uses the ubuntu image
# VERSION 2 - EDITION 1
# Author: seancheng
# Command format: Instruction [arguments / command] ...
# 第一行必须指定基于的基础镜像
FROM ubuntu
# 维护者信息
LABEL MAINTAINER='seancheng xianshangxian@126.com'
# 镜像操作指令
RUN echo "deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# 容器启动时默认要执行的指令
CMD /usr/sbin/nginx
其中,一开始必须指明所基于的镜像名称,接下来一般会说明维护者信息。
后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像添加新的一层,并提交。
最后是CMD指令来指定运行容器时的操作指令。
二、指令
指令的一般格式为INSTRUCTION arguments
,指令包括:
指令名字 | 作用 |
---|---|
FROM | 基础镜像,一切从这里开始构建 |
MAINTAINER | 镜像是谁写的,姓名+邮箱 |
RUN | 镜像构建的时候需要运行的命 |
ADD | 提供安装包位置 |
WORKDIR | 镜像的工作目录 |
VOLUME | 挂载的目录 |
EXPOSE | 暴露端口配置 |
CMD | 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 |
ENTRYPOINT | 指定这个容器启动的时候要运行的命令,可以追加命令 |
ONBUILD | 当构建一个被继承 Dockerfile 这个时候就会运行ONBUILD 的指令 |
COPY | 类似ADD,将我们文件拷贝到镜像中 |
ENV | 构建的时候设置环境变量 |
2.1 FROM
格式为FROM <image>
或FROM <image>:<tag>
。
第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。
FROM centos:8(默认是最新版本)
2.2 LABEL MAINTAINER(维护者)
格式为LABEL MAINTAINER <name email_address>
,指定维护者信息
用户名字+邮箱
LABEL MAINTAINER='amu 123@qq.com'
2.3 RUN
格式为RUN <command>
或RUN ["executable","param1","param2"]
。
前者将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行。指定使用其他终端可以通过第二种方式实现,例如:
[root@localhost ~]# mkdir test
[root@localhost ~]# cd test/
[root@localhost test]# cat Dockerfile
FROM centos
RUN mkdir abc
[root@localhost test]# docker build -t test:v0.1 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : RUN mkdir abc
---> Running in 1cc3cd5aa69d
Removing intermediate container 1cc3cd5aa69d
---> 37ec05f5a1ac
Successfully built 37ec05f5a1ac
Successfully tagged test:v0.1
[root@localhost test]# docker run -it --rm test:v0.1
[root@95d5cf5be279 /]# ls
abc etc lib64 mnt root srv usr
bin home lost+found opt run sys var
dev lib media proc sbin tmp
[root@localhost test]# cat Dockerfile
FROM centos
RUN ["/usr/bin/mkdir","-p","/hehe/xixi/haha"]
[root@localhost test]# docker build -t test:v0.2 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : RUN ["/usr/bin/mkdir","-p","/hehe/xixi/haha"]
---> Running in 36392aa44fb9
Removing intermediate container 36392aa44fb9
---> baf7fce2f1d7
Successfully built baf7fce2f1d7
Successfully tagged test:v0.2
[root@localhost test]# docker run -it --rm test:v0.2
[root@4d9d5dfddfc7 /]# ls
bin hehe lib64 mnt root srv usr
dev home lost+found opt run sys var
etc lib media proc sbin tmp
[root@4d9d5dfddfc7 /]# cd hehe/
[root@4d9d5dfddfc7 hehe]# ls xixi/
haha
每条RUN指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行,例如:
[root@localhost test]# cat Dockerfile
FROM centos
RUN echo "hello world\nhello tom" > /tmp/abc && \
cat /tmp/abc
2.4 CMD
CMD支持三种格式:
CMD ["executable","param1","param2"]
使用exec执行,推荐方式CMD command param1 param2
在/bin/sh中执行,提供给需要交互的应用CMD ["param1","param2"]
提供给ENTRYPOINT的默认参数
CMD用于指定启动容器时默认要执行的命令,如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT,那么就会使用执行CMD指定的默认的命令
每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。
// 使用CMD第二种格式
[root@localhost test]# cat Dockerfile
FROM centos
CMD sleep 600 // 当CMD只有这一条的时候就执行当前命令
[root@localhost test]# docker build -t test:v0.4 /root/test
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : CMD sleep 600
---> Running in c8334041d0d8
Removing intermediate container c8334041d0d8
---> 04b29b18007f
Successfully built 04b29b18007f
Successfully tagged test:v0.4
[root@localhost test]# docker run -itd --rm test:v0.4
e332f6d2b7e49bfd1b536ba8d4c2dd8fa2473b84b2fd33280ba5d503b493f429
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e332f6d2b7e4 test:v0.4 "/bin/sh -c 'sleep 6…" 3 seconds ago Up 2 seconds trusting_chaplygin
[root@localhost test]# cat Dockerfile
FROM centos
CMD sleep 600
CMD sleep 700
CMD sleep 800 // 当CMD有三条的时候,只会执行最后一条命令
[root@localhost test]# docker build -t test:v0.5 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 5d0da3dc9764
Step 2/4 : CMD sleep 600
---> Using cache
---> 04b29b18007f
Step 3/4 : CMD sleep 700
---> Running in 0894d1cb0ee8
Removing intermediate container 0894d1cb0ee8
---> c8dc64c9276e
Step 4/4 : CMD sleep 800
---> Running in a8d504b7b9b1
Removing intermediate container a8d504b7b9b1
---> a1bb66d8c5d2
Successfully built a1bb66d8c5d2
Successfully tagged test:v0.5
[root@localhost test]# docker run -itd --rm test:v0.5
f95fb66e5c16a446984a2e88648a85465deb7569e82664997eebc7dad960064d
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f95fb66e5c16 test:v0.5 "/bin/sh -c 'sleep 8…" 2 seconds ago Up 2 seconds vigorous_ritchie
如果用户启动容器时指定了运行的命令,则会覆盖掉CMD指定的命令。
[root@localhost test]# docker images
[root@localhost test]# cat Dockerfile
FROM centos
CMD ["sleep","400"]
[root@localhost test]# docker build -t test:v0.8 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : CMD ["sleep","400"]
---> Running in faffd15f9944
Removing intermediate container faffd15f9944
---> 0c1864ac64c6
Successfully built 0c1864ac64c6
Successfully tagged test:v0.8
// 没有覆盖是这样的
[root@localhost test]# docker run -itd --rm test:v0.8
b4e6f4625d04b824cf7dc324c50ef603c31e3366464006bc067ba9b5a4a7288d
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b4e6f4625d04 test:v0.8 "sleep 400" 5 seconds ago Up 4 seconds strange_chandrasekhar
[root@localhost test]# docker rm -f b4e6f4625d04
b4e6f4625d04
// 覆盖之后 sleep 400 变成 /bin/bash
[root@localhost test]# docker run -itd --rm test:v0.8 /bin/bash
fbf0ec0e58fdf49358aca74efd2575464724fef5afa15890cc93193916016e65
[root@localhost test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fbf0ec0e58fd test:v0.8 "/bin/bash" 5 seconds ago Up 4 seconds naughty_albattani
使用CMD第一种格式在前台运行httpd(推荐使用这种格式)
[root@localhost test]# cat Dockerfile
FROM centos
RUN ["/usr/bin/dnf","-y","install","httpd"]
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
[root@localhost test]# docker build -t test:v0.7 /root/test/
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM centos
---> 5d0da3dc9764
Step 2/3 : RUN ["/usr/bin/dnf","-y","install","httpd"]
---> Using cache
---> e044e1eda4ef
Step 3/3 :