目录
1. 基本结构
2. 配置指令
3. 操作指令
4. 创建镜像
5. 使用.dockerignore
6. springboot应用打包成镜像
Dockerfile
Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。
1. 基本结构
一般而言,Dockerfile主体内容分为四部分: 基础镜像部分 、维护者信息、镜像操作指令 和 容器启动时执行指令 。
2. 配置指令
指令 | 说明 | |
---|---|---|
1 | ARG | 定义镜像过程中使用的变量 |
2 | FROM | 指定所创建镜像的基础镜像 |
3 | LABEL | 为生成的镜像添加元数据标签信息 |
4 | EXPOSE | 声明镜像内服务监听的端口 |
5 | ENV | 指定环境变量 |
6 | ENTRYPOINT | 指定镜像默认入口命令 |
7 | VOLUME | 创建一个数据卷挂载点 |
8 | WORKDIR | 配置工作目录 |
9 | ONBUILD | 创建子镜像时指定自动执行的操作命令 |
(1) ARG
定义镜像过程中使用的变量。
格式:
ARG <参数名>[=<默认值>]
在执行 docker build
时,可以通过 -build-arg[=]
来赋值。当镜像编译成功后,ARG指定的变量将不再存在。(ENV指定的变量将在镜像中保留)
(2) FROM
指定所创建镜像的基础镜像
格式:
FROM <image> 或 FROM <image>:<tag>
任何Dockerfile中第一条指令必须为 FROM
指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM
指令(每个镜像一次)。
ARG VERSION=1.0
FROM debian:${VERSION}
(3)LABEL
为生成的镜像添加元数据标签信息。这些信息可以用来辅助过滤出特定镜像。
格式:
LABEL <key>=<value> <key>=<value>…
LABEL version="1.0"
LABEL author="user@github" date="2022-02-22"
LABEL description="This text may help you \
solve some problem."
(4)EXPOSE
声明镜像内服务监听的端口。
格式:
EXPOSE <port1> [<port2>…]
该指令只是起到声明的作用,并不会自动完成端口映射。
在运行时使用随机端口映射时,也就是 docker run -P
时,会自动随机映射 EXPOSE
的端口。
(5)ENV
指定环境变量。
格式:
ENV <key> <value> 或 ENV <key>=<value>…
# 设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用
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"
指令指定的环境变量在运行时可以被覆盖掉,如 docker run --env <key>=<value> built_image
。
注意,当 一条ENV 指令中同时为多个环境变量赋值并且值也是从环境变量中读取时,会为所有的变量都赋值后再更新。
# 最终结果为 key1=value1 key2=value2
ENV key1=value2
ENV key1=value1 key2=${key1}
(6)ENTRYPOINT
指定镜像默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。
支持格式:
- ENTRYPOINT["<executable", “param1”, “param2”]:exec调用执行。
- ENTRYPOINT command param1 param2 :shell中执行。
此时,CMD
指令指定值将作为根命令的参数。
每个Dockerfile只能有一个 ENTRYPOINT
,当指定多个时,只有最后一个起效。在运行时,可以被 --entrypoint
参数覆盖掉。
搭配 CMD
命令使用:一般变参才会使用 CMD
,这里的 CMD
相当于给 ENTRYPOINT
传参。
# 通过Dockerfile构建nginx:test镜像
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
-
不传参运行
docker run nginx:test # 容器会默认执行以下命令,启动主进程 nginx -c /etc/nginx/nginx.conf
-
传参运行
docker run nginx:test /etc/nginx/new.conf # 容器会默认执行以下命令,启动主进程 nginx -c /etc/nginx/new.conf
(7)VOLUME
创建一个数据卷挂载点。
格式:
VOLUME ["<path1>", “<path2>”, …]
运行容器时可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保持的数据等。
(8)WORKDIR
为后续的 RUN
、CMD
、ENTRYPOINT
指令配置工作目录。
格式:
WORKDIR <path>
可以使用多个 WORKDIR
指令,后续命令如果参数时相对路径,则会基于之前命令指定的路径。
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# 最终路径为/a/b/c
为了避免出错,推荐 WORKDIR
中只使用绝对路径。
(9)ONBUILD
指定当基于所生成镜像创建子镜像时,自动执行的操作指令。
格式:
ONBUILD [其他指令]
# 创建父镜像ParentImage,指定ONBUILD指令
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
使用 docker build
命令创建子镜像 ChildImage
时(FROM ParentImage),会首先执行 ParentImage
中配置的 ONBUILD
指令。
3. 操作指令
指令 | 说明 | |
---|---|---|
1 | RUN | 运行指定命令 |
2 | CMD | 用来指定启动容器时默认执行的命令 |
3 | ADD | 添加内容到镜像 |
4 | COPY | 复制内容到镜像 |
(1)RUN
运行指定命令。
shell格式:
RUN <command> :等同于,在终端操作的shell命令。
exec格式:
RUN [“executable”, “param1”, “param2”]:指令会被解析为JSON数组,因此必须加上双引号。
指定使用其他终端类型可以通过第二种方式实现:
RUN ["/bin/bash", "-c", "echo hello"]
每条 RUN
指令将在当前镜像基础上执行指定命令,并提交为新的镜像层。当命令较长时,可以使用 \
来换行。(Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。)
# 执行3个RUN指令,会创建3层镜像
FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
# 以 && 符号连接命令,进行简化
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
(2)CMD
该指令用来指定启动容器时默认执行的命令。
支持3种格式:
-
CMD [“executable”, “param1”, “param2”, …]:相当于执行
executable param1 param2 ...
,推荐方式; -
CMD command param1 param2 … :在默认的shell种执行,提供给需要交互的应用;
-
CMD [“param1”, “param2”, …] :提供给
ENTRYPOINT
的默认参数。
每个Dockerfile只能有一条 CMD
命令。如果指定了多条命令,只有最后一条会被执行。
如果用户启动容器时手动指定了运行的命令(作为 docker run
命令的参数),则会覆盖掉 CMD
指定的命令。
注意:
CMD
在docker run
时运行。RUN
是在docker build
。
(3)ADD
添加内容到镜像。
格式:
ADD <src> <dest>
该命令将赋值指定的<src>路径下内容到容器中的<dest>路径下。
其中<src>可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件( 自动解压为目录 )。<dest>可以是镜像内的绝对路径,或者相对于工作目录( WORKDIR
)的相对路径。
路径支持正则格式:
ADD *.c /code/
(4)COPY
复制内容到镜像。
格式:
COPY <src> <dest>
复制本机的<src>(为Dockerfile所在目录的相对路径,文件或者目录)下内容到镜像中的<dest>中。目标路径不存在时,会自动创建。
COPY
与 ADD
指令功能类似,当使用 本地目录为源目录 时,推荐使用COPY。
4. 创建镜像
编写完成Dockerfile之后,可以通过
docker [image] build
命令来创建镜像。
基本格式:
docker build [OPTIONS] PATH | URL | -
该命令读取指定路径下(包括子目录)的Dockerfile,并将该路径下所有数据作为 上下文(Context)
发送给Docker服务端。Docker服务端在校验Dockerfile格式通过后,逐条执行其中定义的指令,碰到 ADD
、COPY
和 RUN
指令会生成一层新的镜像。最终如果创建镜像成功,会返回最终镜像的UID。
如果使用非上下文路径下的Dockerfile,可以使用 -f
选项来指定其路径。
要指定生成镜像的标签信息,可以通过 -t
选项。该选项可以重复使用多次为镜像一次添加多个标签。
注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 服务端,如果文件过多会造成过程缓慢。
docker build -t nginx:v1 .
注意:最后的 .
代表本次执行的上下文路径。
5. 使用.dockerignore
可以使用 .dockerignore 文件(每一行添加一条匹配模式)来让Docker忽略匹配路径或文件,在创建镜像时候不将无用数据发送到服务端。
# .dockerignore 文件中可以定义忽略模式 (该行为注释)
*/temp*
*/*/temp*
tmp?
~*
Dockerfile
!README.md
- dockerignore文件中模式语法支持Colang风格的路径正则格式;
- “*”:表示任意多个字符;
- “?”:代表单个字符;
- “!”:表示不匹配(及不忽略指定的路径或文件)。
6. springboot应用打包成docker镜像
-
编写好springboot应用并打包。
@RestController public class HelloController { @RequestMapping("/hello") public String hello() { return "Hello, world!"; } }
-
编写Dockerfile。
FROM java:8 COPY *.jar /app.jar CMD ["--server.port=9000"] EXPOSE 9000 ENTRYPOINT ["java", "-jar", "/app.jar"]
-
把dockerfile和jar上传至服务器。
-
构建镜像。
docker build -t springboot_image:v1 .
-
运行。
docker run -d -p 9000:9000 --name springboot-web springboot_image:v1
-
结果