VOLUME指令的格式为:nginx
以前咱们说过,容器运行时应该尽可能保持容器存储层不发生写操做,对于数据库类须要保存动态数据的应用,其数据库文件应该保存于卷(volume)中。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在Dockerfile 中,咱们能够事先指定某些目录挂载为匿名卷,这样在运行时若是用户不指定挂载,其应用也能够正常运行,不会向容器存储层写入大量数据.git
VOLUMN /data
这里的 /data 目录就会在运行时自动挂载为匿名卷,任何向 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。固然,运行时能够覆盖这个挂载设置。好比:github
docker run -d -v mydata:/data xxxx
在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了Dockerfile 中定义的匿名卷的挂载配置web
格式为 EXPOSE <端口1> [ <端口2> ...] 。 redis
EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会由于这个声
明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另外一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端。docker
要将 EXPOSE 和在运行时使用 -p <宿主端口> : <容器端口> 区分开来。 -p ,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。 shell
格式为 WORKDIR <工做目录路径> 数据库
使用 WORKDIR 指令能够来指定工做目录(或者称为当前目录),之后各层的当前目录就被改
为指定的目录,如该目录不存在, WORKDIR 会帮你创建目录。app
下面的写法把Dockerfile按照Shell脚原本写,可能致使下面的错误curl
RUN cd /app RUN echo "hello" > world.txt
若是将这个 Dockerfile 进行构建镜像运行后,会发现找不到 /app/world.txt 文件,或者其内容不是 hello 。缘由其实很简单,在 Shell 中,连续两行是同一个进程执行环境,所以前一个命令修改的内存状态,会直接影响后一个命令;而在 Dockerfile 中,这两行 RUN 命令的执行环境根本不一样,是两个彻底不一样的容器。这就是对 Dockerfile 构建分层存储的概念不了解所致使的错误。以前说过每个 RUN 都是启动一个容器、执行命令、而后提交存储层文件变动。第一层 RUN cd /app 的执行仅仅是当前进程的工做目录变动,一个内存上的变化而已,其结果不会形成任何文件变动。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更彻底不要紧,天然不可能继承前一层构建过程当中的内存变化。
所以若是须要改变之后各层的工做目录的位置,那么应该使用 WORKDIR 指令。
格式: USER <用户名>
USER 指令和 WORKDIR 类似,都是改变环境状态并影响之后的层。 WORKDIR 是改变工做目录, USER 则是改变以后层的执行 RUN , CMD 以及 ENTRYPOINT 这类命令的身份。
固然,和 WORKDIR 同样, USER 只是帮助你切换到指定用户而已,这个用户必须是事先创建
好的,不然没法切换。
若是以 root 执行的脚本,在执行期间但愿改变身份,好比但愿以某个已经创建好的用户来运行某个服务进程,不要使用 su 或者 sudo ,这些都须要比较麻烦的配置,并且在 TTY 缺失的环境下常常出错。建议使用 gosu
# 创建 redis 用户,并使用 gosu 换另外一个用户执行命令 RUN groupadd -r redis && useradd -r -g redis redis # 下载 gosu RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/ gosu-amd64" \ && chmod +x /usr/local/bin/gosu \ && gosu nobody true # 设置 CMD,并以另外的用户执行 CMD [ "exec", "gosu", "redis", "redis-server" ]
HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12
引入的新指,经过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。格式:
当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting ,在HEALTHCHECK 指令检查成功后变为 healthy ,若是连续必定次数失败,则会变为unhealthy
HEALTHCHECK 支持下列选项:
和 CMD , ENTRYPOINT 同样, HEALTHCHECK 只能够出现一次,若是写了多个,只有最后一个生效。
在 HEALTHCHECK [选项] CMD 后面的命令,格式和 ENTRYPOINT 同样,分为 shell 格式,和exec 格式。命令的返回值决定了该次健康检查的成功与否: 0 :成功; 1 :失败; 2 :保留,不要使用这个值。
假设咱们有个镜像是个最简单的 Web 服务,咱们但愿增长健康检查来判断其 Web 服务是否在正常工做,咱们能够用 curl 来帮助判断,其 Dockerfile 的 HEALTHCHECK 能够这么写:
FROM nginx RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* HEALTHCHECK --interval=5s --timeout=3s \ CMD curl -fs http://localhost/ || exit 1
这里咱们设置了每 5 秒检查一次(这里为了试验因此间隔很是短,实际应该相对较长),若是健康检查命令超过 3 秒没响应就视为失败,而且使用 curl -fs http://localhost/ || exit1 做为健康检查命令。
使用 docker build 来构建这个镜像:
docker build -t myweb:v1 .
构建好了后,咱们启动一个容器:
docker run -d --name web -p 80:80 myweb:v1
当运行该镜像后,能够经过 docker ps 看到最初的状态为 (health: starting) ,在等待几秒钟后,再次 docker ps ,就会看到健康状态变化为了 (healthy) 。若是健康检查连续失败超过了重试次数,状态就会变为 (unhealthy)。
为了帮助排障,健康检查命令的输出(包括 stdout 以及 stderr )都会被存储于健康状态里,能够用 docker inspect 来查看
格式: ONBUILD <其它指令>
ONBUILD 是一个特殊的指令,它后面跟的是其它指令,好比 RUN , COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。Dockerfile 中的其它指令都是为了定制当前镜像而准备的,惟有 ONBUILD 是为了帮助别人定制本身而准备的