Dockerfile
1、说明
Dockerfile是一个组合镜像命令的文本文件,其中存放了一系列指令,Docker通过这些指令自动生成镜像。
写好Dockerfile之后,通过指令docker build -t repository:tag 路径 即可构建,要求路径下存在Dockerfile文件。
镜像是分层的,Dockerfile中每多一条指令,就多一层。用&&或\连接的多条指令仍视为一条指令。
2、规则
- 文件名一定是Dockerfile;
- Dockerfile中用到的所有文件都和Dockerfile文件位于同级目录下;
- Dockerfile中的相对路径默认都是Dockerfile所在目录;
- Dockerfile是分层结构,一行就是一层,构建镜像时是分层构建的,因此某些指令能写到一行就写到一行,减少层次;
- Dockerfile对指令大小写不敏感,但是指令都用大写;
- 非注释的第一行一定是FROM;
- Dockerfile工作空间目录下支持隐藏文件(.dockerignore),类似git的.gitignore
- 一行写不下,可以用\来换行接着写
3、指令
1)FROM:基础镜像
语法:FROM <image>:<tag> [as new_name]
例子:
FROM 172.30.138.23/base/nginx_2024v1:latest
说明
- FROM是非注释首行代码;
- 为该镜像文件指定基础镜像,后续指令都基于该基础镜像环境运行;
- 基础镜像可以是任何一个已存在的镜像文件;
- as new_name是可选的,常用于长期工程、多阶段构建(有利于减少镜像大小)
- 通过--from other_name 使用,例如COPY --from oter_name。
2)LABEL:镜像描述信息
语法
#① LABEL K1=V1 K2=V2 #② LABEL K1=V1 LABEL K2=V2 #③ LABEL K1=V1 \ K2=V2
例子
LABEL author="zp wang <test@qq.com>" LABEL describe="test image"
说明
- V一般情况下是带引号字符串;
- LABEL长用于以K-V对的形式给镜像添加一些META信息;
- 可以用于替代MAINTAINER指令;
- 会集成基础镜像中的LABEL,如果二者存在同名K,则新K覆盖老K。
3)MAINTAINER:作者信息
语法:MAINTAINER 姓名 <邮箱>
例子
MAINTAINER Shine Le <test@qq.com>
说明:其功能正逐渐被LABEL替代
4)COPY:从本机复制文件到镜像中
用途:
从本机复制文件到镜像中,每个镜像在运行起来之后,都有其独立的文件系统结构,就像一个虚拟机一样。
使用COPY指令可以把本机中的文件复制到镜像中的指定目录下。
语法:COPY src dst
例子
COPY startServer.sh /app/bin/startServer.sh
说明
关于src
- src是本机路径,且为以Dockerfile所在目录为起始的相对路径;
- src的路径必须是以Dockerfile所在的目录为起始,不能选到Dockerfile的父目录;
- 如果src是目录,那么其下的所有文件、子目录都会递归复制到dst,但src目录自身不会复制;
- 因此要把某个目录复制到镜像中的同名目录下,dst中还要把该目录名给加上;
- 如果指定了多个src,那么dst必须是目录,且以/结尾;
关于dst
- dst为容器中的路径,每个容器都像一个虚拟机,其中的文件有独立的文件结构和路径;
- 如果dst不存在,那么会自动递归创建。
5)ADD:从本机复制文件到镜像
用途:
同COPY,但是ADD支持将tar文件解压缩
语法:ADD src dst
说明
- 如果src是一个压缩文件,那么会被解压为一个目录;
- 如果src是一个URL,那么会通过URL下载一个文件;
- 如果src是多个,那么dst必须是以/结尾的目录,否则src会被视为一个普通文件。
6)WORKDIR:设置(容器)工作目录
用途:
类似cd命令,改变(容器中的)当前工作目录。
默认情况下,容器命令执行时的当前目录为/,可以通过WORKDIR改变当前目录。
之后的RUN、CMD、ENTRYPOINT、COPY、ADD都会将该目录作为当前工作目录。
语法:WORKDIR 绝对路径
例子
WORKDIR /opt
说明
- 如果路径中的某个目录不存在会自动创建,包括它的父目录;
- 一个Dockerfile中的WORKDIR可以出现多次,也可以为相对路径,这里的相对是指相对于前一个WORKDIR;
- 可以在WORKDIR中调用ENV指定的变量。
7)ENV:设置环境变量
语法
ENV K1 V1
ENV K1=V1 K2=V2 K3=V3 ……
环境变量的使用方式(下文的K是上文K-V定义时的K)
- $K
- ${K}
- ${K:-default V}
- ${K:+default V}
例子
#定义 ENV NGINX_VERSION 1.16.1 #使用 RUN cd /usr \ && tar -zxvf nginx_${NGINX_VERSION}.tar.gz
8)USER:设置启动容器的用户
语法:USER username
例子
USER dcos
9)RUN:构建镜像时指定的命令
语法
- shell形式:RUN 指令1 && 指令2 && ……
- exec形式:RUN ["executable" , "参数1" , "参数2" , ……]
例子
#简单用法 #打印1和2 RUN echo 1 && echo 2 #常规用法 RUN chown -R dcos:docker /app/bin/startServer.sh /usr/nginx/conf #分行多条指令 RUN cd /usr \ && curl -O https://172.29.32.190:8081/nginx/${NGINX_VERSION}.tar.gz \ && tar -zxvf nginx/${NGINX_VERSIOIN}.tar.gz
说明
- RUN在下次构建期间,会优先查找本地缓存,如果不想用缓存可以用--no-cache解除:
docker build --no-cache
- shell形式:
- 默认用/bin/sh -c执行后续的命令;
- 可以用&&与\连接多个命令
- exec形式:
- exec形式会被解析为JSON序列,这意味着必须用双引号""
- 与shell不同,exec形式不会调用shell解析。但是exec形式可以运行在不包含shell命令的基础镜像中;
- 例如:
RUN ["echo","$HOME"]
;这样的指令$HOME
并不会被解析,必须RUN ["/bin/sh","-c","echo $HOME"]
10)EXPOSE:打开指定端口以实现与外部通信
语法:EXPOSE <port>/<protocol>
例子
EXPOSE 80 EXPOSE 80/http EXPOSE 2379/tcp
说明
- 不写protocol时,默认协议为tcp;
- 实际暴露时需要在docker run时用-P指定。
11)VOLUME:挂载,将宿主机目录挂载到容器中
语法:VOLUME 挂载路径 挂载点
例子:
VOLUME ["/data"] # [“/data”]可以是一个JsonArray ,也可以是多个值 VOLUME /var/log VOLUME /var/log /opt
说明
- 一般不用于Dockerfile,且在Kubernetes场景中几乎没用
12)CMD:为容器设置默认启动命令或参数
语法
#1 shell形式 CMD 指令 参1 参2 #2 exec形式 CMD ["executable","参1","参2"] #3 exec形式,但是只设置参数 CMD ["参1","参2"]
例子
CMD ["/app/bin/startServer.sh"]
说明
- CMD运行结束后容器将终止,CMD可以被docker run后边的命令覆盖;
- 一个Dockerfile只有顺序向下的最后一个CMD生效;
- 三种语法:
- shell,默认/bin/sh -c
- 此时运行为shell的子进程,可以使用shell的操作符(if、环境变量、?*通配符)
- 位于容器中的进程的PID !=1 ,这意味着该进程并不能接受到外部传入的停止信号docker stop;
- exec,CMD ["executable","参数1",'参数2"]
- 不会以/bin/sh -c运行(非shell子进程),因此不支持shell操作符;
- 若运行的命令依赖shell特性,可以手动启动 CMD ["/bin/sh","-c","executable","参1","参2",……]
- exec,CMD ["参1","参2"]
- 一般结合ENTRYPOINT指令使用。
- shell,默认/bin/sh -c
13)ENTRYPOINT:为容器指定默认运行程序或命令
用途
与CMD类似,但存在区别,主要用于指定启动的父进程的PID=1。
用法
#1 shell形式 ENTRYPOINT command #2 execz形式 ENTRYPOINT ["/bin/bash","参1","参2"]
说明
- ENTRYPOINT设置默认命令不会被docker run命令行指定的参数覆盖,指定的参数会被传递给ENTRYPOINT指定的程序;
- docker run命令的--entrypoint选项可以覆盖ENTRYPOINT指令指定的程序;
- 一个Dockerfile中可以有多个ENTRYPOINT,但只有最后一个生效;
- ENTRYPOINT主要用于启动父进程,后边的参数会被当做子进程来启动。
4、补充
1)Dockerfile非注释首行是FROM,代表它的基础镜像。但是首个基础镜像的FROM是什么?
由于FROM是构建镜像上下文的开始,因此必须存在。
基础镜像:FROM scratch,表示使用一个空镜像。