Dockerfile指令用法

网友投稿 230 2022-10-23

Dockerfile指令用法

切记:docker file 需要有一个工作目录 文件名开头要大写,所有需要用到的目录必须在这个目录或者子目录里面。如果目录里面有不需要打包进镜像里需要在“.dockeringore”文件中把文件名写进去

FROM

FROM指令是最重要的且必须为Dockerfile文件的开篇第一个非注释行,用于为镜像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境实践中,基准镜像可以是任何可用的镜像文件,默认情况下,docker build 会在docker主机上查找指定的镜像文件,在其不存在时,则会从docker hub registry上拉取所需的镜像文件

语法:

FROM [:]或FROM @

:指定作为base image的名称:base iamge的标签,为可选项,省略时默认为latest;

MAINTAINER 指定作者邮箱信息

用于让Dockerfile制作者提供本人的详细信息Dockerfile并不限制MAINTAINER指令可在出现的位置,单推荐将其放在FROM指令之后

语法:

MAINTAINER 可是任何文本信息,但约定要俗成地使用作者名称及邮件地址示例:MAINTAINER "liliang "

COPY

用于从Docker主机复制文件至创建的新镜像文件

语法:

COPY ...COPY ["src" ...""]

:要复制的源文件或目录,支持使用通配符:目标路径,即正在创建的image的文件的系统路径;建议为使用绝对路径,否则COPY指定则以WORKDIR为起始路径**

注意:在路径中有空白字符时,通常用第二种格式

文件复制准则

必须是build上下文中的路径,不能是父目录中的文件ro如果目录,则其内部的文件或子目录会被递归复制,但目录自身不会被复制如果制定了,活在中使用了通配符,则必须是目录,且必须以/结尾如果事先不存在,他将会被自动创建,这其中包含其父目录路径

ADD

ADD指令类似COPY指令,ADD支持使用TAR和URL路径

语法:

ADD ... 或ADD [" ... "]

操作准则

同COPY指令如果为URL且不以/结尾,则指定的文件将被下载并直接创建为;如果以/极为,则文件名URL指定的文件将直接被下载并保存到/如果是一个本地系统上的压缩格式的tar文件,他将直接被展开为目录,其行为类似于“tar -x”命令;然而,通过URL获取到的tar文件将不会自动展开;如果有多个,或者间接或直接使用了通配符,则必须是一个已/结尾的目录路径;如果不以/结尾将被视作为普通文件,的内容将被直接写入到文件中

WORKDIR

用于为Dockerfile中所有的RUN,CMD,ENTRYPOINT,COPY和ADD指定设定工作目录

语法:

WORKDIR

在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可为相对路径,不过,其相对路径是对此前一个WORKDIR指令的相对路径另外,WORKDIR也可以调用由ENV定义的变量

示例:

WORKDIR /var/usr/localWORKDIR $PATH

VOLUME

用于在image中创建一个挂在点目录,以Docker host上的卷或其它容器的卷

语法:

VOLUME VOLUME ["

EXPOSE 定义容器暴露的默认端口

用于为容器打开指定要监听的端口已实现与外部通讯

语法:

EXPOSE |[/] [/]EXPOSE 可一次指定多个端口,例如: EXPOSE 80/tcp 80/udp

注意:要真正让外部能访问到容器,需要在docker run 时加上-P选项

ENV

用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的指令(如ENV、ADD、COPY等)所调用调用格式为$variable_name或者${variable_name}

语法

ENV 或ENV = ...

第一种格式中,之后的所有内容均会被视作其其组成部分,因此,一次只能设置一个变量;第二种格式,可一次设置多个变量,每一个变量为一个“=”的键值对,如果中包含多个空格,可以以反斜线(\)进行转义,也可通过对加引号进行标示;另外反斜线也可以用与续行;定义多个变量建议使用第二种格式,以便在同一层完成所有功能。

RUN

用于指定docker bulid过程中运行的程序,其可以是任何命令

语法

RUN RUN ["executable", "param1", "param2"]

第一种格式中通常是一个shel命令,且以/bin/sh -c 来运行它,这意味着此进程在容器中pid不为1,不能接收Unix信号,因此使用docker stop 命令停止容器时,此进程接受不到SIGTERM信号第二种语法格式中的参数是一个JSON格式的数组,其中 为要运行的命令,后面的为传递给命令的选项和参数,然而,此格式指定的命令不会以/bin/sh -c来运行,因此常见的shell操作如变量替换以及通配符(*.)等将不会运行,不过,要运行的命令依赖shell特性的话,可以将其替换为下面的格式;

RUN ["/bin/sh","-c","exexcutable","param1","param2",....]

CMD 容器启动命令

类似于RUN指令,CMD也可以运行任何命令或应用程序,不过二者运行时间点不同 RUN指令运行在docker bulid构建为镜像文件的过程中,而CMD指令运行在基于Dockerfile构建出的镜像文件启动为为容器的过程中CMD指令的首要目的在于为启动容器指定默认要运行的程序,且其运行结束后容器也将终止,不过,CMD指令其可以被docker run时命令行选项所覆盖 CMD指令可以存在多个,但只有最后一个生效!

语法

CMD 或CMD ["executable","param1","param2",...]CMD ["param1","param2",...]

前两种的意义都与RUN相同第三种语法则用于ENTRYPOINT指令提供默认参数

ENTRYPOINT

类似于CMD指令的功能,用于为容器指定默认运行层序,从而使得容器像一个单独可执行的程序,与CMD不同的是,有ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令还会被当做参数传递给ENTRYPOINT指定的程序 不过,docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序

语法

ENTRYPOINT ENTRYPOINT ["","param1","param2",...]

docker run 命令传入的命令参数会覆盖CMD指令的内容并附加到ENTRYPOINT命令最后作为其参数使用 Dockerfile文件中也可存在多个ENTRYPIONT指令,但仅有最后一个会生效

示例:利用entrypoint.sh脚本初始化nginx环境,可在docker run 通过-e选项对entyypoint.sh脚本传值

# dockerfile工作目录准备的文件[root@node01 NG_Dockerfile]# ls Dockerfile entrypoint.sh(+执行权限) index.html# entrypoint.sh文件,"注意要加执行权限"[root@node01 NG_Dockerfile]# cat entrypoint.sh #!/bin/sh#cat > /etc/nginx/conf.d/conf <welcome to Nginx Server.#Dockerfile文件[root@node01 NG_Dockerfile]# cat Dockerfile FROM nginx:1.14-alpine 指定bese image MAINTAINER "liliang liyueliang@chinatelecom.cn" 指定作者 ENV WEB_ROOT="/opt/ 设置变量名WEB_ROOT,其中为"/opt/COPY index.html ${WEB_ROOT} 复制index.html文件到/opt/ COPY entrypoint.sh /bin/ 复制上面写好的且有执行权限的"entrypoint.sh"脚本到"/bin"目录下 #EXPOSE 80/tcp 定义容器暴露80/tcp端口 CMD ["/usr/sbin/nginx","-g","daemon off;"] 定义容器默认运行的程序 ENTRYPOINT ["/bin/entrypoint.sh"] 这里的作用就是先运行"/bin/entrypoint.sh"脚本,然后在运行CMD指定的程序。

USER 指定当前用户

用于指定运行image时的或运行Dockerfile中任何RUN、CMD、或ENTRYPOINT指令指定的程序时的用户名或UID默认情况下,container的运行身份为root用户

语法:

USER |

需要注意的是,可以是任意数字,但实践中必须为/etc/passwd中某用户的有效UID,否则,docker run 命令将会运行失败

HEALTHCHECK 健康检查

"语法"

HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。在没有 HEALTHCHECK 指令前,Docker 引擎只可以通过容器内主进程是否退出来判断容器是否状态异常。很多情况下这没问题,但是如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了。在 1.12 以前,Docker 不会检测到容器的这种状态,从而不会重新调度,导致可能会有部分容器已经无法提供服务了却还在接受用户请求。而自 1.12 之后,Docker 提供了 HEALTHCHECK 指令,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting,在 HEALTHCHECK 指令检查成功后变为 healthy,如果连续一定次数失败,则会变为 unhealthy。

HEALTHCHECK 支持下列选项:

--interval=<间隔>:两次健康检查的间隔,默认为 30 秒;--timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;--retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。 和 CMD, ENTRYPOINT 一样,HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效。 在 HEALTHCHECK [选项] CMD 后面的命令,格式和 ENTRYPOINT 一样,分为 shell 格式,和 exec 格式。命令的返回值决定了该次健康检查的成功与否:0:成功;1:失败;2:保留,不要使用这个值。假设我们有个镜像是个最简单的 Web 服务,我们希望增加健康检查来判断其 Web 服务是否在正常工作,我们可以用 curl 来帮助判断,其 Dockerfile 的 HEALTHCHECK 可以这么写:

FROM nginxRUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*HEALTHCHECK --interval=5s --timeout=3s \ CMD curl -fs || exit 1

这里我们设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 3 秒没响应就视为失败,并且使用 curl -fs ​​exit 1 作为健康检查命令。

使用 docker build 来构建这个镜像:

$ docker build -t myweb:v1 .

构建好了后,我们启动一个容器:

$ docker run -d --name web -p 80:80 myweb:v1

当运行该镜像后,可以通过 docker container ls 看到最初的状态为 (health: starting):

$ docker container lsCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES03e28eb00bd0 myweb:v1 "nginx -g 'daemon off" 3 seconds ago Up 2 seconds (health: starting) 80/tcp, 443/tcp web

在等待几秒钟后,再次 docker container ls,就会看到健康状态变化为了 (healthy):

$ docker container lsCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES03e28eb00bd0 myweb:v1 "nginx -g 'daemon off" 18 seconds ago Up 16 seconds (healthy) 80/tcp, 443/tcp web

如果健康检查连续失败超过了重试次数,状态就会变为 (unhealthy)。

为了帮助排障,健康检查命令的输出(包括 stdout 以及 stderr)都会被存储于健康状态里,可以用 docker inspect 来查看。

$ docker inspect --format '{{json .State.Health}}' web | python -m json.tool{ "FailingStreak": 0, "Log": [ { "End": "2016-11-25T14:35:37.940957051Z", "ExitCode": 0, "Output": "\n\n\nWelcome to nginx! \n\n\n\n

Welcome to nginx!

\n

If you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.

\n\n

For online documentation and support please refer to\n

\n\n\n", "Start": "2016-11-25T14:35:37.780192565Z" } ], "Status": "healthy"}

ARG

语法

ARG <参数名>[=<默认值>]

构建参数和 ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。在 1.13 之前的版本,要求 --build-arg 中的参数名,必须在 Dockerfile 中用 ARG 定义过了,换句话说,就是 --build-arg 指定的参数,必须在 Dockerfile 中使用了。如果对应参数没有被使用,则会报错退出构建。从 1.13 开始,这种严格的限制被放开,不再报错退出,而是显示警告信息,并继续构建。这对于使用 CI 系统,用同样的构建流程构建不同的 Dockerfile 的时候比较有帮助,避免构建命令必须根据每个 Dockerfile 的内容修改。

ONBUILD 为他人做嫁衣裳

语法

格式:ONBUILD <其它指令>。

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的。假设我们要制作 Node.js 所写的应用的镜像。我们都知道 Node.js 使用 npm 进行包管理,所有依赖、配置、启动信息等会放到 package.json 文件里。在拿到程序代码后,需要先进行 npm install 才可以获得所有需要的依赖。然后就可以通过 npm start 来启动应用。因此,一般来说会这样写 Dockerfile:

FROM node:slimRUN mkdir /appWORKDIR /appCOPY ./package.json /appRUN [ "npm", "install" ]COPY . /app/CMD [ "npm", "start" ]

把这个 Dockerfile 放到 Node.js 项目的根目录,构建好镜像后,就可以直接拿来启动容器运行。但是如果我们还有第二个 Node.js 项目也差不多呢?好吧,那就再把这个 Dockerfile 复制到第二个项目里。那如果有第三个项目呢?再复制么?文件的副本越多,版本控制就越困难,让我们继续看这样的场景维护的问题。

如果第一个 Node.js 项目在开发过程中,发现这个 Dockerfile 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 Dockerfile,再次构建,问题解决。第一个项目没问题了,但是第二个项目呢?虽然最初 Dockerfile 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 Dockerfile,而第二个项目的 Dockerfile 就会被自动修复。

那么我们可不可以做一个基础镜像,然后各个项目使用这个基础镜像呢?这样基础镜像更新,各个项目不用同步 Dockerfile 的变化,重新构建后就继承了基础镜像的更新?好吧,可以,让我们看看这样的结果。那么上面的这个 Dockerfile 就会变为:

FROM node:slimRUN mkdir /appWORKDIR /appCMD [ "npm", "start" ]

这里我们把项目相关的构建指令拿出来,放到子项目里去。假设这个基础镜像的名字为 my-node 的话,各个项目内的自己的 Dockerfile 就变为:

FROM my-nodeCOPY ./package.json /appRUN [ "npm", "install" ]COPY . /app/

基础镜像变化后,各个项目都用这个 Dockerfile 重新构建镜像,会继承基础镜像的更新。

那么,问题解决了么?没有。准确说,只解决了一半。如果这个 Dockerfile 里面有些东西需要调整呢?比如 npm install 都需要加一些参数,那怎么办?这一行 RUN 是不可能放入基础镜像的,因为涉及到了当前项目的 ./package.json,难道又要一个个修改么?所以说,这样制作基础镜像,只解决了原来的 Dockerfile 的前4条指令的变化问题,而后面三条指令的变化则完全没办法处理。

ONBUILD 可以解决这个问题。让我们用 ONBUILD 重新写一下基础镜像的 Dockerfile:

FROM node:slimRUN mkdir /appWORKDIR /appONBUILD COPY ./package.json /appONBUILD RUN [ "npm", "install" ]ONBUILD COPY . /app/CMD [ "npm", "start" ]

这次我们回到原始的 Dockerfile,但是这次将项目相关的指令加上 ONBUILD,这样在构建基础镜像的时候,这三行并不会被执行。然后各个项目的 Dockerfile 就变成了简单地:

FROM my-node

是的,只有这么一行。当在各个项目目录中,用这个只有一行的 Dockerfile 构建镜像时,之前基础镜像的那三行 ONBUILD 就会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 npm install,生成应用镜像。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:分布式系统下调用链追踪技术面试题
下一篇:谷歌云平台正式发布API管理平台
相关文章

 发表评论

暂时没有评论,来抢沙发吧~