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(学习经典)