一、问题

以交互式启动一个容器,在里面对容器进行修改,并对修改后的容器提交为镜像。这样可以正常工作,但是谁知道你对容器做了什么啊??这叫黑箱操作!所以我想要一个工具自动构建镜像,并且将构建步骤与他人共享。

二、解决方案

要想自动创建Docker镜像,需要用到Docekrfile的说明文件来描述镜像构建的步骤。这个文本文件使用一组指令来描述一下各项内容:

  1. 新镜像的基础镜像
  2. 为了安装不同依赖和应用程序需要执行那些操作步骤
  3. 镜像中需要提供那些文件
  4. 这些文件是怎么复制到镜像中的
  5. 要暴露那些端口
  6. 以及在新的容器中启动时默认运行什么命令
  7. 等等

为了对此进行说明,我们编写一个Dockerfile,在当前工作目录下面创建一个名为Dockerfile的文本文件,文件内容如下所示。

  1. FROM ubuntu
  2. ENTRYPOINT ["/bin/echo"]

FROM指令指定了的镜像以哪一个镜像作为基础开始构建。这里我们选择ubuntu镜像作为基础镜像。ENTRYPOINT指令设置了从该镜像创建的容器启动时需要执行的命令,想要构建这个镜像可以在命令行提示符下键入docker build .命令。如下所示。

  1. $ docker build .
  2. Sending build context to Docker daemon 344.5MB
  3. Step 1/2 : FROM ubuntu
  4. ---> d70eaf7277ea
  5. Step 2/2 : ENTRYPOINT ["/bin/echo"]
  6. ---> Running in ca27a0ac9d76
  7. Removing intermediate container ca27a0ac9d76
  8. ---> e68ac1007341
  9. Successfully built e68ac1007341
  10. $ docker images
  11. REPOSITORY TAG IMAGE ID CREATED SIZE
  12. <none> <none> e68ac1007341 About a minute ago 72.9MB

现在就可以基于新镜像启动容器了,只需要指定镜像的ID和一个参数,如下所示。

  1. $ docker run e68ac1007341 Hello Docker !
  2. Hello Docker !

也可以在Dockerfile里面使用CMD指令。使用该指令的优点时,你可以在启动容器时,可以通过docker run命令后面指定新的CMD参数来覆盖Dockerfile文件中设置的内容。Let go try it

  1. $ vim Dockerfile
  2. $ docker build .
  3. ·······
  4. Successfully built 475a936e4495
  5. $ docker run 475a936e4495
  6. Hello Docker!

上面构建命令中,我们指定当前文件夹路径,Docker会自动使用刚才创建的Dockerfile文件。如果希望构建镜像的时候使用在其他位置保存的Dockerfile,可以使用docker build 命令的 -f参数来指定Dockerfile文件的位置。

如果在docker run 命令后面指定一个其它的执行命令,那么这个CMD就会覆盖掉Dockerfile文件中定义的/bin/echo命令,如下所示。

  1. $ docker run 475a echo 123
  2. 123

三、讨论

Dockerfile是一个文本文件,它定义了一个镜像时如何构建的,以及基于该镜像创建的容器运行时会进行什么处理。当然Dockerfile指令不止FROM ENTRYPOINT 和CMD三个简单的指令,可以阅读Dockerfile参考手册(https:docs.docker.com/reference/builder/)学习一下指令。
请记住CMD指令可以docker run后面的参数来进行覆盖吗,而ENTRYPOINT只能通过docker run 的 —entrypoint 参数来进行覆盖。

  1. $ docker images
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. <none> <none> e68ac1007341 About a minute ago 72.9MB

构建结束了我们看到,新的镜像没有仓库名和标签信息,因为在构建的时候没有指定这些信息。可以重新构建该镜像,通过docker build命令的 -t参数将仓库名设置为ubuntu,标签设置为sayhello。由于这些操作都是在本地进行的,所以你可以随意对镜像仓库和标签进行命名。但是,如果你想将镜像发布到registry,你就需要遵循一定的命名约定。

  1. $ docker build -t ubuntu:sayhello .
  2. $ docker images
  3. REPOSITORY TAG IMAGE ID CREATED SIZE
  4. ubuntu sayhello 475a936e4495 2 hours ago 72.9MB

四、参考