当前位置:   article > 正文

Docker定制镜像(Dockerfile)_docker build指定dockerfile

docker build指定dockerfile

一、什么是 Dockerfile?

        dockerfile 是用来构建 docker 镜像的命令参数脚本文件。

        镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile

        Dockerfile 是一个文本文件,其内包含了一条条的指令 (Instruction),每一条指令构建一层,因此每一条指令的内容, 就是描述该层应当如何构建。

二、Dockerfile 规则:

1、格式

        # 是注释,指令建议要大写,内容小写。这样更能区分。比如:FROM centos

2、执行顺序

        docker 是按照 Dockerfile 指令顺序依次执行的,也就是说从上到下。

3、其他

        每一个 Dockerfile 的第一行都是非注释性的,也就是说第一行不能是注释,必须是 FROM 指令,来指定基础镜像,后面的指令都以基础镜像为运行环境。如果构建过程中本地没有指定镜像文件,就会去远端仓库拉。

三、Dockerfile 指令:

前提:

        首先根据自己的需要在指定目录下先创建一个 dockerfile 文件,我是在 /usr/local/dockerfile 目录下创建的自己的 xhf_dockerfile 文件。如下图所示。

        接下来我们要说的这些标签,都是这个 xhf_dockerfile 文件里面的内容。

FROM 标签

        这个 FROM 指令是 dockerfile 的第一个指令,然后指定了基础镜像,后面的所有指令都是运行在该基础镜像环境上的。

  1. # tag 是可选的,如果不使用这两个值时,会使用 latest 版本的基础镜像
  2. FROM <image>
  3. FROM <image>:<tag>
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8

MAINTAINER 标签

        该指令是描述的维护者信息。

MAINTAINER <name>
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 作者的名字为 xhf ,邮箱是1982392926@qq.com
  4. MAINTAINER xhf<1982392926@qq.com>

ENV 标签

        该指令是用于定义环境变量的

  1. # 两种写法都可以满足
  2. ENV <key>=<value>
  3. ENV <key> <value>
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 作者的名字为 xhf ,邮箱是1982392926@qq.com
  4. MAINTAINER xhf<1982392926@qq.com>
  5. # 定义一个变量 MYPATH,路径为 /usr/local
  6. ENV MYPATH /usr/local

WORKDIR 标签

        该指令是切换到 WORKDIR 目录下工作,这个与 linux 里面的 cd 差不多。如果 WORKDIR 不存在,它将被创建。

        需要注意的是通过 WORKDIR 设置工作目录后,Dockerfile 中其后的命令 RUNCMDENTRYPOINTADDCOPY 等命令都会在该目录下执行。在使用 docker run 运行容器时,可以通过 -w 参数覆盖构建时所设置的工作目录。

  1. WORKDIR /usr/workdir
  2. # 这时工作目录为/a
  3. WORKDIR /a
  4. # 这时工作目录为/a/b
  5. WORKDIR b
  6. # 这时工作目录为/a/b/c
  7. WORKDIR c
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 作者的名字为 xhf ,邮箱是1982392926@qq.com
  4. MAINTAINER xhf<1982392926@qq.com>
  5. # 定义一个变量 MYPATH,路径为 /usr/local
  6. ENV MYPATH /usr/local
  7. # 切换到 MYPATH 的路径下
  8. WORKDIR $MYPATH

        这个命令啥时候会生效呢?会等我们进入容器的时候生效,下面这个截图是如果我们不加这行命令创建的容器,默认进入时候的路径。 

        下面这个截图是加了这行命令后,进入容器默认的当前路径。

RUN 标签

        该指令用于在容器中执行命令。我们常用来安装基础软件,或者执行一些命令。

        需要注意的是 RUN 指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定 --no-cache 参数,如:docker build --no-cache

  1. # 第一种 shell 执行,eg: RUN mkdir /usr/local/tomcat/webapps/ROOT
  2. RUN <command>
  3. # 第二种 exec 执行,eg:echo 'Hello xhf Docker'>/usr/local/tomcat/webapps/ROOT/index.html
  4. RUN ["executable", "param1", "param2"]
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 作者的名字为 xhf ,邮箱是1982392926@qq.com
  4. MAINTAINER xhf<1982392926@qq.com>
  5. # 定义一个变量 MYPATH,路径为 /usr/local
  6. ENV MYPATH /usr/local
  7. # 切换到 MYPATH 的路径下
  8. WORKDIR $MYPATH
  9. # 在容器的指定目录下创建一个 ROOT 文件夹
  10. RUN mkdir -p /usr/local/tomcat/webapps/ROOT/

        也可以这么用

  1. # 安装 yum 工具
  2. RUN yum -y install vim
  3. # 安装网络监测工具
  4. RUN yum -y install net-tools

ADD 标签

        该指令是用来将宿主机某个文件或目录放到(复制)容器某个目录下面。

        如果复制的文件是 tar 类型的,那么该文件会自动解压 ( 网络压缩资源不会被解压 ) ,可以访问网络资源,类似 wget

  1. ADD <src>... <dest>
  2. ADD ["<src>",... "<dest>"]

         我们自己创建一个 index.html 文件用于测试,内容很简单。

  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 作者的名字为 xhf ,邮箱是1982392926@qq.com
  4. MAINTAINER xhf<1982392926@qq.com>
  5. # 定义一个变量 MYPATH,路径为 /usr/local
  6. ENV MYPATH /usr/local
  7. # 切换到 MYPATH 的路径下
  8. WORKDIR $MYPATH
  9. # 在容器的指定目录下创建一个 ROOT 文件夹
  10. RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
  11. # 将 index.html 放到指定的目录下
  12. ADD index.html /usr/local/tomcat/webapps/ROOT/index.html

EXPOSE 标签

        该指令用于暴露容器里的端口,没有什么用,加了和不加没有什么区别,仅仅是为了告诉使用这个镜像的人,我的这个容器用到了 xxxx 端口号。

EXPOSE 端口
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 作者的名字为 xhf ,邮箱是1982392926@qq.com
  4. MAINTAINER xhf<1982392926@qq.com>
  5. # 定义一个变量 MYPATH,路径为 /usr/local
  6. ENV MYPATH /usr/local
  7. # 切换到 MYPATH 的路径下
  8. WORKDIR $MYPATH
  9. # 在容器的指定目录下创建一个 ROOT 文件夹
  10. RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
  11. # 将 index.html 放到指定的目录下
  12. ADD index.html /usr/local/tomcat/webapps/ROOT/index.html
  13. # 对外暴露 8080 端口
  14. EXPOSE 8080

build 标签

        该标签用于构建镜像,我们先执行一下我上面的这些命令,验证一下,将目录切换到 /usr/local/dockerfile 下,因为我的 xhf_dockerfile 文件在这个目录下面,执行以下的命令:

  1. docker build -f xhf_dockerfile -t mytomcat:0.1 .
  2. # -f xhf_dockerfile 表示构建的文件路径
  3. # -t 镜像名称:版本号
  4. # . 表示当前路径
  5. # 如果你当前的目录下只有一个 dockerfile 文件,那么可以省略 -f 参数,如下所示:
  6. docker build -t mytomcat:0.1 .

        执行完命令之后,我们可以看下镜像是否成功创建了 

        然后用我们自己的镜像创建容器,输入命令如下所示:

docker run --rm -d --name tomcat-8082 -p 8082:8080 mytomcat:0.1

        接下来我们需要验证两个东西,第一个东西是当我们进入到容器里面,默认的目录是不是 /usr/local ,第二个需要验证的是访问 tomcat 看是否可以出现登录页,因为登录页是我们自己复制过去的,如下所示,这两个需要验证的东西都没有问题。

COPY 标签

        该标签功能类似于 ADD 标签,但是是不会自动解压文件,也不能访问网络资源。

COPY <源路径> <目标路径>
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 在容器的指定目录下创建一个 ROOT 文件夹
  4. RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
  5. # 将 index.html 复制到指定的目录下
  6. COPY index.html /usr/local/tomcat/webapps/ROOT/index.html

VOLUME 标签

        该标签用于在 image 中创建一个挂载目录,以挂载宿主机上的目录。

  1. # path 代表容器中的目录,与 docker run 不同,Dockerfile 中不能指定宿主机目录,默认使用 docker 管理的挂载点
  2. VOLUME <path>
  3. VOLUME ["path"]
  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 在容器的指定目录下创建一个 ROOT 文件夹
  4. RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
  5. # 将 index.html 复制到指定的目录下
  6. COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
  7. # 创建两个挂载点
  8. 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 中无法指定主机上对应的目录,是自动生成的。相当于不指定宿主机的目录创建挂载点。执行下面的语句进行测试查看。

  1. # 指定基础镜像为 tomcat:8
  2. FROM tomcat:8
  3. # 在容器的指定目录下创建一个 ROOT 文件夹
  4. RUN mkdir -p /usr/local/tomcat/webapps/ROOT/
  5. # 将 index.html 复制到指定的目录下
  6. COPY index.html /usr/local/tomcat/webapps/ROOT/index.html
  7. # 创建两个挂载点
  8. VOLUME ["/data1","/data2"]
  1. # 构建镜像
  2. docker build -f xhf_dockerfile -t mytomcat:0.3 .
  3. # 构建容器
  4. docker run --rm -d --name tomcat-8083 -p 8083:8080 mytomcat:0.3

        查看挂载点,会发现一共有两个自动挂载的目录,如下图所示:

CMD 标签

        该标签是构建容器后调用的,也就是在容器启动时才进行调用。

        一个 Dockerfile 只有一个 CMD 指令,若有多个,只有最后一个 CMD 指令生效。

        CMD 主要目的:为容器提供默认执行的命令,这个默认值可以包含可执行文件,也可以不包含可执行文件,意味着必须指定 ENTRYPOINT 指令(第二种写法)。

        注意和 RUN 指令的区别,RUN 是构建镜像时执行的命令,执行的时期不同。

  1. # shell格式
  2. CMD <命令>
  3. # exec格式
  4. CMD ["可执行文件", "参数1", "参数2", …]

        修改我们的 xhf_dockerfile 文件,改写成下面的内容:

  1. # 指定基础镜像为 centos:7
  2. FROM centos:7
  3. CMD echo "This is a test."

        执行下面的命令,并且启动容器,如下所示,我们可以看到可以正常执行 CMD 标签的内容。

  1. # 构建镜像
  2. docker build -f xhf_dockerfile -t mycentos:0.1 .
  3. # 启动容器
  4. docker run mycentos:0.1

ENTRYPOINT 标签

        该标签是指定容器启动的要运行的命令,可以追加命令。

        ENTRYPOINT CMD 非常类似,不同的是通过 docker run 执行的命令不会覆盖ENTRYPOINT,而 docker run 命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT

        Dockerfile 中只允许有一个 ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的 ENTRYPOINT 指令。

  1. ENTRYPOINT ["executable", "param1", "param2"]
  2. ENTRYPOINT command param1 param2 (shell内部命令)

        修改我们的 xhf_dockerfile 文件,改写成下面的内容:

  1. # 指定基础镜像为 centos:7
  2. FROM centos:7
  3. ENTRYPOINT ["echo", "dockerfile-entrypoint test"]
  4. ENTRYPOINT ["ls", "-a"]

        执行下面的命令,并且启动容器,如下所示,我们可以看到可以 ENTRYPOINT 标签的只执行了最后一行。

  1. # 构建镜像
  2. docker build -f xhf_dockerfile -t mycentos:0.2 .
  3. # 启动容器
  4. docker run mycentos:0.2

        接下来我们在 docker run 命令行种追加命令参数,新添加的参数会追加到原 dockerfile 的 ENTRYPOINT 命令里。

        相当于在 Dockerfile ENTRYPOINT 里追加了 -l 的参数,即【ls -a -l】。启动容器,如下所示,我们发现是可以正常执行的。

         我们再追加一些错误的参数,看看容器启动的时候会不会报错,如下所示,是会报错的。

CMD 和 ENTRYPOINT 配合使用

        一般情况下,ENTRYPOINT CMD 标签都是互相配合使用的,即:ENTRYPOINT 填写固定的命令,CMD 填写该固定命令对应的参数,CMD 将这个参数传递给 ENTRYPOINT命令。可以理解为 CMD 参数为 ENTRYPOINT 的默认值,如果项目中使用的不是 CMD 的默认值,就可以在启动 docker 容器时添加上真实的参数值,用来覆盖 CMD 的默认值。

        举个例子,比如要在镜像中通过 java -jar 的方式启动一个 java 工程,就可以采用下面的方式,默认启动的时候 commcon.jar 这个工程。

  1. ENTRYPOINT ["java", "-jar"]
  2. CMD ["common.jar"]

        如果我们不想启动这个 common.jar 的工程了,我们在启动容器的时候更换下命令就可以了,如下所示:

docker run 容器名称 xxxx.jar

实战生成 jdk 镜像:

        接下来我们测试下 CMD 和 ENTRYPOINT 标签,在实际应用中到底是不是按照我们想象的这种方式执行。

        第一步、新建两个 springboot 工程,很简单的就可以,命名为 DockerTestOne  和 DockerTestTwo,主要的内容我简单的贴下,如下所示,这两个工程唯一的区别就是名字和输出不一样,其他的都一样。

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>1.5.8.RELEASE</version>
  5. </parent>
  6. <build>
  7. <plugins>
  8. <plugin>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-maven-plugin</artifactId>
  11. <configuration>
  12. <fork>true</fork>
  13. </configuration>
  14. </plugin>
  15. </plugins>
  16. </build>
  17. <dependencies>
  18. <dependency>
  19. <groupId>junit</groupId>
  20. <artifactId>junit</artifactId>
  21. <scope>test</scope>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter</artifactId>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.springframework.boot</groupId>
  29. <artifactId>spring-boot-starter-test</artifactId>
  30. <scope>test</scope>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.springframework.boot</groupId>
  34. <artifactId>spring-boot-starter-web</artifactId>
  35. </dependency>
  36. </dependencies>
  1. @SpringBootApplication
  2. public class App
  3. {
  4. public static void main( String[] args )
  5. {
  6. //将springboot应用驱动起来
  7. SpringApplication.run(App.class, args);
  8. }
  9. }
  1. @RestController
  2. public class HelloWorld {
  3. @RequestMapping("/hello")
  4. public String Hello(String name) {
  5. return "Hello"+name+" from DockerTestOne";
  6. }
  7. }
  1. @RestController
  2. public class HelloWorld {
  3. @RequestMapping("/hello")
  4. public String Hello(String name) {
  5. return "Hello"+name+" from DockerTestOne";
  6. }
  7. }

        构建出两个可执行的 jar 包,分别重命名为 docker_testone.jar  docker_testtwo.jar 。然后将这两个 jar 包复制到 xhf_dockerfile 同等级的目录下备用。

        第二步、下载一个 linux 环境的 jdk,下载地址是这个,然后也把这个 jdk 复制到上面说的目录下,如图所示:

        第三步、修改 xhf_dockerfile 文件,内容如下所示:

  1. FROM centos:7
  2. MAINTAINER xhf<1982392926@qq.com>
  3. ADD jdk-8u371-linux-x64.tar.gz /usr/local/
  4. ADD docker_testone.jar /usr/local/
  5. ADD docker_testtwo.jar /usr/local/
  6. RUN yum -y install vim
  7. ENV MYPATH /usr/local
  8. WORKDIR $MYPATH
  9. ENV JAVA_HOME /usr/local/jdk1.8.0_371
  10. ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
  11. ENV PATH $JAVA_HOME/bin
  12. ENTRYPOINT ["java", "-jar"]
  13. CMD ["docker_testone.jar"]

        第四步、创建镜像并启动容器,如下所示:

  1. docker build -f xhf_dockerfile -t mycentos:0.4 .
  2. docker run -d -p 8080:8080 --name mycentos mycentos:0.4

        第五步、在浏览器输入 http://localhost:8080/hello?name=World,结果如下所示,我们发现我们的服务可以正常启动和访问。

        第六步、关掉服务,删除容器,重新启动容器,命令如下,我们发现我们的服务被命令行的 jar 包替换掉了,启动之后还是正常的。

  1. docker stop mycentos
  2. docker rm -f mycentos
  3. docker run -d -p 8080:8080 --name mycentos mycentos:0.4 docker_testtwo.jar

实战生成 tomcat 镜像

        第一步、编写 xhf_dockerfile 文件,tomcat 下载地址在这,如下所示:

  1. FROM centos:7
  2. MAINTAINER xhf<1982392926@qq.com>
  3. ADD jdk-8u371-linux-x64.tar.gz /usr/local/
  4. ADD apache-tomcat-9.0.33.tar.gz /usr/local/
  5. RUN yum -y install vim
  6. ENV MYPATH /usr/local
  7. WORKDIR $MYPATH
  8. ENV JAVA_HOME /usr/local/jdk1.8.0_371
  9. ENV CLASSPATH $JAVA_HOME/lib/dt.jar;$JAVA_HOME/lib/tools.jar
  10. ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.33
  11. ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.33
  12. ENV PATH $PATH;$JAVA_HOME/bin;$CATALINA_HOME/lib;$CATALINA_HOME/bin
  13. EXPOSE 8080
  14. CMD /usr/local/apache-tomcat-9.0.33/bin/startup.sh && tailf /usr/local/apache-tomcat-9.0.33/logs/catalina.out

        第二步、构建和启动,命令如下:

  1. docker build -f xhf_dockerfile -t mytomcat:0.1 .
  2. 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,内容如下所示:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <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">
  3. </web-app>
  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <!DOCTYPE html>
  4. <html>
  5. <head>
  6. <meta charset="utf-8">
  7. <title>youngj</title>
  8. </head>
  9. <body>
  10. Hello World!<br/>
  11. <%
  12. System.out.println("你的 IP 地址 " + request.getRemoteAddr());
  13. %>
  14. </body>
  15. </html>

 第四步、测试,在浏览器输入 http://localhost:8080/test/index.jsp,内容如下所示:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/928960
推荐阅读
相关标签
  

闽ICP备14008679号