Dockerfile参考(15) – ARG指令定义由用户在命令行赋值的变量

格式:

  1. ARG <name>[=<default value>]

ARG指令定义了一个变量,能让用户可以在构建期间使用docker build命令和其参数–build-arg =对这个变量赋值。如果用户指定了一个构建参数没有定义在Dockerfile的话,将输出错误。

  1. One or more build-args were not consumed, failing build.

Dockerfile作者可以指定ARG一次定义一个变量,或者指定ARG多次定义多个变量。例如:

  1. FROM busybox
  2. ARG user1
  3. ARG buildno

Dockerfile作者也可以为这个变量指定一个默认值:

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

如果ARG指定了一个默认值并且在构建期间没有传递值过去,那么就使用默认值。
ARG变量定义从在Dockerfile定义的行生效,而不是从在命令行参数的使用或其它地方。
例如下面的Dockerfile:

  1. 1 FROM busybox
  2. 2 USER ${user:-some_user}
  3. 3 ARG user
  4. 4 USER $user

使用如下命令构建:

  1. $ docker build –build-arg user=what_user Dockerfile

第2行的USER的值为some_user,因为user变量在第3行才定义。第4行的USER值为what_user,因为user变量在它之前定义了并且在命令行给user变量赋值为what_user。在ARG指令定义变量之前引用这个变量的得,都会得到空值。

警告:不推荐在构建期间的命令行传递密码如github密钥,用户凭证等数据。构建期间设置的变量可以通过docker history命令来查看。

可以使用ARG或ENV指令指定可用于RUN指令的变量。使用ENV定义的环境变量始终会覆盖同一名称的ARG指令定义的变量。例如:

  1. 1 FROM ubuntu
  2. 2 ARG CONT_IMG_VER
  3. 3 ENV CONT_IMG_VER v1.0.0
  4. 4 RUN echo $CONT_IMG_VER

然后使用如下命令构建镜像:

  1. $ docker build –build-arg CONT_IMG_VER=v2.0.1 Dockerfile

在这种情况中,RUN指令解析CONT_IMG_VER变量的值为v1.0.0而不是ARG设置并由用户传递过来的v2.0.1。
使用上面的示例,但不一样的ENV定义可以在ARG和ENV指令之前创建更有用的交互:

  1. 1 FROM ubuntu
  2. 2 ARG CONT_IMG_VER
  3. 3 ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
  4. 4 RUN echo $CONT_IMG_VER

不像ARG指令,ENV的值始终会存在于镜像中。使用如下不带–build-arg构建镜像:

  1. $ docker build Dockerfile

使用这个Dockerfile示例,CONT_IMG_VER仍然会存在于镜像中,不过它的值会是默认的v1.0.0,当然你也可以在命令行中更改它。
Docker有一组预设置的ARG变量,你不需要在Dockerfile中定义就能够使用它。

  • HTTP_PROXY
  • http_proxy
  • HTTPS_PROXY
  • https_proxy
  • FTP_PROXY
  • ftp_proxy
  • NO_PROXY
  • no_proxy
  • 要设置这些变量,可以在命令行赋值

    1. –build-arg <varname>=<value>

    ARG对构建缓存的影响

    ARG变量不像ENV变量始终存在于镜像中。不过ARG变量会以类似的方式对构建缓存产生影响。如果Dockerfile中定义的ARG变量的值与之前定义的变量值不一样,那么就有可能产生“cache miss”。比如RUN指令使用ARG定义的变量时,ARG变量的值变了之后,就会导致缓存失效。

    Dockerfile参考(14) – WORKDIR设置RUN CMD ENTRYPOINT等指令的工作目录

    格式:

    1. WORKDIR /path/to/workdir

    WORKDIR指令设置Dockerfile中的任何RUN, CMD, ENTRYPOINT, COPY和ADD指令的工作目录。如果WORKDIR指定的目录不存在,即使随后的指令没有用到这个目录,都会创建。
    单个Dockerfile可以使用多次WORKDIR。如果提供一个相对路径,当前的工作目录将与上个WORKDIR指令相关,如:

    1. WORKDIR /a
    2. WORKDIR b
    3. WORKDIR c
    4. RUN pwd

    pwd命令的输出为/a/b/c。
    WORKDIR可以解析之前由ENV设置的环境变量。如:

    1. ENV DIRPATH /path
    2. WORKDIR $DIRPATH/$DIRNAME
    3. RUN pwd

    pwd命令输出为/path/$DIRNAME。

    Dockerfile参考(13) – VOLUME创建数据卷和USER指定容器内运行命令的用户

    VOLUME

    1. VOLUME ["/data"]

    VOLUME指令创建一个指定名称的挂载点,并设置此挂载点为本地主机或其它容器的外部挂载数据卷。VOLUME的值可以是一个JSON数组,如VOLUME [“/var/log/”],或者多个参数的纯字符串,如VOLUME /var/log或VOLUME /var/log /var/db。
    docker run把在base镜像内指定路径已存在的数据复制到这个新创建的数据卷。例如:

    1. FROM ubuntu
    2. RUN mkdir /myvol
    3. RUN echo "hello world" > /myvol/greeting
    4. VOLUME /myvol

    这个Dockerfile使得docker run创建一个新的挂载点/myvol,并复制greeting文件到新创建的数据卷。

    注意:如果在volume声明之后的任何指令对其挂载点更改了数据,这些更改将会撤消。

    USER

    1. USER daemon

    USER指令设置运行镜像时使用的用户名或UID,以及Dockerfile中的任何RUN,CMD和ENTRYPOINT指令。

    Dockerfile参考(12) – ENTRYPOINT配置创建容器后执行的容器命令

    ENTRYPOINT有两种形式:

  • ENTRYPOINT [“executable”, “param1”, “param2”] [exec形式,首选]
  • ENTRYPOINT command param1 param2 [shell形式]
  • ENTRYPOINT指令用来配置创建容器时执行的容器命令。
    例如,下面的示例将以默认页启动nginx,在80端口监听:

    1. docker run -i -t –rm -p 80:80 nginx

    docker run [image]的命令行参数会附加到exec形式ENTRYPOINT所有元素的后面,且会覆盖使用CMD指定的所有元素。这允许命令行参数能够传递到entry point。如docker run [image] -d会传递-d参数到entry point。你可以你使用docker run –entrypoint标志来覆盖ENTRYPOINT指令。
    shell形式的ENTRYPOINT能够阻止使用任何CMD或run命令行参数,不过不好的地方是ENTRYPOINT将以/bin/sh -c的子命令执行,且ENTRYPOINT收不到信号。意味着执行的命令的PID不是容器的PID 1 – 收不到来自主机的Unix信号 – 所以无法使用docker stop [container]停止容器。
    仅是Dockerfile的最后一个ENTRYPOINT指令起作用。

    exec形式ENTRYPOINT示例

    你可以使用ENTRYPOINT的exec形式设置稳定的默认命令和参数,然后使用同样形式的CMD设置额外的可以修改的默认参数。

    1. FROM ubuntu
    2. ENTRYPOINT ["top", "-b"]
    3. CMD ["-c"]

    当你运行容器,你会看到top是唯一的进程:

    1. $ docker run -it –rm –name test  top -H
    2. top – 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
    3. Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
    4. %Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    5. KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
    6. KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem
    7.  
    8.   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    9.     1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

    我们再看到top的具体参数:

    1. $ docker exec -it test ps aux
    2. USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    3. root         1  2.6  0.1  19752  2352 ?        Ss+  08:24   0:00 top -b -H
    4. root         7  0.0  0.1  15572  2164 ?        R+   08:25   0:00 ps aux

    并且可以使用docker stop test来停止这个容器。
    下面的Dockerfile显示了使用ENTRYPOINT来在前台运行Apache[作为PID 1运行]:

    1. FROM debian:stable
    2. RUN apt-get update && apt-get install -y –force-yes apache2
    3. EXPOSE 80 443
    4. VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
    5. ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

    如果你需要为单个可执行程序编辑一个启动脚本,你可以使用exec和gosu命令来确保最终的执行程序能收到Unix信号:

    1. #!/bin/bash
    2. set -e
    3.  
    4. if [ "$1" = ‘postgres’ ]; then
    5.     chown -R postgres "$PGDATA"
    6.  
    7.     if [ -z "$(ls -A "$PGDATA")" ]; then
    8.         gosu postgres initdb
    9.     fi
    10.  
    11.     exec gosu postgres "$@"
    12. fi
    13.  
    14. exec "$@"

    最后,如果你需要在关闭或协调多个可执行程序时做些额外的清理工作,你需要确保ENTRPOINT脚本能够收到Unix信号,捕获它们并做些额外的工作:

    1. #!/bin/sh
    2. # Note: I’ve written this using sh so it works in the busybox container too
    3.  
    4. # USE the trap if you need to also do manual cleanup after the service is stopped,
    5. #     or need to start multiple services in the one container
    6. trap "echo TRAPed signal" HUP INT QUIT TERM
    7.  
    8. # start service in background here
    9. /usr/sbin/apachectl start
    10.  
    11. echo "[hit enter key to exit] or run ‘docker stop <container>’"
    12. read
    13.  
    14. # stop service and clean up here
    15. echo "stopping apache"
    16. /usr/sbin/apachectl stop
    17.  
    18. echo "exited $0"

    如果使用docker run -it –rm -p 80:80 –name test apache运行镜像,可以用docker exec或docker top来检查容器进程,然后请求脚本停止Apache:

    1. $ docker exec -it test ps aux
    2. USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    3. root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
    4. root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
    5. www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
    6. www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
    7. root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux
    8. $ docker top test
    9. PID                 USER                COMMAND
    10. 10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
    11. 10054               root                /usr/sbin/apache2 -k start
    12. 10055               33                  /usr/sbin/apache2 -k start
    13. 10056               33                  /usr/sbin/apache2 -k start
    14. $ /usr/bin/time docker stop test
    15. test
    16. real    0m 0.27s
    17. user    0m 0.03s
    18. sys 0m 0.03s

    注意:你可以使用–entrypoint来覆盖ENTRPOINT的设置,不过仅可以二进制到exec,如/usr/sbin/apache2 -k start[不仅调用sh -c执行]

    shell形式ENTRYPOINT示例

    可以为ENTRYPOINT指定一个纯字符串,它将运行在/bin/sh -c。这种形式将使用shell处理shell环境变量替换,将忽略任何的CMD或docker run命令行参数。为了确保docker stop能够正确发送信号到ENTRPOINT的可执行程序,记得使用exec执行:

    1. FROM ubuntu
    2. ENTRYPOINT exec top -b

    运行这个镜像后,将会看到这个进程的PID为1:

    1. $ docker run -it –rm –name test top
    2. Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
    3. CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
    4. Load average: 0.08 0.03 0.05 2/98 6
    5.   PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    6.     1     0 root     R     3164   0%   0% top -b

    且可以使用docker stop停止进程:

    1. $ /usr/bin/time docker stop test
    2. test
    3. real    0m 0.20s
    4. user    0m 0.02s
    5. sys 0m 0.04s

    如果忘记使用exec执行命令:

    1. FROM ubuntu
    2. ENTRYPOINT top -b
    3. CMD –ignored-param1

    然后运行:

    1. $ docker run -it –name test top –ignored-param2
    2. Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
    3. CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
    4. Load average: 0.01 0.02 0.05 2/101 7
    5.   PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    6.     1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
    7.     7     1 root     R     3164   0%   0% top -b

    可以看到top进程的PID为是1了。
    并且使用docker stop test不能停止进程:

    1. $ docker exec -it test ps aux
    2. PID   USER     COMMAND
    3.     1 root     /bin/sh -c top -b cmd cmd2
    4.     7 root     top -b
    5.     8 root     ps aux
    6. $ /usr/bin/time docker stop test
    7. test
    8. real    0m 10.19s
    9. user    0m 0.04s
    10. sys 0m 0.03s

    ENTRYPOINT和CMD使用建议

    1.Dockerfile应该至少指定一个CMD或ENTRYPOINT指令。
    2.当使用容器作为可执行程序时,应该定义ENTRYPOINT。
    3.CMD应该用来设置ENTRYPOINT的默认参数。
    4.当运行容器带有额外参数时,将会覆盖CMD的参数。

    Dockerfile参考(11) – ADD COPY添加文件和目录到镜像

    ADD有两种形式:

  • ADD <src>… <dest>
  • ADD [“<src>”,… “<dest>”] [这种形式通常用于包含空白字符的路径]
  • ADD指令从<src>复制新的文件,目录或远程文件URLs并添加到镜像文件系统的<dest>路径。
    可以指定多个<src>资源,这些资源必须是相对于正在构建的源目录(构建的上下文)。
    每个<src>可以包含通配符并且使用Go的filepath.Match规则匹配。例如:

    1. ADD hom* /mydir/        # adds all files starting with "hom"
    2. ADD hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

    <dest>是一个绝对路径,或者是WORKDIR的相对路径。

    1. ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
    2. ADD test /absoluteDir/         # adds "test" to /absoluteDir/

    所有新创建的文件和目录的UID和GID都是0.
    当<src>为一个远程文件URL时,新创建的文件和目录权限为600。如果获取的远程文件的HTTP有一个Last-Modified响应头,那么这个响应头的时间戳将设置为新创建的文件和目录的mtime。不过,在ADD期间像其它任意文件的处理过程中,mtime不能决定文件是否已经更改和缓存是否应该更新。

    注意:如果通过标准输入传递Dockerfile构建镜像[docker build – < somefile],那么就没有构建上下文,所以Dockerfile中的ADD指令的<src>只能是远程URL。你也可以通过标准输入传递一个压缩文件:(docker build – < archive.tar.gz),在这个压缩文件根目录的Dockerfile和压缩文件的其它文件将作为构建的上下文使用。

    如果远程URL需要验证,你需要使用RUN wget,RUN curl或容器内的其它工具下载文件,因为ADD指令不支持验证功能。

    如果<src>的文件已经更改,那么涉及到这个路径的第一个ADD指令将使Dockerfile后面的所有指令缓存失效。其中RUN指令的缓存也将失效。

    ADD遵守如下规则:

  • <src>路径必须在构建上下文内;你不能ADD ../something /something,因为docker build的第一步已经把上下文目录和子目录发送到docker daemon了。
  • 如果<src>是一个远程URL,且<dest>路径后没有跟斜杠,那么这个文件从远程URL下载并复制到<dest>
  • 如果<src>是一个远程URL,且<dest>路径后有斜杠,那么filename从URL获取并把文件下载到<dest>/<filename>。例如,ADD http://example.com/foobar /将创建文件/foobar。远程URL是包括路径的URL,这样docker才能获取文件名,像http://example.com是不行的。
  • 如果<src>是一个目录,目录的所有内容都将复制,包括文件系统元数据。
  • 注意:不会复制目录本身,只是它的内容。

  • 如果<src>是一个本地的可识别的tar压缩文件[如gzip,bzip2或xz],那么将在容器内解压为目录。远程URL的压缩文件将不会解压。
  • 如果<src>是多个资源,不管是直接指定或使用通配符,那么<dest>必须是一个目录,并且已经以斜杠/结尾。
  • 如果<dest>不以斜杠/结尾,将视其为一个普通文件,<src>的内容将写到这个文件。
  • 如果<dest>不存在,则会与其路径中的所有缺少的目录一起创建。
  • 注意:ADD与COPY唯一的区别就是COPY添加本地压缩文件时不会自动解压到容器。对于其它不需要自动解压文件的情况,你应该始终使用COPY。

    Dockerfile参考(10) – EXPOSE暴露端口和ENV设置环境变量

    EXPOSE

    1. EXPOSE <port> [<port>…]

    EXPOSE指令通知Docker,容器运行期间监听指定的网络端口。EXPOSE不会自动使主机的容器端口可访问。要设置监听EXPOSE指定的端口,必须使用-p参数来发布一组端口或-P参数来发布所有EXPOSE的端口。你可以暴露容器的一个端口并在外部发布另一个不同的端口。比如发布容器的80端口到主机的8080端口。

    ENV

    1. ENV <key> <value>
    2. ENV <key>=<value> …

    ENV指令设置环境变量的值为。这个值可以用在之后的Dockerfile命令中并替换命令中所有的环境变量。
    ENV指令有两种形式,第一种是 ,将设置单个变量为一个值。第一个空格之后的整个字符将设置为这个变量的值 – 包括空格和引号等字符。
    第二种形式允许同时设置多个变量。设置这种形式使用了等于号,第一种是没有使用的。像命令行解析,引号和反斜杠可以用来包括空格。
    例如:

    1. ENV myName="John Doe" myDog=Rex The Dog
    2.     myCat=fluffy

    和:

    1. ENV myName John Doe
    2. ENV myDog Rex The Dog
    3. ENV myCat fluffy

    虽然这两种形式得到的结果一样,但推荐第一种,因为它只生成了一个缓存层。
    使用ENV设置环境变量将永久存在于从该镜像运行的容器中。你可以使用docker inspect查看这些值,也可以使用

    1. docker run –env <key>=<value>

    更改它们。

    注意:环境变量的存在可能引起意外的副作用。例如,设置ENV DEBIAN_FRONTEND noninteractive可能会使在基于Debian镜像的apt-get用户感到困惑。要在单个命令中使用变量,可以使用

    1. RUN <key>=<value> <command>

    Dockerfile参考(9) – LABEL添加元数据到镜像

    格式:

    1. LABEL <key>=<value> <key>=<value> <key>=<value> …

    LABEL指令添加元数据到一个镜像。一个LABEL是一个键值对。要在LABEL值中包含空格,使用双引号和反斜杠,就像在命令行解析中一样。一些可用的示例:

    1. LABEL "com.example.vendor"="ACME Incorporated"
    2. LABEL com.example.label-with-value="foo"
    3. LABEL version="1.0"
    4. LABEL description="This text illustrates
    5. that label-values can span multiple lines."

    一个镜像可以有多个label。要指定多个labels,Docker推荐尽可能地把多个labels合并到一个LABEL指令中去。每一个LABEL指令会生成一个新的镜像层,如果你使用多个label,将导致构建出一个低效的镜像。这个示例只生成单个镜像层。

    1. LABEL multi.label1="value1" multi.label2="value2" other="value3"

    上面的示例可以重写为:

    1. LABEL multi.label1="value1"
    2.       multi.label2="value2"
    3.       other="value3"

    label是累积的,包括FROM镜像的lable。如果Docker遇到一个label/key已经存在,那么新的值将覆盖这个label/key。
    要查看一个镜像的label,使用docker inspect命令。

    1. "Labels": {
    2.     "com.example.vendor": "ACME Incorporated"
    3.     "com.example.label-with-value": "foo",
    4.     "version": "1.0",
    5.     "description": "This text illustrates that label-values can span multiple lines.",
    6.     "multi.label1": "value1",
    7.     "multi.label2": "value2",
    8.     "other": "value3"
    9. },

    Dockerfile参考(8) – CMD设置运行容器时执行的命令

    CMD指令有三种形式:

  • CMD [“executable”,”param1″,”param2″] [exec形式,这是首选形式]
  • CMD [“param1″,”param2”] [作为ENTRYPIOINT的默认参数]
  • CMD command param1 param2 [shell形式]
  • Dockerfile只能使用一个CMD指令。如果你使用了多个CMD那么Docker仅使用最后一个。
    CMD的主要作用是为执行容器提供默认值。这些默认值可以包括一个可执行程序,或省略可执行程序(这种情况下需要指定一个ENTRYPOINT指令)。

    注意:如果CMD用来提供ENTRYPOINT的默认参数,那么CMD和ENTRYPOINT指令应该使用JSON数组的格式。

    注意:exec形式使用了JSON数组,意味着字符外使用双引号而不是单引号。

    不论使用是的shell或exec格式,CMD指令设置了当运行镜像时要执行的命令。
    如果使用CMD的shell形式,那么将在/bin/sh -c执行:

    1. FROM ubuntu
    2. CMD echo "This is a test." | wc –

    如果你想不调用shell运行你的,那么你必须以JSON数组表示你的命令并给出这个命令的完整路径。这个数组形式是CMD的首先格式。额外的参数必须单独地使用一个数组的字符串表示:

    1. FROM ubuntu
    2. CMD ["/usr/bin/wc","–help"]

    如果你想每次容器都是执行相同的执行程序,那么你应该考虑ENTRYPOINT和CMD一起使用。
    如果用户在docker run指定参数,那么将会覆盖CMD指定的默认参数。

    注意:不要把RUN和CMD搞混了。RUN实际上是在构建镜像时执行命令并提交执行结果到镜像;而CMD在构建期间不会执行任何命令,只是为镜像预先设置运行时容器时运行的命令或参数。

    Dockerfile参考(7) – RUN执行命令指令

    RUN指令有两种形式:

  • RUN [shell形式,运行在shell的命令,默认是Linux上的/bin/sh -c或windows的cmd /S /C]
  • RUN [“executable”, “param1”, “param2”][exec形式]
  • RUN指令将在当前镜像层上面的一个新数据层执行命令并提交其结果。这个新提交的镜像层将用于Dockerfile的下一步。
    分层RUN指令和生成提交符合Docker的核心概念,其中提交成本低,可以从镜像历史中的任何点创建容器,就像源代码控制一样。
    exec形式避免了shell字符的模糊处理,并且可以在没有特定shell的base镜像上使用RUN指令。
    shell形式中默认的shell可以使用SHELL命令更改。
    在shell形式中你可以使用反斜杠在下一行继续这个RUN指令。例如下面两行:

    1. RUN /bin/bash -c ‘source $HOME/.bashrc;
    2. echo $HOME’

    两行相当于:

    1. RUN /bin/bash -c ‘source $HOME/.bashrc; echo $HOME’

    注意:要在exec形式中使用不同的shell,而不是/bin/sh,传递想用的shell即可,如,[“/bin/bash”, “-c”, “echo hello”]

    注意:exec形式是接一个JSON数组,意味着在单词之外使用双引号而不是单引号。

    注意:不像shell形式,exec形式不会调用一个shell再执行命令。意味着常规shell处理不会发生。例如,RUN [ “echo”, “$HOME” ]不会替换$HOME为家目录。如果你想处理此情况,可以直接使用shell形式或直接执行一个shell。如RUN [ “sh”, “-c”, “echo $HOME” ]。

    注意:在JSON格式中,有必要转义反斜杠,特别是windows中使用反斜杠作为路径分隔符的情况。[“c:windowssystem32tasklist.exe”] 会视为shell形式,因为这不是一个有效的JSON格式,正确的语法是RUN [“c:\windows\system32\tasklist.exe”]。

    RUN指令的缓存不会在下一次构建镜像时自动失效。一个指令的缓存如RUN apt-get dist-upgrade -y会在下一次构建中重用。可以使用–no-cache参数来使RUN指令的缓存失效,例如docker build –no-cache。

    Dockerfile参考(6) – FROM和MAINTAINER指令

    FROM

    1. FROM <image>

    1. FROM <image>:<tag>

    1. FROM <image>@<digest>

    FROM指令为随后的指令设置一个Base Image。因此,一个有效的Dockerfile的第一个指令必须是FROM。镜像可以是任意有效的镜像 – 这个很容易从公共仓库拉取一个镜像。

  • FROM必须是Dockerfile中的首个非注释指令。
  • FROM可以在单个Dockerfile中出现多次,这样可以创建多个镜像。只需记下在每个新的FROM命令之前由提交输出的最后一个图像ID。
  • tag或digest值是可选的。如果都不指定,那么默认是latest。如果找不到tag的值将返回错误。
  • MAINTAINER

    1. MAINTAINER <name>

    MAINTAINER指令允许你设置生成这个镜像的作者。