DockerFile在我理解就是可以将所需要构建镜像的功能、组件都天前配置好,然后直接生成一个Image,而不是先生成镜像,再通过修改容器的方法来生成最终需要的镜像。
  镜像的定值实际上就是定值每一层所需要添加的配置、文件,将每一层修改、安装、构建、操作的命令都写入一个脚本,最后使用脚本来构建镜像。Dockerfile的每一条指令(instruction)构建一层,描述了该层该如何构建。

Dockerfile的构建

docker build [选项] <上下文路径/URL/->

Dockerfile上下文(context)

一般情况下构建镜像docker build 最后都会有一个.,表示当前目录,有些人会认为这是指定Dockerfile的所在路径,但是其实是在指定上下文路径。在构建镜像的时候,docker build得知上下文路径后,会将该路径下所有东西打包,然后上传给Docker 引擎,Docker引擎就回获得构建镜像所需要的一切文件。
  需要访问打包的文件,必须以./开头,并不是指当前路径,而是上下文环境。应该讲Dockerfile置于一个空目录下,或者项目根目录下,如果该上下文环境有不希望传给Docker引擎的,可以使用.gitignore一样的语法写一个.dockerignore来剔除不需要的环境。

其他Docker builc的用法

直接使用Git repo构建

docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14

用给定的tar包构建

docker build build.tar.gz

DockerFile指定

FROM 指定基础镜像

必选,而且是第一条指令,在制定基础镜像。

FROM nginx

有一个特殊的镜像名为scratch,是虚拟的概念,表示一个空白的镜像,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在,使用Go预研开发的应用很多会使用这种方式来制作镜像。

FROM scratch

RUN 执行命令

用于执行命令,相当于命令行,格式有两种:
shell格式:RUN <命令>,相当于在命令行中写命令。
exec格式:RUN["可执行文件","参数1", "参数2"],相当于函数调用中的格式。

RUN echo 'hello world' > /usr/share/nginx/html/index.html

Dockerfile会将每一个命令视为一层,所以一般使用RUN都是结合&&来将多个RUN视为一层,避免产生臃肿、多层的镜像,增加构建时间而且容易出错。

FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps

末尾使用了\的方式,以及行首#进行注释的格式,可以让维护、更为容易。另外,可以在这一组命令最后添加清理工作的命令,删除为了编译固件所需要的软件,并且还清理了qpt缓存文件,可以有效避免镜像臃肿

COPY 复制文件

格式:

COPY <源路径>... <目标路径>
COPY ["<源路径1>",... "<目标路径>"]

与RUN命令类似,有shell以及函数式调用,将从上下文目录中的源路径复制到一个新的镜像内的目标路径。源路径可以是多个,可以使用通配符,需要满足Go语言的filepath Match规则。
  目标路径可以使容器内的绝对路径,也可以是相对路径,目标路径不需要手动创建,Docker会自动创建确实的目录。
  需要注意的是拷贝过去的文件会保留源文件的特性,比如读写权限、文件变更时间等。

ADD 高级的复制文件

ADD可以理解为一个升级版本的COPY,源路径可以是一个URL(下载之后的文件权限为600);如果源路径是一个tar压缩文件、格式为gzip、bzip2以及xz的情况下,ADD指令可以自动解压该文件到目标路径中。所以这个命令一般用于解压文件更多。
  Docker官方建议尽可能使用COPY,因为ADD语音不明确,并且ADD会另镜像构建缓存失效,从而可能另镜像构建的比较缓慢。因此仅在需要自动解压的情况下使用ADD。

CMD 容器启动命令

和RUN相似,但是CMD、ENTERPOINT、HEALTHCHECK只能出现一次,写了多个只会使用最后一个。两种格式:

shell 格式: CMD <命令>
exec 格式: CMD ["可执行文件", "参数1", "参数2"...]
参数列表格式: CMD ["参数1", "参数2"...] 。在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。

我们知道Docker不是虚拟机,而容器就是一个进程而已,那么在启动容器的时候就需要指定容器运行的程序以及参数,CMD指令就是用于指定默认的容器主进程的启动命令的。
  在ubuntu默认CDM是/bin/bash,直接docker run -it会直接进入bash,也可以通过手动docker run -it imageid cat /etc/os-release的方式替换默认CMD,打印系统版本信息。
  一般推荐exec的指令格式,会被解析为JSON数组,一定使用双引号而不是单引号。如果直接使用shell格式的话会被包装为sh -c的参数形式执行

CMD echo $HOME
CMD ["sh","-c","echo $HOME"]

这也就是我们为什么可以使用环境变量的原因,因为这些环境变量会被shell进行解析处理。
  另外Docker不是虚拟机,容器中没有后台执行服务的概念,不能使用upstart/systemd去执行后台服务。比如nginx服务

CMD service nginx start

其实会启动之后就立刻推出,甚至systemctl命令根本无法执行。容器中启动进程就是容器应用进程,容器就是为了主进程而存在的,主进程退出容器也就失去了意义。nginx启动应该为:

CMD ["nginx","-g","daemon off;"]

因为service nginx start会被理解为CMD["sh","-c""service nginxstart"],因此主进程是sh,当service nginx start执行完,sh也就结束了,sh作为主进程推出就会导致容器推出。

ENTERPOINT 入口点

作用和CMD类似,都是在容器启动程序及参数,ENTERPOINT在运行时候也可以替代,但是比CMD要繁琐,需要通过docker run的参数 -entrypoint来指定。当指定了ENTERPOINT之后,CMD就不再是直接的运行命令,而是将CMD的内容作为参数传递给ENTERPOINT指令,相当于:

<ENTERPOINT> "<CMD>"

那么有什么用呢?

让镜像变成命令一样使用

有些情况下构建的镜像我们可以当做一个应用直接使用命令行调用,但是使用CMD的构建是写死的。比如获取公网IP:

FROM ubuntu:16:04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD ["curl","-s","http://ip.cn"]

docker build -t myip .构建镜像之后,只需要执行docker run myip就可以查看当前的公网ip。但是如果我们现在想修改一下使用别的参数,比如希望显示http头信息,需要加上-i参数,那么使用docker run myip -i是一定不可行的。因为跟在镜像名后边的command运行时候会替换CMD默认值,相当于直接执行-i,所以绝对不会成功,这个时候就可以使用ENTERPOINT。

FROM ubuntu:16:04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*

然后直接调用docker run myip -i就可以正常执行,相当于curl -s http://ip.cn -i,CMD的内容会作为参数传递给ENTERPOINT,而这里个-i就是新的CMD,和ENTERPOINT组合成新的CMD。

ENV 环境变量

只是设置环境变量,无论是后边其他的任何命令RUN等都可以直接使用这里的环境变量,使用{ENV_NAME}来引用,格式:

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

比如:

ENV NODE_VERSION =7.2.0 DEBUG=on \
NAME="lzy"
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz"

以下的指令支持环境变啦ing的展开:
ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBUILD
  通过环境变量,我们可以让一份Dockerfile制作更多的镜像,只需要使用不同的环境变量即可。

ARG 构建参数

与ENV想类似,设置环境变量,但是ARG的环境变量在最终声称的容器中不会存在,但是不存在不意味着可以保存密码之类的东西,因为在docker history中也会看到。该值所设置的环境变量可以在docker build时候shiyong --build-arg <参数名>=<值>来覆盖。格式:

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

VOLUME定义匿名卷

如果在容器中进行数据输出,那么最终数据不会被保存,对于需要动态保存数据的应用,应该保存与卷volume中,为了避免用户忘记动态文件所保存目录挂载为卷,可以实现指定默写目录挂载为匿名卷,如果用户不指定挂载,应用也可以正常运行,不会向容器存储层写入大量数据。格式为:

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
#比如
COLUME /data

上述的/data就会在运行时候自动挂载为匿名卷,运行时也可以覆盖这个挂载设置

docker run -d -v mydata:/data xxxx

上述就是使用了mydata目录来挂载到了/data位置,替代了Dockerfile中匿名卷的挂载配置。

EXPOSE 声明端口

生命运行时候容器提供服务端口,只是一个生命,在运行时候不会因为这个生命就会开启这个端口。主要作用是帮助镜像使用者理解这个镜像服务的守护端口,方便配置映射。另外就是使用随机端口映射时候docker run -P可以自动随机映射expose的端口。格式为:

EXPOSE <端口1> [<端口2>...]

expose和运行时候指定-p 宿主端口:容器端口不同,-p用户映射宿主端口和容器端口,将容器对应端口公开给外界访问。expose仅仅是生命容器打算使用什么端口而已,并不会自动在宿主机进行端口映射。

WORKDIR 指定工作目录

首先,Dockerfile中不同于执行shell命令,每一层都是不同的运行环境如下的命令一定会报/app/world.txt不存在的错误。

RUN cd /app
RUN echo "hello" > world.txt

第一层的cd /app仅仅是当前进程的工作目录变更,一个内存上的变化而已,结果不会造成任何文件变更。第二层时候是一个全新的容器,自然不可能集成前一层的内存变化,所以如果想是想cd /app的效果,必须使用WORKDIR指令来更改工作空间,并且如果目录不存在,WORKDIR会帮我们建立目录。

USER 指定当前用户

USER <用户名>

USER和WORKDIR类似,都会改变环境状态并影响到以后的层。WORKDIR是改变工作目录,USER是改变之后层的执行RUN、CMD、ENTERPONIT等命令的身份,用户必须提前建立好,否则无法切换

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN ["redis-server"]

HEALTHCHECK 健康检查

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

告知Docker如何判断容器的状态是否正常,于1.12版本引入。当镜像制定了healthcheck指令,指定一行命令之后,勇气启动容器,初始状态为starting,在HEALTHCHECK指令检查陈宫之后变为healthy,如果连续一定次数失败,则会变成unhealthy。HEALTHCHECK支持的选项有:

interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3 次。

ARG

语法:

ARG <name>[=<default value>]

设置变量命令,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 --build-arg <varname>=<value>来指定参数

如果用户在build镜像时指定了一个参数没有定义在Dockerfile种,那么将有一个Warning

提示如下:

[Warning] One or more build-args [foo] were not consumed.

我们可以定义一个或多个参数,如下:

FROM busybox
ARG user1
ARG buildno
...

也可以给参数一个默认值:

FROM busybox
ARG user1=someuser
ARG buildno=1
...

如果我们给了ARG定义的参数默认值,那么当build镜像时没有指定参数值,将会使用这个默认值

ONBUILD

语法:

ONBUILD [INSTRUCTION]

这个命令只对当前镜像的子镜像生效。

比如当前镜像为A,在Dockerfile种添加:

ONBUILD RUN ls -al

这个 ls -al 命令不会在A镜像构建或启动的时候执行

此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。

STOPSIGNAL

语法:

STOPSIGNAL signal

STOPSIGNAL命令是的作用是当容器推出时给系统发送什么样的指令

HEALTHCHECK

容器健康状况检查命令

语法有两种:

1. HEALTHCHECK [OPTIONS] CMD command
2. HEALTHCHECK NONE

第一个的功能是在容器内部运行一个命令来检查容器的健康状况

第二个的功能是在基础镜像中取消健康检查命令

[OPTIONS]的选项支持以下三中选项:

    --interval=DURATION 两次检查默认的时间间隔为30秒

    --timeout=DURATION 健康检查命令运行超时时长,默认30秒

    --retries=N 当连续失败指定次数后,则容器被认为是不健康的,状态为unhealthy,默认次数是3

注意:

HEALTHCHECK命令只能出现一次,如果出现了多次,只有最后一个生效。

CMD后边的命令的返回值决定了本次健康检查是否成功,具体的返回值如下:

0: success - 表示容器是健康的

1: unhealthy - 表示容器已经不能工作了

2: reserved - 保留值

例子:

HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1

健康检查命令是:curl -f http://localhost/ || exit 1

两次检查的间隔时间是5秒

命令超时时间为3秒

DockerFile语法【h】的更多相关文章

  1. 四:(之五)Dockerfile语法梳理和实践

    *5.Dockerfile语法梳理和实践 5.1 尽量使用官方的image作为base image 5.2 metadata:指明作者 版本 描述 5.3 每一条run都能形成一个分层,避免无用分层应 ...

  2. Dockerfile语法梳理

    Dockerfile语法 我们先来看一下上篇的 Dockerfile #获取base image FROM adoptopenjdk/openjdk8:latest #类似于执行 linux指令 RU ...

  3. dockerfile语法

    dockerfiles的指令不区分大小写,但约定为全部大写 dockerfiles支持如下语法命令: 1.FROM <image name> 所有的dockerfile都必须以from命令 ...

  4. dockerfile语法规则

    编写Dockerfile 在前面的章节,我们学习了通过docker命令来下载镜像,运行镜像,在容器中部署自己的程序,最后将容器提交到自己的镜像中.但是,这并不是Docker推荐的镜像构建方式.在这一章 ...

  5. dockerfile 语法

    基本语法格式:INSTRUCTION arguments (指令+参数)不分大小写 注释格式:# 注释 第一个指令必须是FROM,标示使用什么镜像 1.解析器指令 解析器指令是可选的,并且影响处理Do ...

  6. Dockerfile语法简介

    Dockerfile是由一系列命令和参数构成的脚本,一个Dockerfile里面包含了构建整个image的完整命令.Docker通过docker build执行Dockerfile中的一系列命令自动构 ...

  7. 一文学会Dockerfile语法

    接应上篇,续讲前文.今天咱来聊一下Dockerfile的使用 . 虽然可以通过docker commit命令来手动创建镜像,但是通过Dockerfile文件,可以帮助我们自动创建镜像,并且能够自定义创 ...

  8. 四:(之八_Linux压力测试工具stress)Dockerfile语法梳理和实践

    8.1 安装stress stress目前是在该目录下的可执行文件 --vm 创建几个进程 --vm-bytes 为每个进程分配多少内存 8.2 debug输出stress创建进程的过程 一直在创建有 ...

  9. 四:(之六_镜像发布)Dockerfile语法梳理和实践

    *6.镜像发布 1>注册Docker Hub账号并登陆. build的镜像名称格式必须是: dockerhub账户名/标识: 使用docker login在项目目录下登录: 浏览器: 2> ...

随机推荐

  1. 一台服务器配置多个TOMCAT

    如果要在一台服务器上配置多个Tomcat,主要就是要避免Tomcat服务器的端口冲突的问题.只需要修改CATALINA_HOME\conf\server.xml中的启动端口和连接端口就OK了! 下面我 ...

  2. PID动图——很形象

    p是控制现在,i是纠正曾经,d是管控未来! pid的公式: 其中Kp为比例带,TI为积分时间,TD为微分时间.PID控制的基本原理就是如此. pid的原理和代码,在木南创智的博客园中有很好的教程:ht ...

  3. 使用VSCode开发Flutter

    前言 为什么使用VSCode? flutter官方推荐的编辑器有IDEA/Android Studio和VSCode, 之前开发Flutter用的IDEA, 不过IDEA始终比较重,于是换用VSCod ...

  4. hadoop spark合并小文件

      一.输入文件类型设置为 CombineTextInputFormat hadoop job.setInputFormatClass(CombineTextInputFormat.class) sp ...

  5. JavaScript基础10——正则

    什么是正则?     正则表达式(regular expression)是一个描述字符规则的对象.可以用来检查一个字符串是否含有某个字符,将匹配的字符做替换或者从某个字符串中取出某个条件的子串等.   ...

  6. Hibernate的批量查询——原生sql查询

    1.查询所有的学生信息: (1)查询结果中,一条信息放入到一个数组中,从list集合中取出数组,并对数组进行遍历. public class GeneratorTest { public static ...

  7. 启动uiautomatorview 提示无法初始化主类

    启动uiautomatorview 提示无法初始化主类, 重新安装jdk到1.8版本就好了,就是这么神奇.

  8. java集合代码示例

    一.List ArrayList 使用List时,最好初始化容量. ArrayList的默认容量为10,每次扩容增0.5倍,假如要放置100个元素,需要多次扩容. List<String> ...

  9. 敏捷项目管理—Scrum框架总结

    Scrum中的角色 Scrum Master——项目负责人.项目经理 保护团队不受外界干扰,是团队的领导和推进者,负责提升 Scrum 团队的工作效率,控制 Scrum 中的“检视和适应”周期过程.与 ...

  10. 深度学习最全优化方法总结比较及在tensorflow实现

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/u010899985/article/d ...