zoukankan      html  css  js  c++  java
  • Dockerfile指令

    我们已经看过一些Dockerfile中可用的指令,如RUN和EXPOSE。

    实际上还可以在Dockerfile中放入很多其他指令,如CMD、ENTRYPOINT、ADD、COPY、VOLUME、WORKDIR、USER、ONBUILD和ENV等。

    可在https://docs.docker.com/engine/reference/builder/#arg查看Dockerfile中可以使用的全部指令清单。下面将介绍这些指令的具体功能。

    CMD

    CMD指令用于制定一个容器启动时要运行的命令。

    这有点类似于RUN指令,只是RUN指令是指定镜像被构建时要运行的命令,而CMD是指定容器被启动时要运行的命令。

    三种格式分别为:

    • CMD ["executable", "param1", "param2"] 使用exec执行,推荐方式;
    • CMD command param1 param2 在/bin/sh中执行,提供给需要交互的应用;
    • CMD ["param1", "param2"] 提供给ENTRYPOINT的默认参数;

    这和使用docker run命令启动容器时指定要运行的命令非常类似:

    # docker run -it test/static_web /bin/true
    
    ## 上面的命令等效于在Dockerfile中使用如下代码
    CMD ["/bin/true"]
    

    也可以为要运行的命令指定参数:

    ## 这里将 -l 参数传递给 /bin/bash 命令
    CMD ["/bin/bash","-l"]
    
    ## 需要注意的是,要运行的命令是存放在一个数组结构中。
    

    使用docker run命令可以覆盖CMD指令。如果我们在Dockerfile里指定了CMD指令,而同时在docker run命令行中也指定了要运行的命令,命令行中指定的命令会覆盖Dockerfile中的CMD指令。

    ## 假设我们Dockerfile文件中加入CMD
    #vi Dockerfile 
    
    # Version: 0.0.1
    FROM ubuntu:14.04
    MAINTAINER Bourbon Tian "bourbon@1mcloud.com"
    ENV REFRESHED_AT 2017-05-18
    RUN apt-get update
    RUN apt-get install -y nginx
    RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html
    RUN sed -i '22d' /etc/nginx/sites-enabled/default
    EXPOSE 80
    CMD ["/bin/bash"]
    
    ## 重新构建一个新的镜像,镜像名为static_test,并基于这个镜像启动一个新的容器
    # docker build -t="test/static_test" .
    # docker run -t -i test/static_test
    root@40786fce97d2:/# exit
    ## 这里docker run命令的末尾我们并没有指定要运行什么命令。
    ## 实际上,Docker使用了CMD中的命令。
    
    
    ## 如果我们指定了要运行的命令,如这里运行的/bin/ps,容器并没有启动shell
    ## 通过命令行参数覆盖了CMD中指定的命令,容器运行后列出正在运行的进程列表,之后停止了容器。
    # docker run -t -i test/static_test /bin/ps
       PID TTY          TIME CMD
         1 ?        00:00:00 ps
    

    在Dockerfile中只能指定一条CMD指令。如果指定了多条,也只有最后一条CMD指令会被使用。 

    ENTRYPOINT

    ENTRYPOINT指令与CMD指令非常类似,区别在于我们可以在docker run命令行中覆盖CMD命令,而ENTRYPOINT指令提供的命令则不容易(如果确实需要,可以在运行时通过docker run的--entrypoint标志覆盖)在启动时被覆盖。实际上,docker run命令行中指定的任何参数都会被当做参数再次传递给ENTRYPOINT指令中指定的命令。

    有两种格式:

    • ENTRYPOINT ["executable", "param1", "param2"]
    • ENTRYPOINT command param1 param2(shell中执行)
    ENTRYPOINT ["/usr/sbin/nginx"]
    
    ## 通过数组的方式为命令指定相应的参数
    ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
    

     重新构建镜像,添加ENTRYPOINT ["/usr/sbin/nginx"]指令:

    ENTRYPOINT ["/usr/sbin/nginx"]
    
    # docker build -t="test/static_web" .
    
    # docker run -d -p 80 test/static_web -g "daemon off;"
    207886d3d33e78ce3bafe07ae3b5589e37c29e4691f23c77a61c6a0e56d9a95a
    # docker ps -l
    CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                   NAMES
    207886d3d33e        test/static_web     "/usr/sbin/nginx -g    10 seconds ago      Up 9 seconds        0.0.0.0:32774->80/tcp   jolly_kilby
    

    在这里-g "daemon off;"参数传递给了ENTRYPOINT指定的命令,在这里命令为/usr/sbin/nginx -g "daemon off;"。我们也可以组合ENTRYPOINT和CMD指令完成一些巧妙的工作。

    ENTRYPOINT ["/usr/sbin/nginx"]
    CMD ["-h"]
    
    ## 如果启动容器时不指定任何参数,CMD指令会被传递,显示Nginx帮助信息;
    ## 同时也支持通过docker run命令行为该命令指令指定可覆盖的选项或标志。
    

    每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。

    WORKDIR

    WORKDIR指令用来在从镜像创建一个新容器时,在容器内部设置一个工作目录,ENTRYPOINT和/或CMD指定的程序会在这个目录下执行。

    我们可以使用该指令为Dockerfile中后续的一些列指令设置工作目录,也可以为最终的容器设置工作目录。

    格式为: WORKDIR /path/to/workdir

    ## 为特定的指令设置不同的工作目录
    WORKDIR /opt/webapp/db
    ## 将工作目录切换为/opt/webapp/db 后运行bundle install
    RUN bundle install
    WORKDIR /opt/webapp
    ## 将工作目录切换为/opt/webapp后设置ENTRYPOINT指令来启动rackup命令。
    ENTRYPOINT ["rackup"]
    

    通过-w标志在运行时覆盖工作目录,该命令会将容器内的工作目录设置为/var/log。

    docker run -it -w /var/log ubuntu pwd
    /var/log
    

    ENV

    ENV指令用来在镜像构件过程中设置环境变量,格式为: ENV <key> <value>

    ENV RVM_PATH /home/rvm
    

    这个新的环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样

    RUN gem install unicorn
    ## 这条RUN指令就会以如下的方式执行
    RVM_PATH=/home/rvm/ gem install unicorn
    
    
    ## 也能在其他命令中直接使用这些环境变量
    ENV TARGET_DIR /opt/app
    WORKDIR $TARGET_DIR
    ## 这里设定了一个TARGET_DIR的环境变量,并在WORKDIR中调用了这个环境变量
    ## 所以这里的WORKDIR指令的值会被设置为/opt/app
    

    这些环境变量也会被持久保存到从我们的镜像创建的任何容器中。如果我们在使用ENV指令构建容的容器中运行env命令,将会看到我们所设置的环境变量。

    也通过docker run命令行的 -e 标志来传递环境变量。这些环境变量只会在运行时有效

    # docker run -it -e "WEB_PORT=8080" ubuntu env
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    HOSTNAME=2688f9db5f34
    TERM=xterm
    WEB_PORT=8080
    HOME=/root
    

    可以看到,在容器中WEB_PORT环境变量被设置为了8080。

    USER

    USER指令用来指定该镜像会以什么样的用户去运行

    格式为:USER daemon

    USER nginx
    

    基于该镜像启动的容器会以nginx用的身份来运行。我们可以指定用户名或UID以及组或GID,甚至是两者结合。

    USER user
    USER user:group
    USER uid
    USER uid:gid
    USER user:gid
    USER uid:group
    

    也可以在docker run命令中通过-u选项来覆盖该指令指定的值,如果不通过USER指令指定用户,默认用户为root。

    VOLUME

    VOLUME指令用来向基于镜像创建的容器添加卷。一个卷是可以存在于一个或者多个容器内的特定的目录,这个目录可以绕过联合文件系统,并提供如下共享数据或者对数据进行持久化的功能。

    • 卷可以在容器间共享和重用。
    • 一个容器可以不是必须和其他容器共享卷。
    • 对卷的修改是立时生效的。
    • 对卷的修改不会对更新镜像产生影响。
    • 卷会一直存在直到没有任何容器再使用它。

    卷功能让我们可以将数据(如源代码)、数据库或者其他内容添加到镜像中而不是将这些内容提交到镜像中,并且允许我们在多个容器间共享这些内容。我们可以利用此功能来测试容器和内部的应用程序代码,管理日志,或者处理容器内部的数据库。

    格式为: VOLUME ["/data"]

    也可以通过指定数组的方式指定多个卷

    格式为: VOLUME ["/data1", "/data2"]

    ADD

    ADD指令用来将构建环境下的文件和目录复制到镜像中。格式为:ADD <src> <dest>

    ADD software.lic /opt/application/software.lic
    

    这里的ADD指令将会将构建目录下的software.lic文件复制到镜像中的/opt/application/software.lic。指向源文件的位置参数可以是一个URL,或者构建上下文或环境中文件名或者目录。不能对构建目录或者上下文之外的文件进行ADD操作。

    在ADD文件时,Docker通过目的地址参数末尾的字符来判断文件源是目录还是文件。以/结尾,那么Docker就认为是一个目录,如果不是以/结尾,那么Docker就认为是个文件。

    源文件也可以使用URL的格式:

    ADD http://wordpress.org/latest.zip /root/wordpress.zip
    

    最后值得一提的是,ADD在处理本地归档文件(tar archive)时还有一些小魔法。如果将一个归档文件(合法的归档文件包括gzip、bzip2、xz)指定为源文件,Docker会自动将归档文件解开(unpack)

    ADD latest.tar.gz /var/www/wordpress/
    

    这里会将归档文件latest.tar.gz 解压到/var/www/wordpress/目录下。如果目的位置不存在的话,Docker将会为我们创建这个全路径,包括路径中的任何目录。新创建的文件和目录的模式为0755,并且UID和GID都是0。

    ADD指令会使得构建缓存变得无效,如果通过ADD指令向镜像添加一个文件或者目录,那么这将使Dockerfile中的后续指令都不能继续使用之前的构建缓存。

    COPY

    COPY指令非常类似于ADD,它们根本的不同是COPY只关心在构建上下文中复制本地文件,而不会去做文件提取(extraction)和解压(decompression)的工作。

    格式为:COPY <src> <dest>

    COPY conf.d/ /etc/apache2/
    

    这条指令会把本地conf.d目录中的文件复制到/etc/apache2/目录中。文件源路径必须是一个与当前构建环境相对的文件或者目录,本地文件都放到和Dockerfile同一个目录下。不能复制该目录之外的任何文件,因为构建环境将会上传到Docker守护进程,而复制是在Docker守护进程中进行的,任何位于构建环境之外的东西都不可用。COPY指令的目的位置则必须是容器内部的一个绝对路径。

    任何由指定创建的文件或者目录的UID和GID都会设置为0。如果目的位置不存在,Docker将会自动创建所有需要的目录结构。

    ONBUILD

    ONBUILD指令能为镜像添加触发器(trigger)。当一个镜像被用作其他镜像的基础镜像,该镜像的触发器将会被执行。触发器会在构建过程中插入新指令,我们可以认为这些指令是紧跟在FROM之后指定的。触发器可以是任何构建指令。

    格式为:ONBUILD [INSTRUCTION]

    比如,我们为apache镜像构建一个全新的Dockerfile,该镜像名为static_apache2

    # Version: 0.0.1
    FROM ubuntu:14.04
    MAINTAINER Bourbon Tian "bourbon@1mcloud.com"
    RUN apt-get update
    RUN apt-get install -y apache2
    ENV APACHE_RUN_USER www-data
    ENV APACHE_RUN_GROUP www-data
    ENV APACHE_LOG_DIR /var/log/apache2
    ONBUILD ADD . /var/www/ 
    EXPOSE 80
    ENTRYPOINT ["/usr/sbin/apache2"]
    CMD ["-D", "FOREGROUND"]
    
    # docker build -t="test/static_apache2" .
    

    在新构建的镜像中包含一条ONBUILD指令,该指令会使用ADD指令将构建环境所在的目录下的内容全部添加到镜像中的/var/www/目录下。我们可以将这个Dockerfile作为一个通用的Web应用程序的模板,可以基于这个模板来构建Web应用程序。

    我们可以通过构建一个名为webapp的镜像来看看如何使用镜像模板功能:

    FROM test/static_apache2
    MAINTAINER Bourbon Tian "bourbon@1mcloud.com"
    ENV APPLICATION_name webapp
    ENV ENVIRONMENT development
    
    # docker build -t="test/webapp" .
    Sending build context to Docker daemon 2.048 kB
    Sending build context to Docker daemon 
    Step 0 : FROM test/static_apache2
    # Executing 1 build triggers
    Trigger 0, ADD . /var/www/ 
    Step 0 : ADD . /var/www/
     ---> 92a790340715
    Removing intermediate container cf7accb5ca5b
    Step 1 : MAINTAINER Bourbon Tian "bourbon@1mcloud.com"
    ...
    Successfully built 36ae30d2e972
    

    可以看到,在FROM指令之后,Docker插入了一条ADD指令,这条ADD指令就在ONBUILD触发器中指定的。执行完该ADD指令后,Docker才会继续执行构建文件中的后续指令。这种机制使我每次都会将本地源代码添加到镜像,就像上面我们做到的那样,也支持我为不同的应用程序进行一些特定的配置或者设置构建信息。这时,可以将test/static_apache2当做一个镜像模板。

    ONBUILD触发器会按照在父镜像中指定的顺序执行,并且只能被继承一次。如果再基于test/webapp构建一个镜像,则新镜像不会继承test/static_apache2中的触发器。

    值得注意的是,有好几条指令是不能用在ONBUILD指令中,其中包括FROM、MAINTAINER和ONBUILD本身。之所以这么规定是为了防止在Dockerfile构建过程中产生递归调用的问题。

  • 相关阅读:
    .NET[C#]使用LINQ从List<T>集合中获取最后N条数据记录的方法有哪些?
    这个匿名对象没有实现IComparable接口
    c/c++中define用法详解及代码示例
    几个常用Json组件的性能测试
    通过jQuery Ajax使用FormData对象上传文件
    《631962 揭秘Java虚拟机-JVM设计原理与实现.pdf【第8章】》 ——类方法解析
    《631962 揭秘Java虚拟机-JVM设计原理与实现.pdf【第7章】》 ——Java栈桢
    《OOP-Klass》
    《631962 揭秘Java虚拟机-JVM设计原理与实现.pdf【第6章】》——类变量解析
    《631962 揭秘Java虚拟机-JVM设计原理与实现.pdf【第5章】》——常量池解析
  • 原文地址:https://www.cnblogs.com/Bourbon-tian/p/6879889.html
Copyright © 2011-2022 走看看