docker学习四:DockerFile解析

一、是什么

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

         1.构建三步骤 

                   (1)编写Dockerfile文件

                   (2)使用docker build命令基于该Dockerfile中的指令构建一个新的镜像

                   (3)docker run命令创建容器

         2.文件是什么样

                       以centos为例              

FROM scratch
ADD centos-7-x86_64-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="20191001"

CMD ["/bin/bash"]

其中 FROM、ADD、LABEL、CMD都是保留字指令

二、DockerFile构建过程解析 

      1.Dockerfile内容基础知识

               (1)每条保留字指令都必须为大写字母且后面要跟随至少一个参数

               (2)指令按照从上到下,顺序执行

               (3)#表示注释

               (4) 每条指令都会创建一个新的镜像层,并对镜像进行提交

      2.Docker执行Dockerfile的大致流程

               (1)docker从基础镜像运行一个容器

               (2)执行一条指令并对容器作出修改

               (3)执行类似docker commit的操作提交一个新的镜像层

               (4)docker再基于刚提交的镜像运行一个新容器

               (5)执行dockerfile中的下一条指令直到所有指令都执行完成

     3. 总结

            从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
                 *  Dockerfile是软件的原材料
                 *  Docker镜像是软件的交付品
                 *  Docker容器则可以认为是软件的运行态。
            Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

        

       (1) Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者                是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系              统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
 
     (2) Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正              开始提供服务;
 
     (3) Docker容器,容器是直接提供服务的。 

四、常用保留字指令(DSL语法

        1.FROM(指定基础image

      构建指令,必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定 的imageFROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。 FROM命令告诉docker我们构建的镜像是以哪个(发行版)镜像为基础的。第一条指令必须是 FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指 令。

     该指令有两种格式:

       FROM <image>
              指定基础 image 为该 image 的最后修改的版本。或者:
       FROM <image>:<tag>
              指定基础 image 为该 image 的一个 tag 版本。

       2.MAINTAINER(用来指定镜像创建者信息)

       构建指令,用于将 image 的制作者相关的信息写入到 image 中。当我们对该 image 执行 docker inspect命令时,输出中有相应的字段记录该信息
        
       格式:
             MAINTAINER <name>

     3.RUN(镜像构建时需要运行的命令)

          构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了ubuntu,那么软件管理部分只能使用ubuntu的命令。

         该指令有两种格式:
                   (sell格式)
                    RUN command param1 param2
                    (exec格式)
                    RUN ["executable", "param1", "param2" ... ]
 RUN 后面接要执行的命令,比如,我们想在镜像中安装 vim ,只需在 Dockfile 中写入 RUN yum install ‐y vim

    4.CMD(设置container启动时执行的操作)

         设置指令,用于container启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。

      该指令有三种格式:

            CMD ["executable","param1","param2"]
             CMD command param1 param2
                 当 Dockerfile 指定了 ENTRYPOINT ,那么使用下面的格式:
           CMD ["param1","param2"]
其中:
ENTRYPOINT指定的是一个可执行的脚本或者linux命令,该指定的脚本或者linux命令将会以 param1和param2 作为参数执行。
所以如果 CMD 指令使用上面的形式,那么 Dockerfile 中必须要有配套的 ENTRYPOINT

   5.ENTRYPOINT(设置container启动时执行的操作)

      设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。

                两种格式 :
             ENTRYPOINT ["executable", "param1", "param2"]
             ENTRYPOINT command param1 param2
                 
       该指令的使用分为两种情况,一种是独自使用,另一种和 CMD 指令配合使用。
     
      (1) 当独自使用时,如果你还使用了 CMD 命令且 CMD 是一个完整的可执行的命令,那么 CMD 指令和 ENTRYPOINT会互相覆盖,只有最后一个 CMD 或者 ENTRYPOINT 有效。
 
# CMD 指令将不会被执行,只有 ENTRYPOINT 指令被执行
CMD echo “Hello, World!”
ENTRYPOINT ls ‐l
 
     (2)另一种用法和 CMD 指令配合使用来指定 ENTRYPOINT 的默认参数,这时 CMD 指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用 exec 格式指定执行命令。
 
     CMD ["‐l"]
     ENTRYPOINT ["ls"]
 
ps:CMD 命令会被 docker run 命令之后的参数替换,而ENTRYPOINT指令(exec格式下)可以追加docker run命令 之后的参数
    如:
        a.此时我自定义的dockerfile中设置的
            CMD["ls"]
        
       此时docker run -it myimage top,容器启动后执行的不是ls命令而是top命令
 
        b.此时我自定义的dockerfile中设置的
           ENTRYPOINT ["ls"]
     此时docker run -it myimage -l,容器启动后执行的是ls -l命令
     
 

 6.USER(设置container容器的用户)

 7.EXPOSE(指定容器需要映射到宿主机器的端口)

      设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。

     要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定‐p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。

     EXPOSE 指令可以一次设置多个端口号,相应的运行容器的时候,可以配套的多次使用 ‐p 选项。
格式 :
EXPOSE <port> [<port>...]
# 映射一个端口
EXPOSE port1
# 相应的运行容器使用的命令
docker run ‐p port1 image
# 映射多个端口
EXPOSE port1 port2 port3
# 相应的运行容器使用的命令
docker run ‐p port1 ‐p port2 ‐p port3 image
# 还可以指定需要映射到宿主机器上的某个端口号
docker run ‐p host_port1:port1 ‐p host_port2:port2 ‐p host_port3:port3 image
 
        端口映射是 docker 比较重要的一个功能,原因在于我们每次运行容器的时候容器的 IP 地址不能指定而是在桥接网卡的地址范围内随机生成的。 宿主机器的IP 地址是固定的,我们可以将容器的端口的映射到宿主机器上的一个端口,免去每次访问容器中的某个服务时都要查看容器的IP 的地址。 对于一个运行的容器,可以使用docker port 加上容器中需要映射的端口和容器的 ID 来查看
该端口号在宿主机器上的映射端口。
 

 8.ENV(用于设置环境变量)

       格式 :
          ENV <key> <value>
     设置了后,后续的 RUN 命令都可以使用, container 启动后,可以通过 docker inspect 查看 这个环境变量,也可以通过在
docker run ‐‐env key=value 时设置或修改环境变量。
     假如你安装了 JAVA 程序,需要设置 JAVA_HOME ,那么可以在 Dockerfile 中这样写:
         ENV JAVA_HOME /path/to/java/dirent
 

9.ADD(从src复制文件到containerdest路径)

   主要用于将宿主机中的文件添加到镜像中

     构建指令, 如果是一个目录,那么会将该目录下的所有文件添加到container 中,不包括目录; 如果文件是可识别的压缩格式,则docker 会帮忙解压缩(注意压缩格式);如果 <src> 是文件且<dest> 中不使用斜杠结束,则会将 <dest> 视为文件, <src> 的内容会写入 <dest> ;如果<src> 是文件且 <dest> 中使用斜杠结束,则会 <src> 文件拷贝到 <dest> 目录下。
     
格式 :
ADD <src> <dest>
<src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;
<dest> container 中的绝对路径
 

10.COPY (从src复制文件到containerdest路径)

    COPY是ADD的一种简化版本,目的在于满足大多数人“复制文件到容器”的需求。

    COPY不支持URL,也不会特别对待压缩文件。如果build 上下文件中没有指定解压的话,那么就不会自动解压,只会复制压缩文件到容器中。

11.VOLUME(指定挂载点)

      设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。

格式 :
VOLUME ["<mountpoint>"]
例如:
FROM base
VOLUME ["/tmp/data"]
 
运行通过该 Dockerfile 生成 image 的容器, /tmp/data 目录中的数据在容器关闭后,里面的 数据还存在。
 
例如另一个容器也有持久化数据的需求,且想使用上面容器共享的 /tmp/data 目录,那么可以运行下面的命令启动一个容器:
     docker run ‐t ‐i ‐rm ‐volumes‐from container1 image2 bash
其中: container1 为第一个容器的 ID image2 为第二个容器运行 image 的名字。
 
PS :也可以通过命令
    docker run -it -v /宿主机绝对路径目录:/容器内目录      镜像名 
来持久化数据,则容器内目录就挂在到宿主机绝对路径目录上;
   docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名,则容器内的目录就只读,没有写权限
 
   Docker挂载主机目录Docker访问出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true参数即可
 

12.WORKDIR(指定容器的一个目录,容器启动时执行的命令会在该目录下执行,相当于设置了容器的工作目录

 
设置指令,可以多次切换 ( 相当于 cd 命令 ) ,对 RUN,CMD,ENTRYPOINT 生效。
格式 :
WORKDIR /path/to/workdir
# /p1/p2 下执行 vim a.txt
WORKDIR /p1
WORKDIR p2
RUN vim a.txt
 
我们知道每执行一次命令,就是会提交一次新的镜像,docker再基于刚提交的镜像运行一个新容器,然后执行下一个命令;
上述命令中,执行完 WORKDIR /p1后提交了一个新的镜像a,再根据镜像a运行了新的容器,则此时容器的工作目录就是在/p1下,并继续执行WORKDIR p2,然后提交了一个新的镜像b,再根据镜像b运行了新的容器,则此时容器的工作目录就是在/p1/p2下。
 

13.ONBUILD(在子镜像中执行)

 
  格式:
ONBUILD <Dockerfile 关键字 >
ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行。
 

五、案例

     制作一个tomcat7镜像

1.mkdir /mydockerfile

2.在/mydockerfile目录下touch c.txt

3.将jdk和tomcat安装的压缩包拷贝进/mydockerfile目录

4.在/mydockerfile目录下新建Dockerfile文件

FROM         centos:centos6.8
MAINTAINER    hl<hl@126.com>
#把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u141-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-7.0.70.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_141
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-7.0.70
ENV CATALINA_BASE /usr/local/apache-tomcat-7.0.70
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE  8080
#启动时运行tomcat
# CMD ["/usr/local/apache-tomcat-7.0.70/bin/catalina.sh","run"]
ENTRYPOINT /usr/local/apache-tomcat-7.0.70/bin/startup.sh&&tail -f /usr/local/apache-tomcat-7.0.70/logs/catalina.out
 

5.在 /mydockerfile目录下构建镜像

   docker build -t mytomcat7.0 --rm=true .

‐t 表示选择指定生成镜像的用户名,仓库名和 tag
‐‐rm = true 表示指定在生成镜像过程中删除中间产生的临时容器。
注意:上面构建命令中最后的 .符号不要漏了,其实是在指定当前目录为镜像构建过程中的上下文环境的目录

 

构建完成

[root@java12 mydockerfile]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
mytomcat7.0         latest              262714c51a4d        About an hour ago   730.7 MB

6.测试

    docker run -it -d -p 9090:8080 --name mytomcat7 -v /mydockerfile/tomcat7logs/:/usr/local/apache-tomcat-7.0.70/logs --privileged=true  mytomcat7.0 

    

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值