dockerfile中指令详解

190 阅读3分钟

1.基本指令 FROM

FROM 第一个指令必须是FROM; FROM <IMAGE>[:<TAG>] 如果依赖多个镜像,可以使用多个FROM 

2 基本指令 MAINTAINER

MAINTAINER <NAME> 指定维护者信息 

3.基本指令 ADD

 ADD <src> <dest> 复制src到容器中的dest位置; 
 src可以是一个相对路径,可以是一个URL,可以是一个tar文件
  1、如果源路径是个文件,且目标路径是以 / 结尾, 
        则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下。
        如果目标路径不存在,则会自动创建目标路径。 
  2、如果源路径是个文件,且目标路径是不是以 / 结尾,
        则docker会把目标路径当作一个文件。 
        如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件; 
        如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。 
        如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 
        注意,这种情况下,最好显示的以 / 结尾,以避免混淆。 
  3、如果源路径是个目录,且目标路径不存在
        则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来。
        如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。 
  4、如果源文件是个归档文件(压缩文件),则docker会自动帮解压。 

4. 基本指令 COPY

COPY 复制本机src到容器的dest位置; src同上; 推荐使用copy

5 基本指令 VOLUME 参考文档

  VOLUME ["/data"] 创建一个挂载点, 一般用来存放数据库和需保持的数据
 (1)容器中的进程操作的数据持久化都是保存在容器的可写层上。 一旦容器删除后,这些数据就没了,除非我们人工备份下来(或者基于容器创建新的镜像)。 VOLUME以让容器进程持久化的数据保存在主机上,这样即使容器删除了,数据还在。 
 (2)当我们在开发一个web应用时,开发环境是在主机本地,但运行测试环境是放在docker容器上。 这样的话,我在主机上修改文件(如html,js等)后,需要再同步到容器中。这显然比较麻烦。 
 (3)多个容器运行一组相关联的服务,如何数据共享 
 一、通过docker run命令 
 1、运行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash  
    其中的 -v 标记 在容器中设置了一个挂载点 /data(就是容器中的一个目录),
        并将主机上的 /home/xqh/myimage 目录中的内容关联到 /data下。
    这样在容器中对/data目录下的操作,还是在主机上对/home/xqh/myimage的操作,都是完全实时同步的,因为这两个目录实际都是指向主机目录。
 2、运行命令:docker run --name test1 -it -v /data ubuntu /bin/bash  
     上面-v的标记只设置了容器的挂载点,并没有指定关联的主机目录。
     这时docker会自动绑定主机上的一个目录。
     通过docker inspect 命令可以查看到。 
 xqh@ubuntu:~/myimage$ docker inspect test1 
 [ 
 { 
    "Id": "1fd6c2c4bc545163d8c5c5b02d60052ea41900a781a82c20a8f02059cb82c30c", ............................. 
    "Mounts": [ 
     { 
     "Name": "0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01",
     "Source": "/var/lib/docker/volumes/0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01/_data",
     "Destination": "/data",
     "Driver": "local", 
     "Mode": "", 
     "RW": true 
     }],
      ........................... 
 }]
 上面 Mounts下的每条信息记录了容器上一个挂载点的信息,
 "Destination" 值是容器的挂载点,
 "Source"值是对应的主机目录。 
 可以看出这种方式对应的主机目录是自动创建的,其目的不是让在主机上修改,而是让多个容器共享 
 二、通过dockerfile创建挂载点 上面介绍的通过docker run命令的-v标识创建的挂载点只能对创建的容器有效。 
 通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。 
 还有一个区别是,通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。 
  
  #test
  FROM ubuntu 
  MAINTAINER hello1 
  VOLUME ["/data1","/data2"] 
  
  上面的dockfile文件通过VOLUME指令指定了两个挂载点 /data1 和 /data2.
  我们通过docker inspect 查看通过该dockerfile创建的镜像生成的容器,可以看到如下信息 
  "Mounts": [ 
    { 
    "Name": "d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21", 
    "Source": "/var/lib/docker/volumes/d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21/_data", 
    "Destination": "/data1", "Driver": "local", "Mode": "", "RW": true 
    }, 
    { 
    "Name": "6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36", 
    "Source": "/var/lib/docker/volumes/6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36/_data", 
    "Destination": "/data2", "Driver": "local", "Mode": "", "RW": true 
    } 
 ] 
 三、容器共享卷(挂载点) 
 docker run --name test1 -it myimage /bin/bash 
 上面命令中的 myimage是用前面的dockerfile文件构建的镜像。 
 这样容器test1就有了 /data1 和 /data2两个挂载点。 
 下面我们创建另一个容器可以和test1共享 /data1 和 /data2卷 ,这是在 docker run中使用 --volumes-from标记,
 如: 
 可以是来源不同镜像,如: docker run --name test2 -it --volumes-from test1 ubuntu /bin/bash 
 也可以是同一镜像,如: docker run --name test3 -it --volumes-from test1 myimage /bin/bash 
 上面的三个容器 test1 , test2 , test3 均有 /data1 和 /data2 两个目录,且目录中内容是共享的,
 任何一个容器修改了内容,别的容器都能获取到。 
 
 四、最佳实践:数据容器 如果多个容器需要共享数据(如持久化数据库、配置文件或者数据文件等),可以考虑创建一个特定的数据容器,该容器有1个或多个卷。 其它容器通过--volumes-from 来共享这个数据容器的卷。 
  因为容器的卷本质上对应主机上的目录,所以这个数据容器也不需要启动。
  如: docker run --name dbdata myimage echo "data container" 
  说明:有个卷,容器之间的数据共享比较方便,但也有很多问题需要解决,如权限控制、数据的备份、卷的删除等。这些内容后续文章介绍。 

6 基本指令 USER

USER daemon 指定运行容器时的用户名 或 UID

7 基本指令 WORKDIR

WORKER /PATH/TO/WORKDIR 
为后续的 run cmd entrypoint 指定配置工作目录 可以使用多个WORKDIR 指定,
如果参数是相对路径, 会基于之前的命令指定的路径
    WORKER /a 
    WORKER b 
    WORKER c 
最终路径 /a/b/c 

docker run xxx.image more test.txt 这里的test.txt的位置就是根据WORKER定义的路径来查找
docker run -w / xxx.image 复写了worker定义的路径, 现在到根目录下查找xxx.image了 

8 基本指令 ONBUILD

ONBUILD [instruction] 镜像添加触发器 : 配置当所创建的镜像作为其他新创建镜像的基础镜像时,所执行的命令.
当我们在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生实质性影响。 
但是当我们编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,
     这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了, 
        在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令。 
            如果是再利用B镜像构造新的镜像时,那个ONBUILD指令就无效了 
            FROM ubuntu 
            MAINTAINER hello 
            ONBUILD 
            RUN mkdir mydir 

9 基本指令 RUN

RUN RUN ["executable","p1","p2"] 每个run都是在当前镜像的基本上执行指定的命令 RUN 是在 docker build。

10 基本指令 CMD

 CMD ["executable","p1","p2"] 
 CMD command p1 p2 在/bin/sh中执行,
    交互模式应用 CMD ["p1","p2"] 
    提供给entrypoint的参数  指定容器启动时执行的执行的命令;
    多个 cmd 只有最后一个cmd命令生效 可以指定容器启动后在容器内立即要执行的指令 
    docker run -i -t ubunu /bin/bash 
    可以配置 CMD["/bin/bash"] 会被docker run命令的参数覆盖掉。 
 
 CMD 在docker run 时运行
 CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖
 

11 基本指令 ENTRYPOINT

ENTRYPOINT ["executable","p1","p2"] 
ENTRYPOINT command p1 p2  
配置容器启动后执行的命令, 不可被docker run 提供的参数覆盖 
多个ENTRYPOINT ,只有最后一个ENTRYPOINT生效 
如果dockerfile中也有CMD指令, CMD中的参数会被附加到ENTRYPOINT 指令的后面。 
如果这时docker run命令带了参数,这个参数会覆盖掉CMD指令的参数, 并也会附加到ENTRYPOINT 指令的后面。
        如: docker run --entrypoint="echo" myimage good 结果输出good 

 FROM ubuntu 
 MAINTAINER hello 
 RUN echo hello1 > test1.txt RUN echo hello2 > /test2.txt 
 EXPOSE 80 
 CMD ["defaultvalue"] 
 ENTRYPOINT ["echo"]  
 输出为 defaultvalue 

12 基本指令 EXPOSE

EXPOSE <port> [<port>] EXPOSE 22 80 443 告诉docker服务器容器暴露的端口号, 供互联系统使用 

13 基本指令 ENV

 ENV <key> <value> 在镜像构建过程中设置环境变量 
 类似 docker run -i -t -e "TEST=hello" ubuntu /bin/bash 

 #test 
 FROM ubuntu 
 MAINTAINER hello 
 ENV MYDIR /mydir 
 RUN mkdir $MYDIR 
 RUN echo hello world > $MYDIR/test.txt 

 二 Dockerfile创建镜像
 docker build [选项] dockerfile文件路径
 docker build -t tagname /etc/dockertest