Docker系列-第六篇DockerFile解析

Posted niugang0920

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker系列-第六篇DockerFile解析相关的知识,希望对你有一定的参考价值。

1.手动编写一个dockerfile文件,当然必须要符合file的规则

2.有了这个文件,直接docker build命令执行,获得一个自定义的镜像

3.run

1.是什么

Dockerfle 是一个文本格式的配置文件, 用户可以使用 Dockerfle 来快速创建自定义的镜像。

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

1.1三步骤

  • 编写Dockerfile文件
  • docker build
  • docker run

2.DockerFile构建过程解析

2.1Dockerfile内容基础知识

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

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

3:#表示注释

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

2.2Docker执行Dockerfile的大致流程

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

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

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

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

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

2.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容器,容器是直接提供服务的。

3.DockerFile体系结构(保留字指令)

3.1FROM

基础镜像,当前新镜像是基于哪个镜像的

每个Dockerfile的第一挑指令必须是FROM,FROM指令指定一个已存在的镜像,后续指令都继续该镜像进行,这个镜像也称为基础镜像

3.2MAINTAINER

MAINTAINER指令没有具体的格式,建议一般使用姓名和邮箱

3.3RUN

镜像构建时需要运行的命令(即镜像制作过程中需要执行的命令)

每条RUN指令都会创建一个新的镜像层,如果该指令执行成功,就会将此镜像层提交。

如果需要执行多条命令,可使用多行RUN命令,但经验告我,将多条指定通过命令换行合并成一条,这样将减少锁构建的体积。原因,上面也已经说了,在镜像中每执行一条命令,都会形成新的镜像层,需要尽可能的较少镜像层,从而减少镜像的提示

3.4EXPOSE

当前容器对外暴露出的端口

3.5WORKDIR

指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点

可以用过-w标志在运行时覆盖工作目录

3.6ENV

用来在构建镜像过程中设置环境变量

ENV MY_PATH /usr/mytest
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;
也可以在其它指令中直接使用这些环境变量,

比如:WORKDIR $MY_PATH

3.7ADD

将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包

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

ADD jdk-8u91-linux-x64.tar.gz /opt

是将宿主机当前目录下的 jdk-8u91-linux-x64.tar.gz 拷贝到容器/opt目录下 ,容器的目标路径必须的绝对路径。

一般将Dockerfile与需要添加到容器中的文件放在同一目录下,有助于编写来源路径

3.8COPY

类似ADD,拷贝文件和目录到镜像中。没有自动解压的功能
将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

3.9VOLUME

容器数据卷,用于数据保存和持久化工作

3.10CMD

指定一个容器启动时要运行的命令

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数

CMD指令用于执行容器提供默认值。每个Dockerfile只有一个CMD命令,如果指定了多个CMD命令,那么只有最后一个会被执行。

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

如 CMD java app.jar 容器启动时启动app.jar应用

3.11ENTRYPOINT

指定一个容器启动时要运行的命令

ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数

区别:

可以在docker run 命令中覆盖CMD命令。

ENTRYPOINT指令提供的命令则不容易在启动容器时被覆盖。实际上docker run命令中指定的任何参数会被当做参数再次传递给ENTRYPOINT指令中指定的命令。

3.12ONBUILD

当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发

3.13USER

指定该镜像会以什么用户运行

3.13小结

技术图片

4.案例

使用Dockerfile构建Java镜像入门1

  • step 1

    新建Dockerfile文件

    touch Dokcerfile
  • step 2

    编写Dockerfile脚本

    FROM centos:latest
    MAINTAINER "NIU GANG"<863263957@qq.com>
    # 在opt目录下新建apps目录
    RUN  mkdir -p /opt/apps
    # 在当前目录下及和Dockerfile在一个目录下,将jdk安装包增加到镜像的opt/apps目录下
    # ADD目录会自动将 .tar.gz包进行解压
    ADD jdk-8u211-linux-x64.tar.gz /opt/apps
    # 在启动容器是执行命令
    CMD /opt/apps/jdk1.8.0_211/bin/java -version
  • step 3 构建镜像

    [root@localhost tools]# docker build -t niugang/java .
    Sending build context to Docker daemon  197.8MB
    Step 1/5 : FROM centos:latest
     ---> 9f38484d220f
    Step 2/5 : MAINTAINER "NIU GANG"<863263957@qq.com>
     ---> Running in e4a4a0c1ffa9
    Removing intermediate container e4a4a0c1ffa9
     ---> a7f400aae1a7
    Step 3/5 : RUN  mkdir -p /opt/apps
     ---> Running in 49f2c1f076c0
    Removing intermediate container 49f2c1f076c0
     ---> 287c44707477
    Step 4/5 : ADD jdk-8u211-linux-x64.tar.gz /opt/apps
     ---> cf2dfbb373c8
    Step 5/5 : CMD /opt/apps/jdk1.8.0_211/bin/java -version
     ---> Running in 83d41700285a
    Removing intermediate container 83d41700285a
     ---> 79bf24642eb4
    Successfully built 79bf24642eb4
    Successfully tagged niugang/java:latest

对于 docker build -t niugang/java . 这个命令

-t 选项指定镜像名称 并读取当前(即.)目录中的Dockerfile文件

  • step 4 验证

    [root@localhost tools]# docker run --rm niugang/java
    java version "1.8.0_211"
    Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
    Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

    --rm 是启动并删除容器

    注意:

    最开始在启动docker run --rm niugang/java 会报

    /bin/sh: /opt/apps/jdk-8u211/bin/java: No such file or directory

    是因为当初认为ADD 增加 jdk-8u211-linux-x64.tar.gz 后解压的名称叫 jdk-8u211(感觉犯例了一个常识性的错误),但其实解压完成后的文件夹名称为1.8.0_211

使用Dockerfile构建Java镜像入门2

一般在安装JDK后需要设置JAVA_HOME 与PATH 这样就可以直接在命令中使用Java命令了,而须带路径参数

使用Dockerfile中的ENV指令来设置所需的环境变量

前提:

为了二次生成的镜像于之前的不重名,修改之前生成镜像的tag

docker tag 79bf24642eb4 niugang/java:1.0

修改之前的Dockerfile文件,修改后的文件内容如下

FROM centos:latest
MAINTAINER "NIU GANG"<863263957@qq.com>
RUN  mkdir -p /opt/apps
ADD jdk-8u211-linux-x64.tar.gz /opt/apps
ENV JAVA_HOME /opt/apps/jdk1.8.0_211
ENV PATH $JAVA_HOME/bin:$PATH
CMD java -version

重新构建镜像

[root@localhost tools]# docker build -t niugang/java .
Sending build context to Docker daemon  197.8MB
Step 1/7 : FROM centos:latest
 ---> 9f38484d220f
Step 2/7 : MAINTAINER "NIU GANG"<863263957@qq.com>
 ---> Using cache
 ---> a7f400aae1a7
Step 3/7 : RUN  mkdir -p /opt/apps
 ---> Using cache
 ---> 287c44707477
Step 4/7 : ADD jdk-8u211-linux-x64.tar.gz /opt/apps
 ---> Using cache
 ---> cf2dfbb373c8
Step 5/7 : ENV JAVA_HOME /opt/apps/jdk1.8.0_211
 ---> Running in 6117528026ae
Removing intermediate container 6117528026ae
 ---> 1b9e9c656a8e
Step 6/7 : ENV PATH $JAVA_HOME/bin:$PATH
 ---> Running in 5711715ae4eb
Removing intermediate container 5711715ae4eb
 ---> 82f94b6f5211
Step 7/7 : CMD java -version
 ---> Running in fcb8b117a0c2
Removing intermediate container fcb8b117a0c2
 ---> 9a26c48936a4
Successfully built 9a26c48936a4
Successfully tagged niugang/java:latest

通过上面输出的信息可以观察到,step2 step3 step4 这三个步骤直接从缓存中获取之前构建的镜像,而不是重新构建镜像

Dockerfile和构建和缓存

由于每一步的构建都会将结果提交未镜像,所以Docker的构建过程就显得非常聪明。它会将之前的镜像层看作缓存。

要想忽略缓存功能,可以使用docker build --no-cache标志

如 docker build --no-cache -t niugang/java .

自定义mycentos镜像

  • 新建Dockerfile

    touch Dockerfile
  • 编写Dockerfile

    FROM centos
    MAINTAINER ng<863263957@qq.com>
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    RUN yum -y install vim
    RUN yum -y install net-tools
    
    EXPOSE 80
    
    CMD echo $MYPATH
    CMD echo "success--------------ok"
    CMD /bin/bash
  • 构建

    docker build -t 新镜像名:TAG .

    参数:

    -f :指定要使用的Dockerfile路径;

    --no-cache :创建镜像的过程不使用缓存;

    -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;

  • 运行

? docker run -it 新镜像名:TAG

  • 列出镜像变更历史

? docker history 镜像ID

CMD/ENTRYPOINT案例镜像

共同特点:都是指定一个容器启动时要运行的命令

CMD

Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换

列如:

以下是运行tomcat镜像的命令

docker run -it -p 8888:8080 tomcat

从docker.hub上查看tomcat镜像的Dockerfile文件会发现最后有 CMD ["catalina.sh", "run"]

现在以如下方式启动:

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH (CATALINA_HOME/bin:)PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

在tomcat的Dockerfile中设置的WORKDIR为/usr/local/tomcat

docker run -it -p 8888:8080 tomcat ls -l

[root@localhost mycmdip]# docker run -it -p 8888:8080 tomcat ls -l
total 124
-rw-r--r--. 1 root root  19534 Jul  4 20:56 BUILDING.txt
-rw-r--r--. 1 root root   5407 Jul  4 20:56 CONTRIBUTING.md
-rw-r--r--. 1 root root  57011 Jul  4 20:56 LICENSE
-rw-r--r--. 1 root root   1726 Jul  4 20:56 NOTICE
-rw-r--r--. 1 root root   3255 Jul  4 20:56 README.md
-rw-r--r--. 1 root root   7139 Jul  4 20:56 RELEASE-NOTES
-rw-r--r--. 1 root root  16262 Jul  4 20:56 RUNNING.txt
drwxr-xr-x. 2 root root   4096 Jul 18 02:55 bin
drwxr-sr-x. 2 root root    238 Jul  4 20:56 conf
drwxr-sr-x. 2 root staff    78 Jul 18 02:55 include
drwxr-xr-x. 2 root root   4096 Jul 18 02:54 lib
drwxrwxrwx. 2 root root      6 Jul  4 20:53 logs
drwxr-sr-x. 3 root staff   151 Jul 18 02:55 native-jni-lib
drwxr-xr-x. 2 root root     30 Jul 18 02:54 temp
drwxr-xr-x. 7 root root     81 Jul  4 20:53 webapps
drwxrwxrwx. 2 root root      6 Jul  4 20:53 work

以上说明:

ls -l 命令覆盖了Dockerfile中的catalina.sh run

NETRYPOINT

docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合

通过案列镜像对比

操作 1

执行CMD版查询IP信息的镜像

具体Dockerfile文件内容为:

FROM centos
RUN yum install -y curl
CMD [ "curl", "-s", "http://ip.cn" ]

构建镜像

运行镜像 会返回你当前的ip信息

问题:如果我们希望显示 HTTP 头信息,就需要加上 -i 参数
技术图片

为什么会出错:

我们可以看到可执行文件找不到的报错,executable file not found。

之前也提到过跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。

因此这里的 -i CMD而不是添加在原来的后面。而根本不是命令,所以自然找不到

操作2

制作ENTROYPOINT版查询IP信息的容器

具体Dockerfile文件内容为:

FROM centos
RUN yum install -y curl
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]

这样制作出的镜像在运行过程就不会报错了 ,就会显示出http头信息了

自定义tomcat9镜像

step1 在根目录下新建mytomcat9文件夹

mkdir mytomcat9

step2 上传jdk tomcat安装包

step3 新建Dockerfile文件

touch Dockerfile

step4 编写Dockerfile 内容如下

FROM         centos
MAINTAINER    niugang<863263957@qq.com>
#把宿主机当前上下文的test.txt拷贝到容器/usr/local/路径下并重命名为test1.txt
COPY test.txt /usr/local/test1.txt
#把java与tomcat添加到容器中
ADD jdk-8u211-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.27.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_211
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.27
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.27
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE  8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.27/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.27/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.27/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.27/bin/logs/catalina.out

step5 构建镜像

docker build -t niugang/tomcat9 .

step6 运行容器

docker run -d -p 9080:8080 --name myt9  -v /mytomcat9/mywebapp/:/usr/local/apache-tomcat-9.0.27/webapps   -v /mytomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.27/logs niugang/tomcat9 --privileged=true

上述运行容器创建两个数据卷

第一个是将容器中的tomcat日志映射到宿主机上
第二个是 将tomcat中的webapps目录映射到宿主机上方便日后发布应用
也可以将容器中tomcat的配置conf文件夹映射到宿主机

step7 验证应用发布

在映射的/mytomcat9/mywebapp/ 新建test目录,test目录下新建index.html,写入helle world。

[root@localhost test]# pwd
/mytomcat9/mywebapp/test
[root@localhost test]# ll
总用量 4
-rw-r--r--. 1 root root 12 10月 23 21:30 index.html

技术图片

5.小总结

技术图片
微信公众号

技术图片
JAVA程序猿成长之路
分享资源,记录程序猿成长点滴。专注于Java,Spring,SpringBoot,SpringCloud,分布式,微服务。

以上是关于Docker系列-第六篇DockerFile解析的主要内容,如果未能解决你的问题,请参考以下文章

docker系列逐行解析Nginx镜像Dockerfile(学习经典)

[ 数据结构 -- 手撕排序算法第六篇 ] 归并排序(上)--递归方法实现

docker学习笔记 --- Dockerfile解析

Redis系列-第六篇哨兵模式

第六篇:JVM执行子系统,一点一滴解析.class文件

第六篇:JVM执行子系统,一点一滴解析.class文件