DockerFile解析 什么是Dockerfile Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
Dockerfile构建三步骤:
1 2 3 4 5 graph TB A(编写Dockerfile文件) --> B B(docker build)--> C C(docker run)
看下centos精简版centos镜像dockerfile。
from scratch中的scratch相当于java中的object类,是源镜像。
maintainer 作者+邮箱
label 标签描述信息
default command 即运行后执行
DockerFile构建过程解析 Dockerfile编写规范
每条保留字指令都必须为大写字母且后面要跟随至少一个参数
指令按照从上到下,顺序执行
表示注释
每条指令都会创建一个新的镜像层,并对镜像进行提交
Docker执行Dockerfile流程
docker从基础镜像运行一个容器
执行一条指令并对容器作出修改
执行类似docker commit的操作提交一个新的镜像层
docker再基于刚提交的镜像运行一个新容器
执行dockerfile中的下一条指令直到所有指令都执行完成
总结 从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
Dockerfile是软件的原材料
Docker镜像是软件的交付品
Docker容器则可以认为是软件的运行态。
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
Docker容器,容器是直接提供服务的。
DockerFile体系结构(保留字指令)
保留字指令
解释
FROM
基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER
镜像维护者的姓名和邮箱地址
RUN
容器构建时需要运行的命令
EXPOSE
当前容器对外暴露出的端口
WORKDIR
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
ENV
用来在构建镜像过程中设置环境变量
ADD
将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY
类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
VOLUME
容器数据卷,用于数据保存和持久化工作
CMD
指定一个容器启动时要运行的命令。Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换 cmd指令的格式和run相似也是两种格式 shell格式:CMD <命令> exec格式:CMD [“可执行文件”, “参数1”, “参数2”] 在指定了ENTRYPOINT指令后,用CMD的具体参数<>
ENTRYPOINT
指定一个容器启动时要运行的命令,ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数
ONBUILD
当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发
Dockerfile实践案例 案例1:自定义centos镜像 已知原始拉取的centos镜像不支持ifconfig
和vim
,我们这里做一个案例,用Dockerfile构建一个支持这两个命令的centos镜像。
1.编写Dockerfile Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 FROM centosMAINTAINER hj<hjabari@qq.com>ENV MYPATH /usr/localWORKDIR $MYPATH RUN yum -y install vim RUN yum -y install net-tools EXPOSE 80 CMD echo $MYPATH CMD echo "success-------ok" CMD /bin/bash
2.构建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 [dw@dk mydocker]$ sudo vim Dockerfile2 [dw@dk mydocker]$ sudo docker build -f /mydocker/Dockerfile2 -t mycentos:1.3 . Sending build context to Docker daemon 3.072kB Step 1/10 : FROM centos ---> 300e315adb2f Step 2/10 : MAINTAINER hj<hjabari@qq.com> ---> Running in f9a3aee1bb70 Removing intermediate container f9a3aee1bb70 ---> 0680f2af1459 Step 3/10 : ENV MYPATH /usr/local ---> Running in e62b6cf85a66 Removing intermediate container e62b6cf85a66 ---> 75b40fb2bcf4 Step 4/10 : WORKDIR $MYPATH ---> Running in a00db920ca3f Removing intermediate container a00db920ca3f ---> 21724bcf3e5b Step 5/10 : RUN yum -y install vim ---> Running in e0e927e885dc ...... [dw@dk mydocker]$ sudo vim Dockerfile2 [dw@dk mydocker]$ sudo docker build -f /mydocker/Dockerfile2 -t mycentos:1.3 . Sending build context to Docker daemon 3.072kB Step 1/10 : FROM centos ---> 300e315adb2f Step 2/10 : MAINTAINER hj<hjabari@qq.com> ---> Running in f9a3aee1bb70 Removing intermediate container f9a3aee1bb70 ---> 0680f2af1459 Step 3/10 : ENV MYPATH /usr/local ---> Running in e62b6cf85a66 Removing intermediate container e62b6cf85a66 ---> 75b40fb2bcf4 Step 4/10 : WORKDIR $MYPATH ---> Running in a00db920ca3f Removing intermediate container a00db920ca3f ---> 21724bcf3e5b Step 5/10 : RUN yum -y install vim ---> Running in e0e927e885dc
1 2 3 4 5 6 REPOSITORY TAG IMAGE ID CREATED SIZE mycentos 1.3 1e839242ccce About a minute ago 295MB hj/centos latest a5b1d45db2cf 2 days ago 209MB atguigu/mytomcat 1.2 3195c86b5066 5 days ago 669MB tomcat latest c43a65faae57 4 weeks ago 667MB centos latest 300e315adb2f 6 months ago 209MB
3.启动 1 2 3 [dw@dk mydocker]$ sudo docker run -it mycentos:1.3 [root@3f0cdc92f1d9 local ] /usr/local
案例2:CMD/ENTRYPOINT 镜像案例 两者都是指定一个容器启动时要运行的命令,但是ENTRYPOINT可以额外为命令添加参数,CMD却不行。
CMD
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
1 docker run -it -p 8888:8080 tomcat ls -l
ENTRYPOINT docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合
制作CMD版可以查询IP信息的容器 curl命令解释 curl命令可以用来执行下载、发送各种HTTP请求,指定HTTP头部等操作。 如果系统没有curl可以使用yum install curl安装,也可以下载安装。 curl是将下载文件输出到stdout
使用命令:curl http://www.baidu.com 执行后,www.baidu.com的html就会显示在屏幕上了
这是最简单的使用方法。用这个命令获得了http://curl.haxx.se指向的页面,同样,如果这里的URL指向的是一个文件或者一幅图都可以直接下载到本地。如果下载的是HTML文档,那么缺省的将只显示文件头部,即HTML文档的header。要全部显示,请加参数 -i
1.编写dockerfile 1 2 3 FROM centosRUN yum install -y curl CMD ["curl" , "-s" , "http://cip.cc" ]
2.构建运行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [dw@dk mydocker]$ sudo docker build -f /mydocker/Dockerfile3 -t myip . Sending build context to Docker daemon 4.608kB Step 1/3 : FROM centos ---> 300e315adb2f Step 2/3 : RUN yum install -y curl ---> Running in cee2a446a78a [dw@dk mydocker]$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE myip latest aae1a79f575a 34 seconds ago 245MB mycentos 1.3 1e839242ccce 15 hours ago 295MB hj/centos latest a5b1d45db2cf 2 days ago 209MB atguigu/mytomcat 1.2 3195c86b5066 6 days ago 669MB tomcat latest c43a65faae57 4 weeks ago 667MB centos latest 300e315adb2f 6 months ago 209MB [dw@dk mydocker]$ sudo docker run -it myip IP : 120.236.177.121 地址 : 中国 广东 广州 运营商 : 移动 数据二 : 广东省广州市 | 移动 数据三 : 中国广东广州 | 移动 URL : http://www.cip.cc/120.236.177.121
如果我们想再加入一个命令查看ip头:
我们可以看到可执行文件找不到的报错,executable file not found。之前说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。因此这里的 -i 替换了原来的 CMD,而不是添加在原来的 curl -s http://cip.cc 后面。而 -i 根本不是命令,所以自然找不到。
那么如果我们希望加入 -i 这参数,我们就必须重新完整的输入这个命令:
$ docker run myip curl -s http://cip.cc -i
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [dw@dk mydocker]$ curl -s -i cip.cc HTTP/1.1 200 OK Server: openresty Date: Sun, 13 Jun 2021 06:01:22 GMT Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept-Encoding X-cip-c: H IP : 120.236.177.36 地址 : 中国 广东 广州 运营商 : 移动 数据二 : 广东省广州市 | 移动 数据三 : 中国广东广州 | 移动 URL : http://www.cip.cc/120.236.177.36
此时CMD命令就无法实现了,因为会产生命令覆盖,这个时候就用entrypoint。
dockerfile:
1 2 3 FROM centosRUN yum install -y curl ENTRYPOINT [ "curl" , "-s" , "http://ip.cn" ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [dw@dk mydocker]$ sudo vim Dockerfile4 [dw@dk mydocker]$ sudo docker build -f /mydocker/Dockerfile4 -t myip2 . Sending build context to Docker daemon 5.632kB Step 1/3 : FROM centos ---> 300e315adb2f Step 2/3 : RUN yum install -y curl ---> Using cache ---> 1df2d50b8c95 Step 3/3 : ENTRYPOINT ["curl" , "-s" , "http://cip.cc" ] <-- ---> Running in f236ec0f2882 Removing intermediate container f236ec0f2882 ---> 891d700ccc99 Successfully built 891d700ccc99 Successfully tagged myip2:latest [dw@dk mydocker]$
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 [dw@dk mydocker]$ sudo docker run -it myip2 IP : 120.236.177.121 地址 : 中国 广东 广州 运营商 : 移动 数据二 : 广东省广州市 | 移动 数据三 : 中国广东广州 | 移动 URL : http://www.cip.cc/120.236.177.121 [dw@dk mydocker]$ sudo docker run -it myip2 -i HTTP/1.1 200 OK Server: openresty Date: Sun, 13 Jun 2021 06:06:19 GMT Content-Type: text/html; charset=UTF-8 Transfer-Encoding: chunked Connection: keep-alive Vary: Accept-Encoding X-cip-c: H IP : 120.236.177.121 地址 : 中国 广东 广州 运营商 : 移动 数据二 : 广东省广州市 | 移动 数据三 : 中国广东广州 | 移动 URL : http://www.cip.cc/120.236.177.121
案例3:ONBUILD 当构建一个被继承的Dockerfile时运行命令,父镜像在被子继承后父镜像的onbuild被触发。做一个onbuild的镜像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@dk mydocker] Sending build context to Docker daemon 5.632kB Step 1/4 : FROM centos ---> 300e315adb2f Step 2/4 : RUN yum install -y curl ---> Using cache ---> 1df2d50b8c95 Step 3/4 : ENTRYPOINT ["curl" , "-s" , "http://cip.cc" ] ---> Using cache ---> 891d700ccc99 Step 4/4 : ONBUILD RUN echo "father onbuild---------886" <-- ---> Running in 70e0c81e2b5f Removing intermediate container 70e0c81e2b5f ---> 1cbdf842113a Successfully built 1cbdf842113a Successfully tagged myip_father:latest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [root@dk mydocker] REPOSITORY TAG IMAGE ID CREATED SIZE myip_father latest 1cbdf842113a 14 seconds ago 245MB myip2 latest 891d700ccc99 11 minutes ago 245MB myip latest aae1a79f575a 15 minutes ago 245MB mycentos 1.3 1e839242ccce 15 hours ago 295MB hj/centos latest a5b1d45db2cf 2 days ago 209MB atguigu/mytomcat 1.2 3195c86b5066 6 days ago 669MB tomcat latest c43a65faae57 4 weeks ago 667MB centos latest 300e315adb2f 6 months ago 209MB [root@dk mydocker] [root@dk mydocker] Dockerfile Dockerfile2 Dockerfile3 Dockerfile4 [root@dk mydocker] [root@dk mydocker] FROM myip_father RUN yum install -y curl ENTRYPOINT ["curl" , "-s" , "http://cip.cc" ]
构建,可以看到父镜像在被子镜像继承后触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [root@dk mydocker] Sending build context to Docker daemon 6.656kB Step 1/3 : FROM myip_father <-- ---> Running in 4ac886846572 father onbuild---------886 Removing intermediate container 4ac886846572 ---> 3046036194b2 Step 2/3 : RUN yum install -y curl ---> Running in da7f72244bf5 Last metadata expiration check: 0:19:14 ago on Sun Jun 13 06:00:13 2021. Package curl-7.61.1-18.el8.x86_64 is already installed. Dependencies resolved. Nothing to do . Complete! Removing intermediate container da7f72244bf5 ---> e169ad98e111 Step 3/3 : ENTRYPOINT ["curl" , "-s" , "http://cip.cc" ] ---> Running in 0274c2228b25 Removing intermediate container 0274c2228b25 ---> 7172ab2360ca Successfully built 7172ab2360ca Successfully tagged myip_son:latest
案例4:自定义tomcat 自定义一个tomcat
编写dockerfile 将对应的压缩包拉到dockerfile的文件夹目录下,便于构建时使用压缩包构建docker镜像。
1 2 3 4 [root@dk tomcat9] apache-tomcat-9.0.46.tar.gz c.txt jdk-8u212-linux-x64.tar.gz [root@dk tomcat9] /mydocker/mydockerfile/tomcat9
dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 FROM centosMAINTAINER hj<1961663351 @qq.com>COPY c.txt /usr/local/cincontainer.txt ADD jdk-8u212-linux-x64.tar.gz /usr/local/ ADD apache-tomcat-9.0.46.tar.gz /usr/local/ RUN yum -y install vim ENV MYPATH /usr/localWORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0 _212ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jarENV CATALINA_HOME /usr/local/apache-tomcat-9.0 .46 ENV CATALINA_BASE /usr/local/apache-tomcat-9.0 .46 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/binEXPOSE 8080 CMD /usr/local/apache-tomcat-9.0.46/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.46/bin/logs/catalina.out
构建
1 2 3 4 5 6 7 8 9 10 11 [root@dk tomcat9] Sending build context to Docker daemon 206.5MB Step 1/15 : FROM centos ---> 300e315adb2f Step 2/15 : MAINTAINER hj<1961663351@qq.com> ---> Running in 6285570d7fe9 Removing intermediate container 6285570d7fe9 ---> f7301d070188 Step 3/15 : COPY c.txt /usr/local/cincontainer.txt ---> b61f1a056f38 Step 4/15 : ADD jdk-8u212-linux-x64.tar.gz /usr/local/
运行
1 2 3 4 5 6 7 8 9 10 11 docker run -d -p 9080:8080 --name myt9 -v /mydocker/mydockerfile/tomcat9/test:/usr/local/apache-tomcat-9.0.46/webapps/test -v /mydocker/mydockerfile/tomcat9/tomcat9logs:/usr/local/apache-tomcat-9.0.46//logs --privileged=true hjtomcat9
上面创建了宿主机和docker容器互通的两个目录,其中:
/mydocker/mydockerfile/tomcat9/test
与/usr/local/apache-tomcat-9.0.46/webapps/test
目录对应,通过对宿主机的test目录修改就能同步到docker容器上,下面尝试在本机test目录编写一个小的web应用,看是否tomcat容器同步且能浏览到。
验证 1 2 3 4 5 6 7 8 [root@dk tomcat9] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@dk tomcat9] c38aace076e1ad830c61858650eeb8c36dc59e82d56ec3e71c655b09167d8eaa [root@dk tomcat9] CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c38aace076e1 hjtomcat "/bin/sh -c '/usr/lo…" 6 seconds ago Up 5 seconds 0.0.0.0:9080->8080/tcp, :::9080->8080/tcp myt9 [root@dk tomcat9]
结合前述容器卷将测试的web服务在test目录发布 以下是一个简单的java web项目所需要的东西:
web.xml
1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns ="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation ="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id ="WebApp_ID" version ="2.5" > <display-name > test</display-name > </web-app >
a.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" > <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" > <title>Insert title here</title> </head> <body> -----------welcome------------ <%="i am in docker tomcat self " %> <br> <br> <% System.out.println("=============docker tomcat self" );%> </body> </html>
宿主机往容器卷添加完文件后,查看容器:
重启容器:
访问test目录下的小web应用:
可以看到,访问成功。此时想要修改页面,直接在主机上修改即可,容器卷数据也会有相应的变化。
总结
上一篇 容器数据卷