赞
踩
dockerfile 是用来构建 docker 镜像的命令参数脚本文件。
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条的指令 (Instruction),每一条指令构建一层,因此每一条指令的内容, 就是描述该层应当如何构建。
# 是注释,指令建议要大写,内容小写。这样更能区分。比如:FROM centos
2、执行顺序
docker 是按照 Dockerfile 指令顺序依次执行的,也就是说从上到下。
3、其他
每一个 Dockerfile 的第一行都是非注释性的,也就是说第一行不能是注释,必须是 FROM 指令,来指定基础镜像,后面的指令都以基础镜像为运行环境。如果构建过程中本地没有指定镜像文件,就会去远端仓库拉。
首先根据自己的需要在指定目录下先创建一个 dockerfile 文件,我是在 /usr/local/dockerfile 目录下创建的自己的 xhf_dockerfile 文件。如下图所示。
接下来我们要说的这些标签,都是这个 xhf_dockerfile 文件里面的内容。
这个 FROM 指令是 dockerfile 的第一个指令,然后指定了基础镜像,后面的所有指令都是运行在该基础镜像环境上的。
- # tag 是可选的,如果不使用这两个值时,会使用 latest 版本的基础镜像
- FROM <image>
- FROM <image>:<tag>
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
该指令是描述的维护者信息。
MAINTAINER <name>
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 作者的名字为 xhf ,邮箱是1982392926@qq.com
- MAINTAINER xhf<1982392926@qq.com>
该指令是用于定义环境变量的
- # 两种写法都可以满足
- ENV <key>=<value>
- ENV <key> <value>
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 作者的名字为 xhf ,邮箱是1982392926@qq.com
- MAINTAINER xhf<1982392926@qq.com>
-
- # 定义一个变量 MYPATH,路径为 /usr/local
- ENV MYPATH /usr/local
该指令是切换到 WORKDIR 目录下工作,这个与 linux 里面的 cd 差不多。如果 WORKDIR 不存在,它将被创建。
需要注意的是通过 WORKDIR 设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、 COPY 等命令都会在该目录下执行。在使用 docker run 运行容器时,可以通过 -w 参数覆盖构建时所设置的工作目录。
- WORKDIR /usr/workdir
-
- # 这时工作目录为/a
- WORKDIR /a
-
- # 这时工作目录为/a/b
- WORKDIR b
-
- # 这时工作目录为/a/b/c
- WORKDIR c
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 作者的名字为 xhf ,邮箱是1982392926@qq.com
- MAINTAINER xhf<1982392926@qq.com>
-
- # 定义一个变量 MYPATH,路径为 /usr/local
- ENV MYPATH /usr/local
-
- # 切换到 MYPATH 的路径下
- WORKDIR $MYPATH
这个命令啥时候会生效呢?会等我们进入容器的时候生效,下面这个截图是如果我们不加这行命令创建的容器,默认进入时候的路径。
下面这个截图是加了这行命令后,进入容器默认的当前路径。
该指令用于在容器中执行命令。我们常用来安装基础软件,或者执行一些命令。
需要注意的是 RUN 指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定 --no-cache 参数,如:docker build --no-cache
- # 第一种 shell 执行,eg: RUN mkdir /usr/local/tomcat/webapps/ROOT
- RUN <command>
-
- # 第二种 exec 执行,eg:echo 'Hello xhf Docker'>/usr/local/tomcat/webapps/ROOT/index.html
- RUN ["executable", "param1", "param2"]
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 作者的名字为 xhf ,邮箱是1982392926@qq.com
- MAINTAINER xhf<1982392926@qq.com>
-
- # 定义一个变量 MYPATH,路径为 /usr/local
- ENV MYPATH /usr/local
-
- # 切换到 MYPATH 的路径下
- WORKDIR $MYPATH
-
- # 在容器的指定目录下创建一个 ROOT 文件夹
- RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
也可以这么用
- # 安装 yum 工具
- RUN yum -y install vim
-
- # 安装网络监测工具
- RUN yum -y install net-tools
该指令是用来将宿主机某个文件或目录放到(复制)容器某个目录下面。
如果复制的文件是 tar 类型的,那么该文件会自动解压 ( 网络压缩资源不会被解压 ) ,可以访问网络资源,类似 wget。
- ADD <src>... <dest>
-
- ADD ["<src>",... "<dest>"]
我们自己创建一个 index.html 文件用于测试,内容很简单。
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 作者的名字为 xhf ,邮箱是1982392926@qq.com
- MAINTAINER xhf<1982392926@qq.com>
-
- # 定义一个变量 MYPATH,路径为 /usr/local
- ENV MYPATH /usr/local
-
- # 切换到 MYPATH 的路径下
- WORKDIR $MYPATH
-
- # 在容器的指定目录下创建一个 ROOT 文件夹
- RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
-
- # 将 index.html 放到指定的目录下
- ADD index.html /usr/local/tomcat/webapps/ROOT/index.html
该指令用于暴露容器里的端口,没有什么用,加了和不加没有什么区别,仅仅是为了告诉使用这个镜像的人,我的这个容器用到了 xxxx 端口号。
EXPOSE 端口
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 作者的名字为 xhf ,邮箱是1982392926@qq.com
- MAINTAINER xhf<1982392926@qq.com>
-
- # 定义一个变量 MYPATH,路径为 /usr/local
- ENV MYPATH /usr/local
-
- # 切换到 MYPATH 的路径下
- WORKDIR $MYPATH
-
- # 在容器的指定目录下创建一个 ROOT 文件夹
- RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
-
- # 将 index.html 放到指定的目录下
- ADD index.html /usr/local/tomcat/webapps/ROOT/index.html
-
- # 对外暴露 8080 端口
- EXPOSE 8080
该标签用于构建镜像,我们先执行一下我上面的这些命令,验证一下,将目录切换到 /usr/local/dockerfile 下,因为我的 xhf_dockerfile 文件在这个目录下面,执行以下的命令:
- docker build -f xhf_dockerfile -t mytomcat:0.1 .
-
- # -f xhf_dockerfile 表示构建的文件路径
-
- # -t 镜像名称:版本号
-
- # . 表示当前路径
-
-
- # 如果你当前的目录下只有一个 dockerfile 文件,那么可以省略 -f 参数,如下所示:
- docker build -t mytomcat:0.1 .
-
-
执行完命令之后,我们可以看下镜像是否成功创建了
然后用我们自己的镜像创建容器,输入命令如下所示:
docker run --rm -d --name tomcat-8082 -p 8082:8080 mytomcat:0.1
接下来我们需要验证两个东西,第一个东西是当我们进入到容器里面,默认的目录是不是 /usr/local ,第二个需要验证的是访问 tomcat 看是否可以出现登录页,因为登录页是我们自己复制过去的,如下所示,这两个需要验证的东西都没有问题。
该标签功能类似于 ADD 标签,但是是不会自动解压文件,也不能访问网络资源。
COPY <源路径> <目标路径>
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 在容器的指定目录下创建一个 ROOT 文件夹
- RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
-
- # 将 index.html 复制到指定的目录下
- COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
该标签用于在 image 中创建一个挂载目录,以挂载宿主机上的目录。
- # path 代表容器中的目录,与 docker run 不同,Dockerfile 中不能指定宿主机目录,默认使用 docker 管理的挂载点
- VOLUME <path>
- VOLUME ["path"]
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 在容器的指定目录下创建一个 ROOT 文件夹
- RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
-
- # 将 index.html 复制到指定的目录下
- COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
-
- # 创建两个挂载点
- VOLUME ["/data1","/data2"]
1、我们先使用 run -v 指定容器和宿主机的目录进行挂载,执行命令
docker run --rm -d --name tomcat-8081 -p 8081:8080 -v /usr/local/docker/ROOT:/usr/local/tomcat/webapps/ROOT tomcat:8
查看当前容器的挂载信息,如下所示,挂载的路径是我们上面指定的宿主和容器的路径,没有问题。
2、再次使用 docker run -v 参数,但不指定宿主机的目录,执行命令
docker run --rm -d --name tomcat-8082 -p 8082:8080 -v /usr/local/tomcat/webapps/ROOT tomcat:8
从下面可以看到,Source 的路径是自动分配的一个目录
3、使用 dockerfile 中挂载点进行测试。通过 docker run 命令的 -v 标识创建的挂载点只能对创建的容器有效。而通过 dockerfile 的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。但在 dockerfile 中无法指定主机上对应的目录,是自动生成的。相当于不指定宿主机的目录创建挂载点。执行下面的语句进行测试查看。
- # 指定基础镜像为 tomcat:8
- FROM tomcat:8
-
- # 在容器的指定目录下创建一个 ROOT 文件夹
- RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
-
- # 将 index.html 复制到指定的目录下
- COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
-
- # 创建两个挂载点
- VOLUME ["/data1","/data2"]
- # 构建镜像
- docker build -f xhf_dockerfile -t mytomcat:0.3 .
-
- # 构建容器
- docker run --rm -d --name tomcat-8083 -p 8083:8080 mytomcat:0.3
查看挂载点,会发现一共有两个自动挂载的目录,如下图所示:
该标签是构建容器后调用的,也就是在容器启动时才进行调用。
一个 Dockerfile 只有一个 CMD 指令,若有多个,只有最后一个 CMD 指令生效。
CMD 主要目的:为容器提供默认执行的命令,这个默认值可以包含可执行文件,也可以不包含可执行文件,意味着必须指定 ENTRYPOINT 指令(第二种写法)。
注意和 RUN 指令的区别,RUN 是构建镜像时执行的命令,执行的时期不同。
- # shell格式
- CMD <命令>
-
- # exec格式
- CMD ["可执行文件", "参数1", "参数2", …]
修改我们的 xhf_dockerfile 文件,改写成下面的内容:
- # 指定基础镜像为 centos:7
- FROM centos:7
-
- CMD echo "This is a test."
执行下面的命令,并且启动容器,如下所示,我们可以看到可以正常执行 CMD 标签的内容。
- # 构建镜像
- docker build -f xhf_dockerfile -t mycentos:0.1 .
-
- # 启动容器
- docker run mycentos:0.1
该标签是指定容器启动的要运行的命令,可以追加命令。
ENTRYPOINT 与 CMD 非常类似,不同的是通过 docker run 执行的命令不会覆盖ENTRYPOINT,而 docker run 命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT。
Dockerfile 中只允许有一个 ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的 ENTRYPOINT 指令。
- ENTRYPOINT ["executable", "param1", "param2"]
-
- ENTRYPOINT command param1 param2 (shell内部命令)
修改我们的 xhf_dockerfile 文件,改写成下面的内容:
- # 指定基础镜像为 centos:7
- FROM centos:7
- ENTRYPOINT ["echo", "dockerfile-entrypoint test"]
- ENTRYPOINT ["ls", "-a"]
执行下面的命令,并且启动容器,如下所示,我们可以看到可以 ENTRYPOINT 标签的只执行了最后一行。
- # 构建镜像
- docker build -f xhf_dockerfile -t mycentos:0.2 .
-
- # 启动容器
- docker run mycentos:0.2
接下来我们在 docker run 命令行种追加命令参数,新添加的参数会追加到原 dockerfile 的 ENTRYPOINT 命令里。
相当于在 Dockerfile 的 ENTRYPOINT 里追加了 -l 的参数,即【ls -a -l】。启动容器,如下所示,我们发现是可以正常执行的。
我们再追加一些错误的参数,看看容器启动的时候会不会报错,如下所示,是会报错的。
一般情况下,ENTRYPOINT 和 CMD 标签都是互相配合使用的,即:ENTRYPOINT 填写固定的命令,CMD 填写该固定命令对应的参数,CMD 将这个参数传递给 ENTRYPOINT命令。可以理解为 CMD 参数为 ENTRYPOINT 的默认值,如果项目中使用的不是 CMD 的默认值,就可以在启动 docker 容器时添加上真实的参数值,用来覆盖 CMD 的默认值。
举个例子,比如要在镜像中通过 java -jar 的方式启动一个 java 工程,就可以采用下面的方式,默认启动的时候 commcon.jar 这个工程。
- ENTRYPOINT ["java", "-jar"]
-
- CMD ["common.jar"]
如果我们不想启动这个 common.jar 的工程了,我们在启动容器的时候更换下命令就可以了,如下所示:
docker run 容器名称 xxxx.jar
接下来我们测试下 CMD 和 ENTRYPOINT 标签,在实际应用中到底是不是按照我们想象的这种方式执行。
第一步、新建两个 springboot 工程,很简单的就可以,命名为 DockerTestOne 和 DockerTestTwo,主要的内容我简单的贴下,如下所示,这两个工程唯一的区别就是名字和输出不一样,其他的都一样。
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.8.RELEASE</version>
- </parent>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <configuration>
- <fork>true</fork>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- </dependencies>
- @SpringBootApplication
- public class App
- {
- public static void main( String[] args )
- {
- //将springboot应用驱动起来
- SpringApplication.run(App.class, args);
- }
- }
- @RestController
- public class HelloWorld {
-
- @RequestMapping("/hello")
- public String Hello(String name) {
-
- return "Hello"+name+" from DockerTestOne";
- }
- }
- @RestController
- public class HelloWorld {
-
- @RequestMapping("/hello")
- public String Hello(String name) {
-
- return "Hello"+name+" from DockerTestOne";
- }
- }
构建出两个可执行的 jar 包,分别重命名为 docker_testone.jar 和 docker_testtwo.jar 。然后将这两个 jar 包复制到 xhf_dockerfile 同等级的目录下备用。
第二步、下载一个 linux 环境的 jdk,下载地址是这个,然后也把这个 jdk 复制到上面说的目录下,如图所示:
第三步、修改 xhf_dockerfile 文件,内容如下所示:
- FROM centos:7
- MAINTAINER xhf<1982392926@qq.com>
- ADD jdk-8u371-linux-x64.tar.gz /usr/local/
- ADD docker_testone.jar /usr/local/
- ADD docker_testtwo.jar /usr/local/
- RUN yum -y install vim
- ENV MYPATH /usr/local
- WORKDIR $MYPATH
- ENV JAVA_HOME /usr/local/jdk1.8.0_371
- ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
- ENV PATH $JAVA_HOME/bin
- ENTRYPOINT ["java", "-jar"]
- CMD ["docker_testone.jar"]
第四步、创建镜像并启动容器,如下所示:
- docker build -f xhf_dockerfile -t mycentos:0.4 .
-
- docker run -d -p 8080:8080 --name mycentos mycentos:0.4
-
-
第五步、在浏览器输入 http://localhost:8080/hello?name=World,结果如下所示,我们发现我们的服务可以正常启动和访问。
第六步、关掉服务,删除容器,重新启动容器,命令如下,我们发现我们的服务被命令行的 jar 包替换掉了,启动之后还是正常的。
- docker stop mycentos
-
- docker rm -f mycentos
-
- docker run -d -p 8080:8080 --name mycentos mycentos:0.4 docker_testtwo.jar
第一步、编写 xhf_dockerfile 文件,tomcat 的下载地址在这,如下所示:
- FROM centos:7
- MAINTAINER xhf<1982392926@qq.com>
- ADD jdk-8u371-linux-x64.tar.gz /usr/local/
- ADD apache-tomcat-9.0.33.tar.gz /usr/local/
- RUN yum -y install vim
- ENV MYPATH /usr/local
- WORKDIR $MYPATH
- ENV JAVA_HOME /usr/local/jdk1.8.0_371
- ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
- ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.33
- ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.33
- ENV PATH $PATH;$JAVA_HOME/bin;$CATALINA_HOME/lib;$CATALINA_HOME/bin
- EXPOSE 8080
- CMD /usr/local/apache-tomcat-9.0.33/bin/startup.sh && tailf /usr/local/apache-tomcat-9.0.33/logs/catalina.out
第二步、构建和启动,命令如下:
- docker build -f xhf_dockerfile -t mytomcat:0.1 .
-
- docker run -d -p 8080:8080 --name mytomcat -v /usr/local/tomcat/test:/usr/local/apache-tomcat-9.0.33/webapps/test -v /usr/local/tomcat/logs:/usr/local/apache-tomcat-9.0.33/logs mytomcat:0.1
第三步、新建 web.xml 和 index.jsp,内容如下所示:
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
- </web-app>
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>youngj</title>
- </head>
- <body>
- Hello World!<br/>
- <%
- System.out.println("你的 IP 地址 " + request.getRemoteAddr());
- %>
- </body>
- </html>
第四步、测试,在浏览器输入 http://localhost:8080/test/index.jsp,内容如下所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。