• DockerFile语法【h】


      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_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秒

  • 相关阅读:
    querySelectorAll和getElementsByClassName获取元素的区别
    移动端的点透事件
    formidable处理node.js的post请求
    Node中流的概念
    关于Node.js中的路径问题
    前端设计模式——原型模式
    JavaScript中的循环和闭包
    为什么给函数表达式添加函数名
    作为一个初学者如何简单地理解闭包
    JS的with关键字到底是什么?
  • 原文地址:https://www.cnblogs.com/ExMan/p/12017026.html
Copyright © 2020-2023  润新知