精华内容
下载资源
问答
  • DockerFile解析之Dockerfile什么

    千次阅读 2018-11-05 22:04:13
    一、Dockerfile什么Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。 二、构建三步骤: 三、文件什么样??? centos的Dockerfile如下所示: FROM scratch ## 所有镜像...

    一、Dockerfile是什么?

    Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。

    二、构建三步骤:

    三、文件什么样???

    centos的Dockerfile如下所示:

    FROM scratch   ## 所有镜像文件的祖先类
    ADD centos-7-docker.tar.xz /
    
    LABEL org.label-schema.schema-version="1.0" \
        org.label-schema.name="CentOS Base Image" \
        org.label-schema.vendor="CentOS" \
        org.label-schema.license="GPLv2" \
        org.label-schema.build-date="20181006"
    
    CMD ["/bin/bash"]

     

    展开全文
  • dockerfile到底嘛的

    2017-10-19 05:42:46
    我用dockerfile创建了一个镜像,然后我该嘛,用docker run来启动镜像?还是说有别的事情可以做。 我在dockerfile里面写了一个RUN xxx /usr/local/jvm 然后用build创建了镜像,在用docker run建了个容器,但是在...
  • Dockerfile究竟是做什么

    千次阅读 2020-02-24 09:01:00
    Dockerfile什么 Dockerfile是一个创建镜像所有命令的文本文件, 包含了一条条指令和说明, 每条指令构建一层, 通过docker build命令,根据Dockerfile的内容构建镜像,因此每一条指令的内容, 就是描述该层如何构建.有了...

    开源领域的技术明星-Docker,一时风光无限好,Docker吸引了业界的众多知名企业的支持google, 亚马逊, IBM, 阿里, 腾讯等.只要有Linux的地方,就能看到docker被追捧的盛况.在技术更新迭代频繁的当下, Docker是今天翘楚.如果作为IT从业者你现在还不了解docker,那只能说明你生活在月球.

    我们在之前的文章中分享过Docker的三个关键名称:仓库, 镜像, 容器之间的概念和关系.

    今天我们就把重点放在Dockerfile上.

     Docker通过dockerfile来自动构建镜像.

    Dockerfile是什么

    Dockerfile是一个创建镜像所有命令的文本文件, 包含了一条条指令和说明, 每条指令构建一层, 通过docker build命令,根据Dockerfile的内容构建镜像,因此每一条指令的内容, 就是描述该层如何构建.有了Dockefile, 就可以制定自己的docker镜像规则,只需要在Dockerfile上添加或者修改指令, 就可生成docker 镜像.

    Dockerfile文件格式 

    Dockerfile 文件组成如下:

    ##  Dockerfile文件格式
    
    
    # This dockerfile uses the ubuntu image
    # VERSION 2 - EDITION 1
    # Author: docker_user
    # Command format: Instruction [arguments / command] ..
    
    
    # 1、第一行必须指定 基础镜像信息
    FROM ubuntu
    
    
    # 2、维护者信息
    MAINTAINER docker_user docker_user@email.com
    
    
    # 3、镜像操作指令
    RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
    RUN apt-get update && apt-get install -y nginx
    RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
    
    
    # 4、容器启动执行指令
    CMD /usr/sbin/nginx
    

    Dockerfile 四部分说明:

    • 一开始必须要指明所基于的镜像名称, 关键字是FROM, 这是必须的.

    • 接下来是维护者信息关键字是MAINTAINER, 非必须, 但良好的习惯有利于后期的职责明确.

    • 后面是镜像操作指令, 如RUN等, 每执行一条RUN命令,镜像添加新的一层.

    • 最后是CMD指令,来指明运行容器时的操作命令.

    Dockerfile 指令选项:

    • FROM

    • MAINTAINER

    • RUN

    • CMD

    • EXPOSE

    • ENV

    • ADD

    • COPY

    • ENTRYPOINT

    • VOLUME

    • USER

    • WORKDIR

    • ONBUILD

     具体的指令使用可以参阅官方:http://www.docker.org.cn/

     

    构建镜像

    Docker build命令会根据Dockerfile文件的上下文关系构建Docker镜像. 构建上下文是指Dockerfile所在的本地路径或一个URL(Git仓库地址). 构建上线文环境会递归处理, 所以构建所指定的路径还包括子目录, 而且URL还包括了其中指定的子模块.

    Dockerfile 一般位于构建上下文的根目录下,也可以通过-f来指定文件位置

    docker build -f /path/to/a/Dockerfile .
    

    镜像标签

    构建时候还可以通过-t参数指定构建成镜像的仓库标签

    docker build -t nginx/v3 .
    

    如果存在多个仓库下, 或者使用多个镜像标签, 可以用多个-t参数

    docker build -t nginx/v3:1.0.2 -t nginx/v3:latest .
    

    注意:命令的最后一个点不能丢他是告诉docker引擎的上下文路径,默认上下文路径就是Dockerfile的所在位置, 上下文路径下面不要放无用的文件,因为他会一起打包发送给docker引擎,文件过多会造成过程缓慢.

    简单示例

    接下来用一个简单的示例Dockerfile如何来构建和启动容器.

    在一个空白的文本文件, 命名为Dockerfile

    mkdir mynginx
    cd mynginx
    vi Dockerfile
    

    Dockerfile文件内容:

    FROM nginx
    RUN echo '<h1>It works!</h1>' > /usr/share/nginx/html/index.html
    

    非常简单的Dockerfile, 在执行过程中重写了nginx的默认页面信息,将其替换为It works!

    在dockerfile文件目录下执行:

    louie-mac:mynginx louiezhou$ docker build -t nginx:v1 .
    Sending build context to Docker daemon  3.072kB
    Step 1/2 : FROM nginx
    latest: Pulling from library/nginx
    bc51dd8edc1b: Pull complete
    66ba67045f57: Pull complete
    bf317aa10aa5: Pull complete
    Digest: sha256:ad5552c786f128e389a0263104ae39f3d3c7895579d45ae716f528185b36bc6f
    Status: Downloaded newer image for nginx:latest
     ---> 2073e0bcb60e
    Step 2/2 : RUN echo '<h1>It works!</h1>' > /usr/share/nginx/html/index.html
     ---> Running in 2f49ab8104be
    Removing intermediate container 2f49ab8104be
     ---> e68df98a0494
    Successfully built e68df98a0494
    Successfully tagged nginx:v1
    
    构建完成后,使用docker images,可以查看构建的镜像,如果存在REPOSITORY为nginx和
    TAG是v1的信息,就表示成功了.
    louie-mac:mynginx louiezhou$ docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    nginx               v1                  e68df98a0494        4 minutes ago       127MB
    nginx               latest              2073e0bcb60e        2 weeks ago         127MB
    
    可以通过命令单独查看镜像
    louie-mac:mynginx louiezhou$ docker images | grep e68df98a0494
    nginx               v1                  e68df98a0494        2 hours ago         127MB
    

    接下来是启动容器, 使用docker run 命令

    louie-mac:mynginx louiezhou$ docker run  --name docker_nginx_v1 -d -p 80:80 nginx:v1
    32180627ef8a97710726d14efa499d4c61ccb95d9e7b0d293cd1f0227fc74f94
    

    docker run还有丰富的参数可以使用

    docker run -p 3000:3000 -ti --rm --init nginx:v1
    

    这条命令会使用nginx镜像启动一个容器, 命名为 docker_nginx_v1 , 映射端口是80

    打开浏览器地址localhost,就可以看到

     

    这样一个简单使用Dockerfile构建镜像,运行容器就完成了.

    通过docker exec 命令可以进入容器内部

    louie-mac:mynginx louiezhou$ docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                        NAMES
    32180627ef8a        nginx:v1            "nginx -g 'daemon of…"   2 hours ago         Up 2 hours          80/tcp, 0.0.0.0:99->99/tcp   docker_nginx_v1
    louie-mac:mynginx louiezhou$ docker exec -it 32180627ef8a /bin/bash
    root@32180627ef8a:/#
    

    带上容器id,就可以进入容器内部进行访问了

    修改容器内容

    容器启动后,需要对容器内容的文件进行完善, 可以使用

    docker exec -it 容器名称 bash 命令进行修改, 基于上面示例基础修改启动提示内容

    docker exec -it docker_nginx_v1 /bin/bash
    root@3729b97e8226:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
    root@3729b97e8226:/# exit
    exit
    

    以交互式终端方式进入docker_nginx_v1 容器, 并执行bash命令,也就是获取了一个可操作的shell,再次刷新浏览器, 就是你新修改的内容了.

    修改了容器的文件,也就是动了容器的存储层,可以通过docker diff命令看到具体改动

    louie-mac:mynginx louiezhou$ docker diff docker_nginx_v1
    C /run
    A /run/nginx.pid
    C /var/cache/nginx
    A /var/cache/nginx/client_temp
    A /var/cache/nginx/fastcgi_temp
    A /var/cache/nginx/proxy_temp
    A /var/cache/nginx/scgi_temp
    A /var/cache/nginx/uwsgi_temp
    

    到此Dockerfile使用方式就介绍的差不多了

    补充内容:

    缓存

     Dockerfile守护进程会一条条执行Dockerfile中的命令, 而且会在每一步提交并生成一个新镜像,最后会输出最终镜像的id, 生成完成后, Docker守护进程会自动清理你发的上下文.

    Dockerfile文件中的每一条指令都会被独立执行, 并会创建一个新的镜像,RUN命令等不会对下一条指令产生影响.

    更多的实用docker命令, 请关注后回复关键字docker,即可获取.

    总结: 

    测试是一门技术, 更是一门艺术. 也许你今天拥有的技术, 明天就会被淘汰. 同时需要我们开拓思维和眼界, 积极拥抱变化, 学习新知识, 新方法,新技能, 计算机领域讲究的是实践, 学习更要讲究方式方法. 学习和动手一定要结合, 光看不练,犹如看武功秘籍, 是永远成不了武功大侠的.

    作者:Louiezhou

    来源: 公众号:测试工程师成长之道(louiezhou001)

    往期精彩回顾


    点击【在看】与好友一起分享

    展开全文
  • Dockerfile

    2019-05-09 12:15:43
     docker build可以基于Dockerfile和context打包出一个镜像,其中context是一系列在PATH或URL中指定的位置中的文件(context是递归的,包含子目录下的文件,build时会将context中的全部内容传递给docker daemon)。...

    1. 关于docker build

    docker build可以基于Dockerfile和context打包出一个镜像,其中context是一系列在PATHURL中指定的位置中的文件(context是递归的,包含子目录下的文件,build时会将context中的全部内容传递给docker daemon)。其中PATH是指本地文件系统,URL则是git仓库的地址。比如在当前目录下创建镜像:docker build .,此时context就是当前目录.。build的运行是由docker daemon操作的,并不是CLI(Command-Lin Interface)。通常build时强烈建议创建一个空目录,然后将Dockerfile文件放入,最后只将build需要用到的文件放到该目录下。注:千万不要用root或者/作为PATH,docker daemon会将整个目录下的文件读取。为了尽可能提高Docker的build性能,和git一样可以在上述目录中添加.dockerignore文件排除一些不要的文件,比如正常打包时都会排除掉Dockerfile:

    ./Dockerfile*
    

     默认build时会基于context的根目录下Dockerfile文件打包(如果不存在会报错),当然可以通过-f DockerfilePath的方式指定任意位置的Dockerfile位置,但后面的context必须在Dockerfile所在位置的目录或者父目录(指定为其他目录会报错,比如指定为~/k8s/),比如:

    # ~/docker/test1/Dockerfil指定Dockerfile位置,~/docker/指定context一定是Dockerfile所在目录或父目录
    docker build -f ~/docker/test1/Dockerfile ~/docker/
    

     此外还可以指定如果镜像构建成功存放的仓库和标签(即repository和tag),如构建时打上阿里云的仓库标签:docker build -t registry.cn-shanghai.aliyuncs.com/hhu/redis:4.0-alpine3.9 .。注:这里可以不断追加-t 标签的方式打上多个仓库仓库标签,比如:docker build -t registry.cn-shanghai.aliyuncs.com/hhu/redis:4.0-alpine3.9 -t test1/redis:4.0-alpine3.9 -t test2/redis:4.0-alpine3.9 .,上述栗子一下就会出现3个标签的镜像,但它们的ID是相同的,仅仅是标签不同。

     和大部分的应用类似,docker daemon会在运行Dockerfile中的指令时会先验证文件的可行性,比如语法错误就会返回error。Dockerfile中的每条指令都是独立运行的(比如RUN cd /tmp并不会影响下一条指定的执行),并不会创建新的镜像。不论何时,docker都会尽可能重复应用缓存的中间镜像以便加快build的过程,所以有时在build时可能会在控制台看到Using cache的字样。可以使用的缓存镜像只有在本地具备父链才能使用(即缓存的镜像先前被创建过或者整个镜像链都使用docker load加载过)。如果在build时希望使用某个特定的镜像缓存可以使用--cache-from选项,注:使用--cache-from时不需要具备本地父链,可能会从其他的注册中心拉下来。

    注:docker run如果不显式的指定-it进行交互的话,此时创建的容器会直接在后台运行,如果没有前台进行,docker会让容器自动停止并移除,所以很多时候为了让一些只有操作系统的镜像创建的容器不被docker自动移除,我们往往会在创建镜像dockerfile的时候加上一个CMD

    # 创建 centOS 空系统工具经常加这个CMD
    CMD /usr/sbin/init
    # 创建 Alpine 空系统工具经常加这个CMD
    CMD init
    

    他们目的都是在系统中挂一个前台进程,这样docker就不会认为该容器处于空闲状态去移除它,目的都是一样的,当然我们也可以人为造出一些死循环来达到这种目的。

    2. 语法

     Dockerfile的语法为INSTRUCTION arguments,不区分大小写,但为了区分指令和参数,约定指令全部大写、参数尽量小写。docker会按序执行Dockerfile中的指令,Dockerfile文件必须以FROM指令开头(除指令解释器外),它指定了当前构建镜像的基础镜像。通常Dockerfile中也允许注释,注释行以#开头,但指令解释器除外,比如``。

    2.1 指令解释器

    指令解释器是可选的,它会影响下面指令的处理方式,但不会在增加层layer,也不会作为构建的步骤展示出来。docker一旦处理了注释、空行或生成器指令,就不会再看是它否分析器指令了,就算下面还有指令解释器,docker也会将其视为注释(都是以#开头),所以Dockerfile中只要有指令解释器,请务必尽可能的靠前声明(约定解释器为小写),应该Dockerfile的第一行。指令解释器不支持行继续的行为(Linux中表现为\),同时指令解释器后应该空一行。总结一下,应该遵循如下的规则:

    1. #开头,指令解释器小写,如果有位于Dockerfile的第一行;
    2. 不支持行继续操作行为,即\
    3. 解释器后应留一个空白行;

    下面是一些反例:

    # 反例1:使用了行继续 \
    # direc \
    tive=value
    
    # 反例2:只会识别第一个,value2不应该出现会被当成注释
    # directive=value1
    # directive=value2
    
    FROM ImageName
    
    # 反例3:指令解释器非首行
    FROM ImageName
    # directive=value
    
    

    注:指令解释器允许使用空格符,比如下面的几种方式都是一样有效的:

    #directive=value
    # directive =value
    #	directive= value
    # directive = value
    
    

     Dockerfile支持的指令解释器有:syntaxescape。其中syntax仅支持下一代构建工具BuildKit,这里暂不进行捣鼓,直接看escape,它定义的是Dockerfile中的转义字符,有2种定义方式:

    # escape=\
    
    # 或者
    
    # escape=`
    

    如果不指定默认转义字符为\。转义字符既用于转义一行中的字符,也用于转义换行符。这使得Dockerfile指令可以跨越多行,无论转义分析器指令是否包含在Dockerfile中,转义都不会在RUN命令中执行,除非在行尾执行。在windows上,\ 是目录之间的分隔符,将转义字符设置为 ` 是非常有用的,它和 PowerShell 一致,比如在windows的powerShell中:

    FROM microsoft/nanoserver
    COPY testfile.txt c:\\
    RUN dir c:\
    

    没有指定指令解释器,默认为\,那此时第二行中COPY testfile.txt c:\\就出现了转义字符(c:\\中的第一个\),实际意思就是COPY testfile.txt c:\,那剩下的那个\就变成了行继续的操作,所以第二行和第三行是一行实际为:COPY testfile.txt c:\RUN dir c:第三行的转义字符在行末属于可执行范围。在powershell中,为了避免这个问题可以使用 ` 作为转义字符就不会出现上述的问题:

    # escape=`
    
    FROM microsoft/nanoserver
    COPY testfile.txt c:\\
    RUN dir c:\
    

    上述Dockerfile拆解成了3个指令(除去指令解释器,之前是2条指令)。

    2.2 环境替换

     docker中可以使用ENV为特定的指令声明环境变量,转义字符也被处理为将类似变量的语法包含到字面上的语句中。环境变量在Dockerfile中使用$variable_name${variable_name}标注,上述2标注方式是一样的,第2种{xx}的方式通常用于解决变量名没有空格的问题(不是很理解),比如${foo}_bar,此外这种大括号的方式还支持一些标准的bash修饰符,比如(word只是随意取的值):

    • ${variable:-word}表示如果variable设置了,那它的值就是设置的值;如果variable没有设置,那word就是它的值(有点三目运算的意思)。
    • ${variable:+word}表示如果variable设置了,那word就是它的值;如果variable没有设置,那它的值就是空字符串。

    注:变量上也是可以使用转义字符的,比如使用的转义字符是默认的\,那在变量中\$foo\${foo},那就表示它就是个普通的字符串$foo${foo},而不是对应foo的值。

     环境变量支持如下的指令:ADDCOPYENVEXPOSEFROMLABELSTOPSIGNALUSERVOLUMEWORKDIRONBUILD(1.4版本之后该指令只有在和上述其他指令结合使用时才能使用环境变量)。下面是一个示例(解析的指令在#后已经标出):

    FROM busybox
    # 声明环境变量foo,表示的值为/bar
    ENV foo /bar
    # 等同于 WORKDIR /bar
    WORKDIR ${foo}
    # 等同于 ADD . /bar
    ADD . $foo
    # 等同于 COPY $foo /quux
    COPY \$foo /quux
    

     环境变量的替换将在整个指令中对每个变量使用相同的值,比如下面的示例:

    ENV abc=hello
    ENV abc=bye def=$abc
    ENV ghi=$abc
    

    上述的定义过程中,def的值为hello,而不是byeghi的值为bye,因为它不是将abc设置为bye那条指令的一部分。可能有点绕人,但只要记住一点就行了,在使用变量时,变量的值永远都是前面最靠近使用该变量的指令的定义(但不包含本身),如第2条指令使用def=$abc,向前寻找变量abc,排除自身,发现最靠近的abc定义在第一条指令中abc=hello,所以def=hello;同样第3条指令使用ghi=$abc,向前寻找变量abc,发现第2条指令最靠近它,虽然第1条指令也有abc的声明,但没有第2条指令靠近,所以取第2条指令之中abc的声明bye,所以ghi=bye

    2.3 .dockerignore文件

     和.gitignore类似,在CLI(Command-Lin Interface)将context发送给docker daemon时,它会关注一下context根目录下的.dockerignore文件,如果存在,CLI将修改context以排除与该文件中匹配的文件和目录。这样可以避免将一些不必要的大文件和敏感发送给docker daemon并通过ADDCOPY将这些文件加入到镜像中。同样的.dockerignore文件中也是允许注释的,行首用#标注即可,比如:

    # comment
    */temp*
    */*/temp*
    temp?
    

    上述的# comment是一个注释,CLI将不会管它;*/temp*表示CLI将排除context根目录中的任何一级子目录中名称以temp开头的文件或目录;*/*/temp*表示CLI将从context根目录下任何两级子目录中排除以temp开头的文件或目录(如/somedir/subdir/temporary.txt);temp?表示CLI将排除context根目录中名为temp的单字符扩展名的文件和目录(比如/tempa)。此外它还支持**通配符(匹配0或多个目录,注意是用于匹配目录的!!),如**/*.go就是匹配context目录(包括它所有的子孙目录)下所有以.go结尾的文件。

     如果行首是!可以用于排除例外的情况,示例如下:

    *.md
    !README.md
    

    上述就是排除所有以.md结尾的文件,但README.md除外不用排除。

    !的位置会影响.dockerignore文件中与特定文件匹配的属性决定它是包含的还是排除的最后一行,下面是2个示例(有点懵懂):

    # 示例1:除了README-secret.md之外,排除上下文中含任何其他以.md结尾的文件。
    *.md
    !README*.md
    README-secret.md
    
    # 示例2:所有README文件都包含在内,中间的 README-secret.md 没有效果,因为 !readme*.md 与 readme-secret.md 匹配却在最后
    *.md
    README-secret.md
    !README*.md
    

     在.dockerignore中甚至可以将Dockerfile.dockerignore排除掉,但它们仍然会被发送到daemon因为docker需要这些进行job,但ADDCOPY指令不会将它们复制到镜像中。

    2.4 具体指令(只包含18.09版本最新指令)

    2.4.1 FROM

    FROM指令初始化一个新的构建阶段,它为后续的指令设置了一个基本镜像,因此它必须是在所有指令的最前面定义的(除指令解释器),这个基本镜像可以是任何一个合法的镜像。语法如下:

    # 方式1
    FROM <image> [AS <name>]
    
    # 方式2
    FROM <image>[:<tag>] [AS <name>]
    
    # 方式3
    FROM <image>[@<digest>] [AS <name>]
    

    FROM可以在一个Dockerfile文件中出现多次,创建多个镜像或使用一个生成阶段作为另一个的依赖。只需在每条新的FROM指令之前记录提交所输出的最后一个镜像的ID,每个FROM指令会清除之前其他指令创建的状态。name是可选的,可以通过在FROM指令中添加AS name给一个新的构建阶段起一个名字,这个名字可以在后来的FROM指令和COPY --from=<name|index>指令中引用对应的镜像。同样tagdigest也是可选的,如果不指定,默认为latest

    2.4.2 ARG

    ARG是唯一一个可以在FROM指令之前的,FROM指令是支持在第一个FROM之前由ARG指令声明的变量,比如:

    # 声明变量 CODE_VERSION,值为latest
    ARG  CODE_VERSION=latest
    # 在FROM指令中使用由ARG声明的变量
    FROM base:${CODE_VERSION}
    CMD  /code/run-app
    
    # 在FROM指令中使用由ARG声明的变量
    FROM extras:${CODE_VERSION}
    CMD  /code/run-extras
    

    FROM指令之前ARG变量的声明是属于构建阶段之外的,因此不能在FROM指令之后的其他指令中使用。如果要使用第一个From之前声明的ARG值,需要在构建阶段内使用没有指定值的ARG指令,比如:

    ARG VERSION=latest
    FROM busybox:$VERSION
    # 声明一个没有默认值的变量 ARG 指令
    ARG VERSION
    RUN echo $VERSION > image_version
    
    2.4.3 RUN

    RUN指令将会在当前镜像的顶部的一个新层layer中执行命令并提交结果,提交镜像的结果将用于Dockerfile文件中的下一步骤。分层RUN并生成新的新的结果符合Docker的核心思想(即提交的成本很低且可以从镜像历史的任何一点创建容器,很像源代码管理)。语法如下:

    # 形式1:shell的形式,命令运行在shell中,Linux中默认运行 /bin/sh -c,win中默认运行 cmd /S /C
    RUN <command>
    
    # 形式2:exec的形式
    RUN ["executable", "param1", "param2"]
    

    exec形式可以避免对shell字符串进行munging,可以在不包含指定可执行shell的基本镜像中运行RUN指令。shell形式默认的shell可以使用SHELL命令更改,比如要使用除/bin/sh之外的shell,就需要使用传入所需shell的exec形式:

    RUN ["/bin/bash", "-c", "echo hello"]
    

    在shell形式中可以使用\以继续运下一行的 RUN 指令(即使用\作为行继续操作符,可以跨行运行),比如:

    RUN /bin/bash -c 'source $HOME/.bashrc; \
    echo $HOME'
    

    上述使用的是行继续操作符,实际是一个指令,等同于:RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'。exec形式会被编译成JSON形式,所以需要使用双引号"而不是单引号',此外在exec形式中应该避免\,如RUN ["c:\windows\system32\tasklist.exe"]会出错,正确的写法应该为RUN ["c:\\windows\\system32\\tasklist.exe"]

     和shell形式不同,exec形式不会调用shell,所以平常在shell正常处理的在exec形式中可能无法处理,比如:RUN [ "echo", "$HOME" ]不会替换变量$HOME,如果要用shell处理,要么直接用shell形式RUN <command>,要么直接执行shell,如:RUN [ "sh", "-c", "echo $HOME" ]RUN指令的缓存在下一个构建阶段不会失效,比如RUN apt-get dist-upgrade -y将会在下一个阶段重复使用,当然也可以使用--no-cache参数来让RUN指令失效,比如:docker build --no-cacheRUN指令的缓存也可以通过ADD指令失效。

    2.4.4 CMD

     一个Dockerfile文件中仅可以只有一个CMD指令,如果有多个CMD,仅有最有一个CMD奏效,它的主要目的是为正在执行的容器提供默认值,这些默认值可以包括可执行文件,也可以省略可执行文件(但此时必须指定一个ENTRYPOINT指令),主要语法如下:

    # 形式1:exec形式,这是首选形式
    CMD ["executable","param1","param2"]
    
    # 作为ENTRYPOINT默认参数
    CMD ["param1","param2"]
    
    # shell形式
    CMD command param1 param2
    

    如果CMD用于为ENTRYPOINT指令提供默认参数(即上述第2种形式),那CMDENTRYPOINT指令都应该用JSON格式指定(双引号")。当在shell或exec形式,CMD指令设置在运行镜像时要执行的命令,如果使用shell形式的CMD<command>应该是/bin/sh -c

    FROM ubuntu
    CMD echo "This is a test." | wc -
    

    如果不想在shell中运行<command>,那就必须使用JSON数组的形式并使用可执行文件的全路径。数组形式是CMD的首选形式,任何额外的参数必须在数组中做独立表达,如:

    FROM ubuntu
    CMD ["/usr/bin/wc","--help"]
    

    如果想每次容器都执行相同的可执行文件,应该考虑使用ENTRYPOINTCMD的配合使用。如果指定docker run的参数,那么它们将覆盖在CMD中指定的默认值。

    注:RUNCMD可能有些像,主要区别是:RUN是运行一个命令然后提交结果,而CMD在构建镜像的过程中不会干任何事,但指定镜像的预期命令。

    2.4.5 LABEL

    LABEL指令用于向镜像添加元数据,它是一个键值对,如果key值或value值中包含空格,需要使用双引号和反斜杠,一个镜像可以有多个标签,下面是示例:

    # 有空格用引号包裹
    LABEL "com.example.vendor"="ACME Incorporated"
    
    # 
    LABEL com.example.label-with-value="foo"
    
    # 
    LABEL version="1.0"
    
    # 使用行继续操作符跨行
    LABEL description="This text illustrates \
    that label-values can span multiple lines."
    
    # 一个LABEL中设置多个标签
    LABEL multi.label1="value1" multi.label2="value2" other="value3"
    
    # 一个LABEL中设置多个标签
    LABEL multi.label1="value1" \
          multi.label2="value2" \
          other="value3"
    

    FROM指令中指定的基本镜像中的标签会被当前构建的镜像继承过来,这些标签如果在当前构建的镜像指定相同的key值但不同的value值时是会被覆盖的,使用docker inspect xxx可以查看镜像xxx的标签,下面是openjdk部分标签:

    docker inspect 3675b9f543c5
    
    # 结果
    [
        {
            "Id": "sha256:3675b9f543c5db0d8d554f8e103a4cb98db26be5e5c88019cbe49dcd4fea4685",
            "RepoTags": [
                "openjdk:8-jdk-alpine"
            ],
            "RepoDigests": [
                "openjdk@sha256:2a52fedf1d4ab53323e16a032cadca89aac47024a8228dea7f862dbccf169e1e"
            ],
            "Parent": "",
            "Comment": "",
            "Created": "2019-04-10T01:52:39.548813341Z",
            "Container": "2d38510bb479e015e7990ac60a6af8855e1c9f7bf6b6a66bde2c8625355eccd9",
            "ContainerConfig": {
                ...
            },
            ...
            "Metadata": {
                "LastTagTime": "0001-01-01T00:00:00Z"
            }
        }
    ]
    
    2.4.6 EXPOSE

    EXPOSE指令表示了docker容器运行时监听的特定网络端口,可以指定监听TCP(默认)或UDP,在实际运行容器docker run时可以使用-p标识去发布并映射到一个或多个端口。比如默认监听TCP,现在改成UDP:

    EXPOSE 80/udp
    

    也可以同时监听TCP和UDP的80端口:

    EXPOSE 80/tcp
    EXPOSE 80/udp
    

    如果在docker run时指定-p,那端口将为TCP和UDP各暴露一次。-p在主机上使用了一个短暂的高阶主机端口,因此TCP和UDP的端口将不相同(不懂)。当然就算在Dockerfile中配置过端口,在docker run时可以通过-p来覆盖这里定义的,如:

    docker run -p 80:80/tcp -p 80:80/udp ...
    

    docker network可以在容器之间创建网络进行交流,不需要暴露或发布特定端口,因为连接到网络的容器可以通过任何端口相互通信。

    2.4.7 ENV

    ENV指令用于设置环境变量,将环境变量设置<key>设置为<value>,这里设置的环境变量将会存在于所有后续指令的环境变量中,可以在命令行进行替换,可以使用docker inspect xxx查看环境变量的值。ENV有如下形式:

    # 形式1:设置单个变量值,在第一个空格后的字符串就是value(可能包含空格)
    ENV <key> <value>
    # 形式1示例,定义了3个环境变量
    ENV myName John Doe
    ENV myDog Rex The Dog
    ENV myCat fluffy
    
    # 形式2:允许同时设置多个环境变量,可以使用双引号 和行继续操作符 \
    ENV <key>=<value> ...
    # 形式2示例,定义了2个环境变量
    ENV myName="John Doe" myDog=Rex\ The\ Dog \
        myCat=fluffy
    

    使用ENV设置的环境变量将从生成镜像到镜像容器运行保持不变,使用docker inspect可以看到这些环境变量,在运行容器时可以使用docker run --env <key>=<value>来改变环境变量。如果为单个指令设置值的话,尽量使用RUN <key>=<value> <command>

    2.4.8 ADD

    ADD指令可以复制新的文件、目录或者远程URL中的<src>,将它们添加到镜像的文件系统中(具体是镜像的<dest>目录),具体语法有2种:

    # 形式1:将context中 src 复制到镜像中的 dest 目录
    ADD [--chown=<user>:<group>] <src>... <dest>
    
    # 形式2:和形式1一样,就多了双引号,主要用于src和dest路径中存在空格的情况
    ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
    

    <src>是相对于context的相对路径,可以有多个,而且它可以包含通配符,比如:

    # 将所有以hom开头的为文件复制进去
    ADD hom* /mydir/
    # ? 匹配单个字符,如"home.txt"
    ADD hom?.txt /mydir/
    

    <dest>是镜像中的一个路径,可以是绝对路径,也可以是相对于WORKDIR的一个相对目录(以/开头就是绝对路径),如下:

    # 将 test 复制到 `WORKDIR`/relativeDir/ 的相对路径
    ADD test relativeDir/
    
    # 将 test 复制到绝对路径 /absoluteDir/
    ADD test /absoluteDir/
    

    当复制包含特殊字符名字(比如[])的文件或目录时,需要做一些处理防止被误认为通配符,比如复制arr[0].txt文件:

    # 将 arr[0].txt文件复制到镜像中的 /mydir/ 目录
    ADD arr[[]0].txt /mydir/
    

    注:其中--chown是仅支持建立再Linux容器上的Dockerfile,win上无效。所有新文件或目录都是使用UID和GID为0开头(Linux中UID和GID即表示UserId和GroupId,0是超级用户,500起则是普通用户,表示的一种权限)被创建,除非使用--chown选项指定用户、用户组(或用UID和GID,2种方式可以混用),如果指定了用户却不指定用户组(或指定了UID却不指定GID),那将会使用和UID一样的GID。下面是示例:

    ADD --chown=55:mygroup files* /somedir/
    ADD --chown=bin files* /somedir/
    ADD --chown=1 files* /somedir/
    ADD --chown=10:11 files* /somedir/
    

    ADD遵循下面的规则:

    • <src>必须在context目录中,不能出现context之外的目录,CLI只将context发送给daemon,docker是无法读取context之外目录的文件、目录的;
    • <src>如果是一个URL:
      • 如果<dest>不以斜杠/结尾,文件将会从URL下载并被复制到<dest>
      • 如果<dest>以斜杠/结尾,那将从URL推断文件名并将文件下载到<dest>/<filename>,如ADD http://example.com/foobar /将会创建/foobar文件;
    • 如果<src>是一个目录,那整个目录的内容(只是它内部的内容但不包含目录本身)将会被复制,包括文件系统的元信息;
    • 如果<src>是本地context目录下的压缩包,那它将会被解压成一个目录(前提是可识别的压缩格式:gzip, bzip2 or xz),但仅限于context是本地目录的情况,如果<src>是URL资源就不会自动解压了。
    • 如果<src>有多个,那<dest>必须只能是一个目录(即必须/结尾);
    • 如果<dest>不以/结尾,那将会被认为是一个文件(不是目录),那<src>的内容将会被写入到该文件中;
    • 如果<dest>不存在,那将会创建(丢失的目录也会随之被创建);
    2.4.9 COPY

    COPY和上述的ADD指令功能一样,但COPY<src>不能是URL,也不能对压缩包进行解压,语法类似:

    COPY [--chown=<user>:<group>] <src>... <dest>
    COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
    
    2.4.10 ENTRYPOINT

    ENTRYPOINT允许配置容器,语法为:

    # 形式1:exec形式,优先
    ENTRYPOINT ["executable", "param1", "param2"]
    
    # 形式2:shell形式
    ENTRYPOINT command param1 param2
    

    比如以默认内容启动nginx,监听80端口:docker run -i -t --rm -p 80:80 nginx。运行docker run xxx时指定命令行参数将会追加到exec形式的ENTRYPOINT指令中,且覆盖使用CMD指令指定的所有元素,允许将这些参数传给entry point,-d(即docker run <image> -d)即可将将这些参数传给entry point,甚至可以使用docker run --entrypoint选项覆盖Dockerfile中的ENTRYPOINT指令。shell形式禁止使用任何CMDrun命令行参数,缺点是ENTRYPOINT将作为/bin/sh-c的子命令启动,不会传递信号,即可执行文件经不会成为容器的PID 1且不会收到 Unix 信号,因此可执行文件将收不到docker stop <container>发的SIGTERM。Dockerfile中最后一条ENTRYPOINT指令才有效。

    【exec形式的ENTRYPOINT

     可以使用exec形式的ENTRYPOINT设置相当稳定的默认命令和参数,然后使用任意一种形式的CMD设置可能改变的额外默认值,如:

    FROM ubuntu
    ENTRYPOINT ["top", "-b"]
    CMD ["-c"]
    

    在运行该镜像容器时,top是唯一的进程。在命令行中可以使用--entrypoint选项来覆盖Dockerfile中ENTRYPOINT指令。

    注:

    1. exec形式必须使用双引号""(最终是被编译成JSON);
    2. exec形式不会对shell命令中的变量做替换(如$HOME不会被替换成用户根目录,比如/root),如有需要必须指定一个shell目录,如ENTRYPOINT [ "sh", "-c", "echo $HOME" ]

    【shell形式的ENTRYPOINT

     shell形式可以直接指定字符串,默认就会在/bin/sh -c中执行,理所当然的可以进行变量替换。

    【总结】

    CMDENTRYPOINT指令定义了在运行容器时什么命令会执行,规则如下:

    1. Dockerfile应当指定至少一个CMDENTRYPOINT指令;
    2. 在将容器用作可执行文件时应当定义ENTRYPOINT
    3. CMD指令应当作为ENTRYPOINT指令指定默认参数的一种方式,或者在容器中执行特殊命令;
    4. CMD指令可以在运行容器时指定被重写;
    5. 如果CMD在基础镜像上定义了,那在当前镜像中如果设置ENTRYPOINT将会重置上述的CMD的值(变为空值),此时必须在当前镜像中定义CMD的值;
    2.4.11 VOLUME

    VOLUME指令用于创建指定名字的挂载点,并将其标记为保存来自本地主机或其他容器的外部装入的卷。形式有JSON和纯字符串的:

    # 形式1(JSON)
    VOLUME ["/var/log/"]
    
    # 形式2
    VOLUME /var/log
    # 可以指定多个
    VOLUME /var/log /var/db
    

    比如:

    FROM ubuntu
    RUN mkdir /myvol
    RUN echo "hello world" > /myvol/greeting
    VOLUME /myvol
    

    将会创建一个新的挂载点/myvol/greeting并将greeting文件复制到上述新建的存储卷。使用VOLUME有如下的注意点:

    1. 基于win平台存储卷的容器:容器内部存储卷的目的地必须为空目录或者不存在的目录(此时docker会自动创建),此外指定目录不能为C盘;
    2. Dockerfile中更改存储卷:如果任何生成步骤在声明卷后然后又更改卷内的数据,则这些更改将被丢弃(即存储卷的使用周期只有当前容器);
    3. 由于JSON,注意双引号;
    4. 在主机目录在容器运行时声明:主机目录(即挂载点)是天然依赖主机的,为了保持映像的可移植性,因为不能保证给定的主机目录在所有主机上都可用,因此不能在Dockerfile中挂载主机目录,VOLUME指令不支持指定host-dir参数,在创建或者运行容器时必须指定挂载点;
    2.4.12 USER

    USER指令用于在运行镜像中的RUNCMDENTRYPOINT指令时设置用户名(或UID)以及用户组(可选,或者GID),主要形式如下:

    # 形式1
    USER <user>[:<group>]
    
    # 形式2
    USER <UID>[:<GID>]
    

    注:

    1. 当用户没有用户组时,镜像将会运行在root用户组下;
    2. win中,如果用户不是内置的账户,那必须先进行创建,可以使用net user来创建,下面是示例:
    FROM microsoft/windowsservercore
    # 在容器中先创建win用户
    RUN net user /add patrick
    # Set it for subsequent commands
    USER patrick
    
    2.4.13 WORKDIR

    WORKDIR指令用于设置RUNCMDENTRYPOINTCOPYADD指令的工作目录,如果WORKDIR指定的目录不存在,就会被创建(即使后续指令没有使用该目录),该目录可以在Dockerfile中使用多次,基本语法为:

    WORKDIR /path/to/workdir
    

    如果提供了相对路径,那它是先前WORKDIR指定目录的相对路径,下面是示例:

    # 示例
    # 绝对路径
    WORKDIR /a
    # 相对路径
    WORKDIR b
    WORKDIR c
    RUN pwd
    

    最终的路径为/a/b/c。此外WORKDIR指令可以解析之前使用ENV设置的环境变量,如:

    ENV DIRPATH /path
    WORKDIR $DIRPATH/$DIRNAME
    # 输出应为 /path/$DIRNAME
    RUN pwd
    
    2.4.14 构建时参数ARG

    ARG指令用于用户在创建镜像时定义的一些变量,语法:

    ARG <name>[=<default value>]
    

    其中默认值是可选的,如果在构建时不指定构建参数将会使用默认值。可以在docker build时使用--build-arg <varname>=<value>指定这些变量的具体值,如果用户指定了Dockerfile中未定义的构建参数,构建时将会出现下面的日志:

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

    可以定义多个ARG指令,比如:

    # 注:默认值是可省的
    FROM busybox
    ARG user1
    ARG buildno
    

    注:不建议将密码这类的信息作为构建参数,因为任何用户都可以使用docker history <images>查看到构建参数。

    【作用域】

    ARG变量定义从dockerfile中定义它的地方开始生效,而不是从参数在命令行或其他地方的使用开始生效,比如:

    FROM busybox
    USER ${user:-some_user}
    ARG user
    USER $user
    

    构建时使用docker build --build-arg user=what_user .,实际在Dockerfile中的第2行中定义了USER,并将变量user的值假设为some_user,第4行的USER指令定义了变量user是什么(将会从命令行中传过来)。在用ARG指令定义变量之前,任何变量的使用都是空字符串(那是,没定义就使用不报错就不错了)。ARG指令的作用域只在定义ARG的阶段生效,如果需要在多个阶段使用arg,每个阶段必须都包含ARG指令,如:

    FROM busybox
    ARG SETTINGS
    RUN ./run/setup $SETTINGS
    
    FROM busybox
    ARG SETTINGS
    RUN ./run/other $SETTINGS
    

    【使用】

    可以使用ARGENV指令指定RUN指令中指定的变量,使用ENV指令定义的环境变量会覆盖掉ARG指令中同名的变量,比如:

    FROM ubuntu
    ARG CONT_IMG_VER
    ENV CONT_IMG_VER v1.0.0
    RUN echo $CONT_IMG_VER
    

    构建镜像docker build --build-arg CONT_IMG_VER=v2.0.1 .最终的CONT_IMG_VER变量输出为v1.0.0

    【预定义的ARG】

    Docker中有一些预定义好的参数ARG,这些参数可以直接在build时指定,而无需在Dockerfile中先进行定义,预定义的参数有:

    • HTTP_PROXY
    • http_proxy
    • HTTPS_PROXY
    • https_proxy
    • FTP_PROXY
    • ftp_proxy
    • NO_PROXY
    • no_proxy

    使用时直接通过--build-arg <varname>=<value>传值进去即可。默认预定义的参数是无法使用docker history看到的,如果要覆盖默认行为(即预定义参数无法通过docker history看到),可以在Dockerfile中定义一个同名参数覆盖即可,如:

    FROM ubuntu
    ARG HTTP_PROXY
    RUN echo "Hello World"
    

    【构建缓存的影响】

    ARG变量不会像ENV变量一样将其持久化到镜像中,但它也以类似的方式影响着构建缓存。如果Dockerfile中定义了和之前构建定义的不同ARG变量值,在第一阶段就会出现“cache miss”,尤其是在所有的RUN指令都是用了之前ARG定义的变量就会造成上述的缓存未命中。所有预定义的ARG变量并不会被缓存除非在Dockerfile中覆盖过(换而言之,所有Dokcerfile中使用ARG定义的变量都会被缓存)。下面是示例:

    # Dockerfile1
    FROM ubuntu
    ARG CONT_IMG_VER
    RUN echo $CONT_IMG_VER
    
    # Dockerfile2
    FROM ubuntu
    ARG CONT_IMG_VER
    RUN echo hello
    

    在构建时指定--build-arg CONT_IMG_VER=<value>,在上述2个Dockerfile的构建过程中,第3行会出现 cache miss 的提示(但我操作过程中进行的很顺利啊,并没有出现这个提示啊( ̄ ‘i  ̄;),我是谁,我在哪……)。

    2.4.15 ONBUILD

     当一个镜像A被用于另一个镜像B的基本镜像时(即FROM),ONBUILD指令用于向一个镜像中添加一个 trigger,以便可以在一段时间后执行。触发器将在下游(即当前构建的镜像B)生成的context中执行,只要它是在下游Dockerfile中FROM指令之后立即插入的。流程如下:

    1. 当看到ONBUILD时,构建器会向当前正在构建的镜像的 metadata 中添加 trigger,该指令不会影响当前构建;
    2. 在构建过程结束时,一系列的 trigger 将会存储到镜像的manifest中的OnBuild字段(一个数组对象)中,可以使用docker inspect查看这个字段;
    3. 然后这个镜像可能用作其他镜像构建的基础镜像,作为FROM指令的一部分,下游的构建器将会寻找ONBUILD trigger并按它们注册的顺序执行。如果其中某一个trigger执行失败了,FROM指令将被中止,从而导致构建失败;
    4. 触发器在执行后从最终镜像中清除,它们不是由“孙子”构建继承;

    下面是示例:

    [...]
    ONBUILD ADD . /app/src
    ONBUILD RUN /usr/local/bin/python-build --dir /app/src
    [...]
    

    注:

    • ONBUILD指令禁止嵌套使用,即类似于ONBUILD ONBUILD
    • ONBUILD指令可能不会触发FROMMAINTAINER指令(即尽量不要在ONBUILD指令中注册FROMMAINTAINER指令);
    2.4.16 STOPSIGNAL

    STOPSIGNAL指令用于设置系统发送到容器中、目的用于退出的命令,这个信号可以是内核的 syscall 表中有效的无符号数字(比如9),或格式为SIGNAME的信号名字(比如SIGKILL)。基本语法如下:

    STOPSIGNAL signal
    
    2.4.17 HEALTHCHECK

    HEALTHCHECK指令用于告诉Docker如何检测容器是否处于健康(工作)状态,有点类似于服务检测,这个功能可以检测到一些情况,如Web服务器卡在无限循环中,无法处理新连接,即使服务器进程仍在运行。当一个容器指定了一个健康检测,那该容器除了它本身的正常状态外,还会额外有一个“健康状态”health status(字段为health_status),健康状态初始值为starting,只有当健康检查(可以称作容器体检)通过了,它才会变成healthy,在连续次数(这个次数可以指定)的体检结果都不通过那 health status 将变成unhealthyHEALTHCHECK的基本语法为:

    # 形式1:在容器内运行指定命令进行容器体检
    HEALTHCHECK [OPTIONS] CMD command
    
    # 形式2:禁用从基映像继承的任何运行状况检查
    HEALTHCHECK NONE
    

    上述形式1中的OPTIONS可用选项有:

    • --interval=DURATION:表示容器体检的时间间隔,通常在容器首次进行体检(此时可以理解为delay)和体检失败后再次体检时用到,默认是30s;
    • --timeout=DURATION:表示容器体检的超时时间,一次体检时长超过此时间则认为本次体检失败,置为默认为30s;
    • --start-period=DURATION:表示容器的启动时长,在这个时间段内体检失败的结果不作数(即不算作retries),但是如果在这段时间内,容器体检成功了,从此刻(即使此刻还在start-period内)开始所有之后的检查就开始生效,retries开始统计,就认为容器已经启动成功,默认是0s;
    • --retries=N:表示容器体检重试的最大次数,即第一次体检失败并不意味着容器不健康,只有失败时尝试指定次数都是失败,该容器此时的health status才会置为unhealthy,默认是3次;

     形式1中CMD后可以是shell命令,如HEALTHCHECK CMD /bin/check-running,也可以是exec数组(和之前类似),这些命令的执行完成后的状态就可以推测出容器的health status,下面是多数命令的常用退出状态码:

    • 0:success - 容器体检健康,可以正常使用;
    • 1:unhealthy - 容器体检不健康,不能进行正常工作;
    • 2:reserved - 不要使用此退出代码;

    比如:

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

    从前至后,参数分别为:检测间隔5分钟,检测超时时间为3s,检测行为指令curl -f http://localhost/ || exit 1。为了调式失败的探测failing probes,使用stdout和stderr命令输出的内容(只能存储最近的4096byte)都将会存储到健康状态中,这些输出都可以使用docker inspect命令查看到。

    2.4.18 SHELL

    SHELL指令允许在shell形式中使用的默认shell可以被重写,Linux中默认的Shell为["/bin/sh", "-c"],win中默认的shell为["cmd", "/S", "/C"]。Dockerfile中的SHELL指令必须使用JSON格式。SHELL指令在win上是非常有用的,因为win上有两种常用的shell:cmdpowershell,包含可选的shell:sh

    SHELL指令可以出现多次,每个SHELL指令都重写之前的SHELL指令,并影响所有的后续指令,如:

    FROM microsoft/windowsservercore
    
    # Executed as cmd /S /C echo default
    RUN echo default
    
    # Executed as cmd /S /C powershell -command Write-Host default
    RUN powershell -command Write-Host default
    
    # Executed as powershell -command Write-Host hello
    SHELL ["powershell", "-command"]
    RUN Write-Host hello
    
    # Executed as cmd /S /C echo hello
    SHELL ["cmd", "/S", "/C"]
    RUN echo hello
    

    当在Dockerfile中的RUNCMDENTRYPOINT指令中使用shell形式会被SHELL指令影响。下面的示例是win上的通用模式,它可以使用SHELL指令简化,如:

    RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
    

    docker最终调用的命令为:

    cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
    

    但这样效率较低,因为存在一个不必要的命令处理器正在被调用(即shell),而且RUN指令以shell形式给出需要一个额外的powershell -command前缀。为了提高效率,有2种方式:

    1. 直接使用RUN指令的JSON形式:RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
    2. 使用SHELL指令,配合使用shell形式,对于win用户是更加是更加自然的语法,特别是结合使用escape指定编译指令时,如:
    # escape=`
    
    FROM microsoft/nanoserver
    SHELL ["powershell","-command"]
    RUN New-Item -ItemType Directory C:\Example
    ADD Execute-MyCmdlet.ps1 c:\example\
    RUN c:\example\Execute-MyCmdlet -sample 'hello world'
    

    SHELL指令还可以用于修改shell的执行方式,如在win上使用SHELL cmd /S /C /V:ON|OFF,可以修改延迟的环境变量扩展语义。

    附:

    下面是整章Dockerfile最终的综合示例:

    # 示例1
    # Nginx
    #
    # VERSION               0.0.1
    
    FROM      ubuntu
    LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0"
    RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
    
    
    # 示例2
    # Firefox over VNC
    #
    # VERSION               0.3
    
    FROM ubuntu
    
    # Install vnc, xvfb in order to create a 'fake' display and firefox
    RUN apt-get update && apt-get install -y x11vnc xvfb firefox
    RUN mkdir ~/.vnc
    # Setup a password
    RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
    # Autostart firefox (might not be the best way, but it does the trick)
    RUN bash -c 'echo "firefox" >> /.bashrc'
    
    EXPOSE 5900
    CMD    ["x11vnc", "-forever", "-usepw", "-create"]
    
    
    # 示例3
    # Multiple images example
    #
    # VERSION               0.1
    
    FROM ubuntu
    RUN echo foo > bar
    # Will output something like ===> 907ad6c2736f
    
    FROM ubuntu
    RUN echo moo > oink
    # Will output something like ===> 695d7793cbe4
    
    # You'll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
    
    展开全文
  • Dockerfile基础

    2020-04-23 21:08:16
    Dockerfile什么? 在Docker中创建镜像最常用的方式,就是使用DockerfileDockerfile是一个Docker镜像的描述文件,我们可以理解成火箭发射的A、B、C、D…的步骤。Dockerfile其内部包含了一条条的指令**,**每一条...

    Dockerfile基础

    Dockerfile是什么?

    在Docker中创建镜像最常用的方式,就是使用Dockerfile。Dockerfile是一个Docker镜像的描述文件,我们可以理解成火箭发射的A、B、C、D…的步骤。Dockerfile其内部包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

    Dockerfile结构大致分为四个部分:

    ​ (1)基础镜像信息

    (2)维护者信息

    (3)镜像操作指令

    (4)容器启动时执行指令。

    Dockerfile每行支持一条指令,每条指令可带多个参数,支持使用以#号开头的注释。

    Docker常用指令

    给大家放Docker File的一张我认为很有趣的全景图,让大家心里有点饺子

    mark

    接下来开吃了,别憋在心里了

    FROM:指定基础镜像

    指明构建的新镜像是来自于哪个基础镜像

    RUN:执行命令

    shell 格式: RUN <命令> ,RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
    exec 格式: RUN ["可执行文件", "参数1", "参数2"] 。run可以写多个,每一个指令都会建立一层,所以正确写法应该是↓
    RUN buildDeps='gcc libc6-dev make' \
             && apt-get update \
             && apt-get install -y $buildDeps \
             && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
             && 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
    

    COPY:复制文本

    COPY <源路径>... <目标路径>
    COPY ["<源路径1>",... "<目标路径>"]
    <源路径> 可以是多个、以及使用通配符,通配符规则满足Go的filepath.Match 规则,如:COPY hom* /mydir/    COPY hom?.txt /mydir/
    <目标路径>使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。
    

    ADD:高级复制文件

    ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
    <源路径> 可以是一个 URL ,下载后的文件权限自动设置为 600 。
    

    CMD:容器启动命令

    shell 格式: CMD <命令>
    exec 格式: CMD ["可执行文件", "参数1", "参数2"...]
    
    CMD ["nginx", "-g", "daemon off;"]
    

    ENTRYPOINT:入口点

    用例一:使用CMD要在运行时重新写命令才能追加运行参数,ENTRYPOINT则可以运行时接受新参数。
    示例:
    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" ]
    
    追加-i参数
    $ docker run myip -i
    ......
    当前 IP61.148.226.66 
    

    ENV:设置环境变量

    ENV <key> <value>
    ENV <key1>=<value1> <key2>=<value2>...
    示例:
    ENV VERSION=1.0 DEBUG=on NAME="Happy Feet"
    

    ARG:构建参数

    与ENV不同的是,容器运行时不会存在这些环境变量。
    可以用 docker build --build-arg <参数名>=<值> 来覆盖。

    VOLUME:定义匿名卷

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

    EXPOSE:暴露端口

    EXPOSE <端口1> [<端口2>...] 
    EXPOSE :EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
    

    WORKDIR:指定工作目录

    WORKDIR <工作目录路径>
    RUN cd /app
    RUN echo "hello" > world.txt
    两次run不在一个环境内,可以使用WORKDIR。
    

    USER:指定当前用户

    这个用户必须是事先建立好的,否则无法切换。
    USER <用户名>
    

    HEALTHCHECK:健康检查

    HEALTHCHECK [选项] CMD <命令> :设置检查容器健康状况的命令
    HEALTHCHECK NONE :如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
    
    HEALTHCHECK 支持下列选项:
        --interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
        --timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
        --retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3次。
    
    示例
    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
    

    小结:Dockerfile的内容相比它庞大的本身,相对来说算是内容较少的的一部分了。8过,对于某人来说,他们两也许就是太古巨兽与洪荒神兽的区别罢了喊声奥利干继续看就是了,忘了的时候来看看我这博客,既给大家涨了知识又给我涨了访问量岂不美哉!奥利给军团,冲啊~

    mark

    展开全文
  • Dockerfile入门教程

    万次阅读 多人点赞 2020-06-20 23:51:01
    dockerfile入门教程
  • Dockerfile解析

    2021-01-03 15:59:56
    Dockerfile解析镜像的创建Dockerfile里应该写什么简单案例相关命令图解构建过程Dockerfile指令总结指令比喻 镜像的创建 镜像的创建可以分为两种方式: 镜像提交,docker commit的方式。docker commit命令可以把容器...
  • Dockerfile是一个文本文件,记录了镜像构建的所有步骤。 饭提示:学习Dockerfile构建镜像,就是在学习Dockerfile文件构建的命令+shell脚本语句 Dockerfile简单介绍  Docker可以使用Dockerfile的内容来自动构建...
  • Dockerfile简介

    2020-03-31 17:14:36
    什么是Dockerfile Dockerfile类似于我们学习过的脚本,将我们在上面学到的docker镜像,使用自动化的方式实现出来。 Dockerfile的作用 找一个镜像:Ubuntu 创建一个容器:docker run ubuntu 进入容器:docker exec -...
  • 参考:1.6 Docker与微服务-使用Dockerfile构建Docker镜像例如: ADD microservice-discovery-eureka-0.0.1-SNAPSHOT.jar app.jar RUN bash -c ‘touch /app.jar’ 它的作用等同于拷贝文件到容器,也可以直接写成...
  • RUN 你想让它啥(在命令前面加上RUN即可) ADD 给它点创业资金(COPY文件,会自动解压) WORKDIR 我是cd,今天刚化了妆(设置当前工作目录) VOLUME 给它一个存放行李的地方(设置卷,挂载主机目录) EXPOSE 它要...
  • Dockerfile构建镜像

    2017-11-02 15:29:00
    本节内容: Dockerfile介绍 Dockerfile指令简单介绍 ...dockerfile提供了一种基于DSL语法的指令来构建镜像,通过代码化,镜像构建过程一目了然,我们能看出镜像构建的每一步都在干什么。 若要共享镜像,我们只...
  • Dockerfile创建镜像

    2019-12-17 14:32:23
    RUN 你让他干什么(在命令前面加上RUN) ADD 往他肚子里放点文件(COPY文件,会自动解压) WORKDIR 我是cd,(就是cd命令) VOLUME 给我一个存放行李的地方(目录挂载) EXPOSE 我要打开的门是什么(端口) ...
  • Dockerfile 之 ENTRYPOINT

    千次阅读 2020-02-29 12:27:20
    下面的Dockerfile展示了如何使用ENTRYPOINT在前台运行Apache(即, as PID 1): FROM debian:stable RUN apt-get update && apt-get install -y --force-yes apache2 EXPOSE 80 443 VOLUME ["/var/www", "/var/...
  • Dockerfile的简介

    2019-12-20 09:33:43
    什么是DockerfileDockerfile类似于我们学习过的脚本,将我们在上面学到的docker镜像,使用自动化的方式实现出来。Dockerfile的作用: 1、找一个镜像: ubuntu ​ 2、创建一个容器: docker run ubuntu ​ 3、...
  • Dockerfile最详细介绍

    2021-03-31 21:17:04
    什么是 DockerfileDockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。 使用 Dockerfile 定制镜像 这里仅讲解如何运行 Dockerfile 文件来定制一个镜像,具体 Dockerfile ...
  • Dockerfile 基础介绍

    2020-09-22 11:56:13
    本篇,我来为你介绍 Dockerfile 带你理解 Dockerfile 中的重点知识,方便你自己定义构建镜像的行为。下面我们一起进入本篇的学习。 Dockerfile 基本格式 在前面的内容中,我有写过几个 Dockerfile,但是并没有对它...
  • Dockerfile命令和实践

    2017-09-13 23:34:18
    2, 通过命令docker build的方式可以预先准备一个dockerfile的脚本,脚本里可以很多事情,更灵活,文件方式也更方便共享和传播。 本文主要学习下Dockerfile的规范,还是先罗列语法和基本命令,再应用于实战。
  • Dockerfile常用指令详解

    千次阅读 2018-04-27 13:28:05
    有些人喜欢用docker commit 命令去打包镜像,这样是不好的,首先commit出来的镜像比你使用Dockerfile构建出来的体积大,而且commit出来的镜像属于黑盒镜像,除了制作者,谁都不知道你在里面什么,...
  • RUN :你想让dockerfile干什么前面就加RUN5.ADD: 往里面添加文件(copy文件。如果是压缩包,会自动解压)6.WORKDIR :相当于cd7.EXPOSE :映射端口8.ENV:定义环境变量9.CMD:运行10.然后进行运行,dock...
  • Flink Dockerfile 走读

    2019-07-20 10:25:55
    文章目录1 Overview2 Dockerfile3 Entrypoint 1 Overview 关于 Flink 的 Docker 相关的配置,可以参考源码这个目录。 /path/to/flink/flink-container/docker ├── Dockerfile // Dockerfile ├── README.md // ...
  • 创建 Dockerfile 文件 在一个空白目录中,建立一个文本文件,并命名为 Dockerfile mkdir docker cd docker mkdir nginx cd nginx touch Dockerfile Dockerfile 文件的内容如下 FROM nginx RUN echo '<h1>...
  • Dockerfile的使用详解

    2019-09-11 13:06:41
    什么是Dockerfile Dockerfile类似于我们学习过的脚本,将我们在上面学到的docker镜像,使用自动化的方式实现出来。 Dockerfile的作用 1、找一个镜像: ubuntu 2、创建一个容器: docker run ubuntu 3、进入容器: ...
  • 本文只有操作 ,原理理论百度。...Dockerfile构建 docker build /opt/nginx/Dockerfile 怎么编写DockerfileDockerfile 基础镜像信息 维护者信息 镜像操作者指令 容器启动时执行指令 FROM :它的妈
  • Dockerfile学习入门

    2020-05-23 12:07:00
    一、带着问题学Dockerfile 1、疑问 我们都知道从远程仓库可以pull一个tomcat等镜像下来,然后docker run启动容器,然后docker exec -it 容器id /bin/bash进入容器,往webapps下仍我们的程序。等等这一系列操作,都...
  • 详细说说Dockerfile

    2020-05-24 09:50:37
    一、 带着问题学Dockerfile 1、疑问 我们都知道从远程仓库可以pull一个tomcat等镜像下来,然后docker run启动容器,然后docker exec -it 容器id /bin/bash进入容器,往webapps下仍我们的程序。等等这一系列操作,...
  • 在该目录下的操作的双向影响的 在这里D:/dev/test要写成/d/dev/test的形式 伪终端启动 接下来说 -it 是嘛的 -i:以交互模式运行容器,通常与 -t 同时使用 -t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;...
  • Dockerfile的使用 Dockerfile简介 Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。 基础知识 每个命令都是大写 保留...
  • 快速掌握dockerfile

    2016-08-05 21:15:12
    本文引用至: dockerfile docker 之所以这么牛逼, 一是在于他强大的生态环境, 以及,他container和writable layer 的新颖的概念. docker镜像的简单剖析 docker的images,我们可以理解为积木, 一层一层往上搭, 最后完成...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,744
精华内容 1,097
关键字:

dockerfile是干什么的