GitHub Page:https://blog.cloudli.top/posts/Dockerfile-指令详解/

FROM

FROM 命令指定基础镜像。在构建镜像时,基础镜像必须指定,因此在 Dockerfile 中 FROM 是必备指令且必须是第一条指令。

在 Docker Hub 上有很多常用的高质量官方镜像,有一些是应用和服务类的镜像,如 nginx、mysql、redis 等;也有一些是用于运行各种语言应用的镜像,如 openjdk、python、node 等。

如果找不到应用的官方镜像,可以基于操作系统镜像构建一个。Docker Hub 上提供了很多操作系统镜像。

FROM ubuntu
...

RUN

RUN 指令是用来执行命令行命令的。RUN 指令的格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入命令一样。

    RUN java -jar app.jar
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"]。

    RUN ["java", "-jar", "app.jar"]

在 Dockerfile 中,每一个指令都会在镜像上建立一层,所以对于多个命令行,不要写多个 RUN 指令。

对于多个命令,可以使用这样的写法:

FROM ubuntu

RUN apt-get update \
&& apt-get install -y redis

对于多个命令,使用 && 连接起来,只用一个 RUN 指令执行,这样就只会构建一层。

COPY

COPY 指令用来将宿主的文件目录复制到镜像中。有两种格式:

  • COPY [--chown=<user>:<group>] <源路径>... <目标路径>

    COPY app.jar /usr/src/
  • COPY [--chown=<user>:<group>] ["源路径1", ... "目标路径"]

    COPY ["app.jar", "config.yml", "/usr/src"]

对于多个路径参数,最后一个为目标路径,其他都是源路径。目标路径 可以是绝对路径,也可以是相对于工作目录的路径(工作目录可以用 WORKDIR 来指定)。目标路径如果不存在,在复制文件前会先创建。

CMD

CMD 是容器启动命令,它指定了容器启动后要执行的程序。与 RUN 指令相似有两种形式:

  • shell 格式:CMD <命令>

    CMD echo 'Hello, world!''
  • exec 格式:CMD ["可执行文件", "参数1", "参数2", ...]

    CMD [ "sh", "-c", "echo 'Hello, world!'" ]

还有一种参数列表格式:CMD ["参数1", "参数2", ...]。在指定了 ENTRYPOINT 指令后,可以用 CMD 指定参数。

在使用 CMD 时,程序必须以前台运行,Docker 不是虚拟机,容器没有后台服务的概念。如果使用 CMD 运行一个后台程序,那么容器在命令执行完就会退出。

CMD java -jar app.jar &

以上命令让 app.jar 在后台运行,容器启动后就会立刻退出。Docker 容器与守护线程很相似,当所有前台程序退出后,容器就会退出。

CMD 指定的命令可以在运行时替换,跟在镜像名称后面的参数将替换镜像中的 CMD。

docker run app echo $HOME

以上命令运行容器时使用 echo $HOME 替换掉镜像中的启动命令。

ENTRYPOINT

ENTRYPOINT 的格式与 CMD 一样有两种格式。

它和 CMD 一样都是指定容器启动的程序和参数,但稍有区别。当指定了 ENTRYPOINT 后,CMD 的内容将作为参数加到 ENTRYPOINT 后面。

也就是变成了:

<ENTRYPOINT> "<CMD>"

ENTRYPOINT 可以让镜像像命令一样使用,当仅仅使用 CMD 时,run 命令中镜像名后面的参数会替换 CMD 的内容。使用 ENTRYPOINT 后,这些参数将附加到原来命令的后面。

FROM alpine
ENTRYPOINT [ "ls" ]

使用以上 Dockerfile 构建的镜像运行容器:

docker run app -al

-al 参数将附加到 ENTRYPOINT 指定的命令后面,当容器启动时执行的是 ls -al。

ENV

ENV 指令用来设置环境变量,格式有两种:

  • ENV <key> <value
  • ENV <key1>=<value1> <key2>=<value2>

环境变量在后面的其它指令中可以通过 $key 来使用:

FROM ubuntu
ENV VERSION="8-jre" RUN apt-get update \
&& apt-get install -y openjdk-$VERSION
...

ARG

ARG 指令指定构建参数,与 ENV 效果一样,都是设置环境变量。不同的是,ARG 设置的构建参数,在容器运行时不存在。

格式:ARG <key>[=<默认值>],可以指定默认值,也可以不指定。

FROM alpine
ARG NAME="Hello, Docker!" RUN echo $NAME
CMD echo $NAME

对于以上 Dockerfile,在构建时可以看到输出,但是在运行容器时没有输出。

ARG 设置的参数可以在构建命令中指定:docker build --build-arg <key>=<value>。

VOLUME

VOLUME 指令用来定义匿名卷。

  • VOLUME <路径>
  • VOLUME ["路径1", "路径2", ...]

对于数据库类需要保持数据的应用,其文件应该保存于卷(volume)中,在 Dockerfile 中,可以事先将指定的目录挂载为匿名卷。

VOLUME /data

这里 /data 目录在容器运行时自动挂载为匿名卷,任何写入 /data 中的数据都不会记录到容器的存储层。在运行时可以覆盖这个挂载设置:

docker run -v dbdir:/data

以上命令将 dbdir 目录挂载到了 /data,替换了 Dockerfile 中的挂载配置。

EXPOSE

EXPOSE 指令指定容器运行时暴露的端口。格式:EXPOSE <端口1> [<端口2> ...]。

FROM ubuntu
EXPOSE 8080 RUN apt-get update \
&& apt-get install -y tomcat8
...

以上 Dockerfile 安装了 tomcat 应用,在运行容器时会暴露 8080 端口。

EXPOSE 只是指定了容器暴露的端口,并不会在宿主机进行端口映射。在使用 docker run -P 时,会自动随机映射 EXPOSE 指定的端口,也可以使用 -p 指定端口:docker run -p <宿主端口>:<容器端口>。

WORKDIR

WORKDIR 指令指定工作目录,即指定当前目录,类似于 cd 命令,以后各层的当前目录都是 WORKDIR 指定的目录。如果目录不存在,会自动创建。格式:WORKDIR <目录路径>。

不能把 Dockerfile 当成 Shell 脚本来写:

RUN cd /src/app
RUN java -jar app.jar

以上操作中第二行的工作目录并不是 /src/app,两个指令不在同一层,第一个 RUN 指令的 cd 操作和第二个没有任何关系。因此要切换目录,应该使用 WORKDIR 来指定。

USER

USER 指令指定当前用户。与 WORKDIR 相似,会影响以后的层。USER 改变执行 RUN、CMD 和 ENTRYPOINT 的用户。格式:USER <用户名>[:<用户组>]。

USER 指定的用户和组必须是事先创建好的,否则无法切换。

# 添加用户
RUN groupadd -r redis \
&& useradd -r -g redis redis
USER redis
ENTRYPOINT ["reids-server"]

ONBUILD

ONBUILD 指令后面跟的是其它指令,它在当前镜像构建时不会被执行,只有以当前镜像为基础镜像去构建下一级镜像时才会被执行。格式:ONBUILD <其它指令>。

FROM openjdk:8-jre-alpine
WORKDIR /app
ONBUILD COPY ./app.jar /app
...

这个 Dockerfile 在构建时不会执行 ONBUILD。

FROM my-jre
...

假设之前构建的镜像名是 my-jre,以上 Dockerfile 构建镜像时,原来的 ONBUILD 将执行。

Dockerfile 指令详解的更多相关文章

  1. Dockerfile指令详解

    Dockerfile中包括FROM.MAINTAINER.RUN.CMD.EXPOSE.ENV.ADD.COPY.ENTRYPOINT.VOLUME.USER.WORKDIR.ONBUILD等13个指 ...

  2. Dockerfile指令详解下

    VOLUME 定义匿名卷 VOLUME指令的格式为: VOLUME [,...] VOLUME 之前我们说过,容器运行时应该尽量保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,其数据库 ...

  3. Dockerfile指令详解上

    COPY复制文件指令 和RUN命令一样,COPY命令也有两种格式,一种类似与命令行,一种类似与函数调用,命令格式如下: COPY ... COPY ["",...] COPY将构建 ...

  4. 3 Dockerfile指令详解-FROM&MAINTAINER&RUN

    1.FROM指令 FROM centos #指定centos为基础镜像 2.MAINTAINER 指令 MAINTAINER @QQ.COM #指定维护人等信息,方便维护 3.RUN  命令  #新建 ...

  5. Docker Dockerfile 指令详解与实战案例

    Dockerfile介绍及常用指令,包括FROM,RUN,还提及了 COPY,ADD,EXPOSE,WORKDIR等,其实 Dockerfile 功能很强大,它提供了十多个指令. Dockerfile ...

  6. Dockerfile指令详解--VOLUME 指令

    Alpine Linux是一个轻型Linux发行版,它不同于通常的Linux发行版,Alpine采用了musl libc 和 BusyBox以减少系统的体积和运行时的资源消耗.Alpine Linux ...

  7. 7 Dockerfile指令详解 && VOLUME 指令

    格式为: VOLUME ["<路径1>", "<路径2>"...] VOLUME <路径> 之前我们说过,容器运行时应该尽量 ...

  8. 6 Dockerfile指令详解 && ENTRYPOINT 指令

    ENTRYPOINT 的格式和 RUN 指令格式一样,分为 exec 格式和 shell 格式. ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数. ENTRYPOINT 在 ...

  9. 5 Dockerfile指令详解 && CMD 指令

    CMD 指令的格式和 RUN 相似,也是两种格式: shell 格式: CMD <命令> exec 格式: CMD ["可执行文件", "参数1", ...

随机推荐

  1. 2019-2020-1 20199303 《Linux内核原理分析》 第一周作业

    2019-2020-1 20199303 <Linux内核原理分析> 第一周作业 1. 环境准备 在众多的Linux发行版中,Ubuntu,小红帽还有类Unix系统的BSD系统,我选择了目 ...

  2. ZK集群如何保证数据一致性源码阅读

    什么是数据一致性? 只有当服务端的ZK存在多台时,才会出现数据一致性的问题, 服务端存在多台服务器,他们被划分成了不同的角色,只有一台Leader,多台Follower和多台Observer, 他们中 ...

  3. yii中缓存(cache)详解 - 彼岸あ年華ツ

    缓存是用于提升网站性能的一种即简单又有效的途径.通过存储相对静态的数据至缓存以备所需,我们可以省去生成 这些数据的时间.在 Yii 中使用缓存主要包括配置和访问缓存组件 . 内部方法 一.缓存配置: ...

  4. NAT网络下tcp_tw_recycle参数引起的故障

    记录一次阿里云服务器故障排查思路 公司网络是nat 环境 问题: 同一个服务有两台服务器 172.19.19.252 172.19.19.187 两台服务器 要连node5 发现172.19.19.2 ...

  5. kotlin -- 可见性修饰符

    puiblic Kotlin的可见修饰符与Java类似,但是默认可见性不同,Java默认包私有,kotlin默认public ### internal internal 只在模块内部可见.一个模块就是 ...

  6. Java 学习笔记之 Stop停止线程

    Stop停止线程: 使用stop()方法停止线程是非常暴力的,会抛出java.lang.ThreadDeath Error,但是我们无需显示捕捉, 以下捕捉只是为了看得更清晰. public clas ...

  7. IDEA 学习笔记之 Java项目开发深入学习(1)

    Java项目开发深入学习(1): 定义编译输出路径: 继承以上工程配置 重新定义新的项目编译路径 添加source目录:点击添加,再点击移除: 编译项目: 常用快捷键总结: Ctrl+Space 代码 ...

  8. RRiBbit,一个事件总线.基于spring配置不同服务通信!

    1.何为RRiBbit? *一种开源事件总线技术,能够让模块(组件)之间双向通讯,也被称为请求相应总线(request-response-bus),使用简单,相对其他框架来说,RRiBbit只需要加个 ...

  9. JavaScript ES6函数式编程(一):闭包与高阶函数

    函数式编程的历史 函数的第一原则是要小,第二原则则是要更小 -- ROBERT C. MARTIN 解释一下上面那句话,就是我们常说的一个函数只做一件事,比如:将字符串首字母和尾字母都改成大写,我们此 ...

  10. 构造函数语义学——Default Constructor篇

    构造函数语义学--Default Constructor 篇 这一章原书主要分析了:编译器关于对象构造过程的干涉,即在对象构造这个过程中,编译器到底在背后做了什么 这一章的重点在于 default c ...