dockerfile
dockerfile
介绍
Dockerfile是一种被Docker程序解释执行的脚本,由一条条的命令组成,每条命令对应linux下面的一条命令,Docker程序将这些Dockerfile指令翻译成真正的linux命令,其有自己的书写方式和支持的命令,Docker程序读取Dockerfile并根据指令生成Docker镜像,相比手动制作镜像的方式,Dockerfile更能直观的展示镜像时怎么产生的,有了Dockerfile,当后期有额外的需求时,只要在之前的Dockerfile添加或者修改相应的命令即可重新生成新的docker镜像,避免了重复手动制作镜像。
dockerfile文件说明
- 每一行以Dockerfile的指令开头,指令不区分大小写,但是惯例使用大写
- 使用#开始作为注释
- 每一行只支持一条指令,每条指令可以携带多个参数
- 指令按文件的顺序从上至下进行执行
- 每个指令的执行会生成一个新的镜像层,为了减少分层和镜像大小,仅可能将多条指令合并成一条指令
- 一般需要多次执行dockerfile才能制作一个满意的镜像,每次执行Dockerfile都按顺序执行,从头开始,上次制作镜像时已经执行过的指令会被缓存,不需要重新执行,如果后续有一行新的指令没有被执行过,其往后的指令都将会重新执行,所以为了加速镜像制作,通常将最常变化的指令放在Dockerfile文件的最后面
dockerfile的相关指令
FROM:就是指定基础镜像,此指令通常必须放在Dockerfile文件第一个指令,后续的指令都是运行于此基准镜像所提供的运行环境
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>] FROM nginx:1.0
LABEL:指定镜像元数据,如镜像作者等
LABEL "com.example.vendor"="ACME Incorporated" LABEL com.example.label-with-value="foo" LABEL version="1.0" LABEL description="This text illustrates \ that label-values can span multiple lines."
RUN:用来在构建镜像阶段需要在FROM指定镜像中执行的shell命令(FROM指定的镜像必须支持这个shell)
- shell格式:RUN /bin/bash -c ls
- exec格式:RUN ["/bin/bash" , “-c” , “ls”]
ENV:设置环境变量,可以被后续指令通过 {KEY}进行引用,并在容器运行时保持
ENV <key>=<value> ENV WORK_DIR=/app
COPY:复制本地宿主机的文件到容器内
不能复制上下文之外的文件(docker build命令执行的目录为上下文)
如果是目录,只复制目录中的内容,而非目录本身
COPY checkredis.py . 把checkredis.py复制到WORKDIR目录中 COPY check.log /testdir/ 把上下文中的check.log复制到/testdir目录下 COPY nickdir . 把nickdir目录中的内容复制到WORKDIR目录中,不复制目录本身
ADD:该命令可认为是增强版的COPY,不仅支持COPY,还支持自动解压。可以将指定的文件复制到容器内
不能复制上下文之外的文件(docker build命令执行的目录为上下文)
可以是Dockerfile所在目录的一个相对路径,也可以是一个URL,还可以是一个tar文件会自动解压
如果是目录,只复制目录中的内容,而非目录本身
如果是一个URL,下载后的文件权限自动设置为600
如果为URL且不以/结尾,则指定的文件将被下载并直接被创建,如果以/结尾,则文件名URL指定的文件将被直接下载并保存为/<filename>
如果是本地文件系统上的打包文件,如:gz,bz2,xz,它将被解压,但是通过URL获取到的tar文件将不会自动展开
如果有多个或其间接使用了通配符,则必须是一个以/结尾的目录路径,如果不以/结尾,则其被视作一个普通文件
ADD http://example.com/big.tar.xz /usr/src/things/ ADD nickdir.tar.gz .
CMD:启动容器命令或者参数
如果docker run没有指定任何的执行命令或者Dockerfile里也没有ENTRYPOINT,那么启动容器时就会执行CMD指定的默认命令
每个Dockerfile只能有一条CMD命令。如果指定了多条,只有最后一条被执行
如果用户启动容器时用docker run 指定运行命令,则会覆盖CMD指定的命令
CMD语法
#exec形式 ENTRYPOINT [ "executable" , "param1", "param2" ] #shell形式 ENTRYPOINT command param1 param2
ENTRYPOINT:功能类似于CMD,配置容器启动后执行的命令及参数
ENTRYPOINT不能被docker run提供的参数覆盖,而是追加,即如果docker run命令有参数,那么参数全部都会作为ENTTRYPOINT的参数
如果docker run后面没有额外参数,但是Dockerfile中的CMD里有,即Dockerfile中即有CMD也有ENTRYPOINT,那么CMD全部内容作为ENTRYPOINT的参数
如果docker run后面有额外的参数,同时Dockerfile中既有CMD也有ENTRYPOINT,那么docker run后面的参数覆盖掉CMD参数内容,最终作为ENTRYPOINT的参数
可以通过docker run --entrypoint 指令覆盖dockerfile里指定的ENTRYPOINT,如
docker run -it --entrypoint /srv/java/jdk/bin/java -jar /tmp/sms.jar
每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效
ENTRYPOINT语法
#exec形式 ENTRYPOINT [ "executable" , "param1", "param2" ] ENTRYPOINT ["java","-jar","app.jar"] #shell形式 ENTRYPOINT command param1 param2
ARG:构建参数,在build阶段指定变量和ENV不同的是,容器运行时不会存在这些环境变量
VOLUME:匿名卷
将容器中指定的目录挂载到宿主机上,宿主机目录不可指定,会自动生成。docker run -v 参数指定的容器目录与宿主机目录的具体路径都可以指定
VOLUME ["/data1","/data2"]
EXPOSE:暴露端口,指定服务端的容器需要对外暴露的端口号,以实现容器与外部通信
- 这个参数用处不大,不指定也行,在docker run时使用-p 指定端口就可以了,EXPOSE的主要用处就是对于以后交接的运维人员进行端口提示
WORKDIE:指定工作目录,为后续的RUN、CMD、ENTRYPOINT指定工作目录,当容器运行后,进入容器内WORKDIR指定的默认目录,当该目录不存在时会自动创建
WORKDIR /path/to/workdir
USER:指定当前用户,dockerfile后续的RUN CMD ENTRYPOINT都将使用该用户,指定的用户需要在当前系统已经存在
USER <user>[:<group>] 或 USER <UID>[:<GID>]
SHELL:可以指定 RUN、ENTRYPOINT、CMD 指令的 shell,Linux 中默认为 ["/bin/sh", “-c”]
SHELL ["/bin/sh", "-c"]
CDM和ENTRYPOINT的shell和exec模式
CMD 和 ENTRYPOINT 指令都支持 exec 模式和 shell 模式的写法,所以要理解 CMD 和 ENTRYPOINT 指令的用法,就得先区分 exec 模式和 shell 模式。这两种模式主要用来指定容器中的不同进程为 1 号进程。
exec模式
使用 exec 模式时,容器中的任务进程就是容器内的 1 号进程,exec 模式的特点是不会通过 shell 执行相关的命令,所以像 $HOME 这样的环境变量是取不到的:
FROM ubuntu CMD [ "top" ]
shell模式
使用 shell 模式时,docker 会以 /bin/sh -c “task command” 的方式执行任务命令。也就是说容器中的 1 号进程不是任务进程而是 bash 进程
FROM ubuntu CMD top
dockerfile使用exec模式的重要性
- 信号是一种进程间通信的形式。一个信号就是内核发送给进程的一个消息,告诉进程发生了某种事件。当一个信号被发送给一个进程后,进程会立即中断当前的执行流并开始执行信号的处理程序(这么说不太准确,信号是在特定的时机被处理)。如果没有为这个信号指定处理程序,就执行默认的处理程序。
- 进程需要为自己感兴趣的信号注册处理程序,比如为了能让程序优雅的退出(接到退出的请求后能够对资源进行清理)一般程序都会处理 SIGTERM 信号。与 SIGTERM 信号不同,SIGKILL 信号会粗暴的结束一个进程。因此我们的应用应该实现这样的目录:捕获并处理 SIGTERM 信号,从而优雅的退出程序。如果我们失败了,用户就只能通过 SIGKILL 信号这一终极手段了。除了 SIGTERM 和 SIGKILL ,还有像 SIGUSR1 这样的专门支持用户自定义行为的信号。
- Docker 的 stop 和 kill 命令都是用来向容器发送信号的。注意,只有容器中的 1 号进程能够收到信号,这一点非常关键!docker stop 命令会首先发送 SIGTERM 信号,并等待容器优雅的结束。如果发现容器没有结束(用户可以指定等待的时间),就再发送一个 SIGKILL 信号强行结束容器。
- 在dockerfile的ENTRYPOINT下的exec模式时,exec的命令就是容器中的一号进程,外部发给容器的信号是可以被命令收到的。但是如果使用ENTRYPOINT的shell模式,则命令不是容器中的1 号进程,则外部发送的信号命令收不到,而是实行命令的bash收到了,bash收到信号后如果没有相应的处理,则docker stop就会发送kill -9 粗暴的结束进程
docker build
docker build . 在当前目录进行构建
https://www.cnblogs.com/sparkdev/p/8461576.html
- 点赞
- 收藏
- 关注作者
评论(0)