docker学习笔记4.1-使用Dockerfile文件构建镜像

Dockerfile文件

Dockerfile 使用基于DSL语法的指令来构建一个Docker镜像,之后使用docker build命令基于该Dockerfile的指令构建一个新的镜像。

关于DSL语言,博主仔细查阅了一下,有兴趣的可以参考郭晓刚老师翻译的《领域专用语言实战》http://book.51cto.com/art/201310/412336.htm

  1. 创建Dockerfile文件

    我们必须创建一个目录来保存Dockerfile,这个目录被称为构建上下文(build context)。Docker会在构建镜像时将该上下文中的所有目录和文件都上传到Docker的守护进程,便于Docker直接访问你想在镜像中存储的所有代码、文件和数据等。

    创建代码如下:

#mkdir static_web
#cd static_web
#vim Dockerfile

博主的Dockerfile文件如下:

  • 每个Dockerfile由一系列的指令和参数构成。
  • 指令必须为大写字母,而且后面必须要跟一个参数。
  • Dockerfile的指令是从上往下顺序执行的。

Dockerfile指令详解

  • 每个Dockerfile的第一个指令都是FROM,用来指定一个基础镜像。
  • 在上图的Dockerfile文件中,我们接着指定了MAINTAINER指令,该指令指明了Docker的作者、作者邮箱
  • RUN指令;在上例中我们更新了apt库并安装了nginx服务然后创建了nginx的index.html。每条RUN指令执行完毕之后都会提交一个新的镜像层,
  • EXPOSE指令;告诉容器中的应用程序在RUN的时候可以访问指定端口。为了安全,Docker不会主动打开该端口,之后在RUN的时候开放改端口。EXPOSE指令也可以将多个容器链接,后续再介绍。

Dockerfile执行流程

  1. 从基础镜像运行一个容器
  2. 执行一条指令
  3. 提交一个新的镜像层
  4. 基于刚才的镜像层构建一个新容器
  5. 执行下一条指令,直到所有指令执行完毕

从这里也能看到我们Docker采用的“写时复制”的概念。这样的好处一方面是轻量化,另一方面就是即使中间某一个指令运行出错,我们也可以很方便的基于前一个运行完好的镜像进行调试,而且调试好之后不用再次运行前面已经运行好了的指令。

基于Dockerfile构建新镜像

构建镜像代码如下:

docker build -t="zhangyang/static_web" .

-t 选项指定了创建新镜像的仓库名和镜像名。例如我的仓库名就是自己的名字zhangyang镜像名是static_web
最后的 .告诉Docker从当前目录去寻找Dockerfile文件,当然也可以指定一个Git的地址。

执行过程如下:
docker学习笔记4.1-使用Dockerfile文件构建镜像_第1张图片
docker学习笔记4.1-使用Dockerfile文件构建镜像_第2张图片
docker学习笔记4.1-使用Dockerfile文件构建镜像_第3张图片

可以看到,最终返回了该镜像的ID b92c35890d8a
而且在每一个step运行完毕之后都会返回一个ID,即Docker会提交每一步的执行结果。

Dockerfile指令运行失败

博主在这里把我的dockerfile文件的nginx故意错写为ngnx,然后build.报错如下:
docker学习笔记4.1-使用Dockerfile文件构建镜像_第4张图片
我们可以看到,错误出在step4,而在step3结束之后就提交了一个新的镜像层e8ec593f1475
我们可以使用命令

docker run -i -t e8ec593f1475 /bin/bash

进入该容器进行调试,解决了该问题之后再退出容器修改Dockerfile文件相应的出错位置。

Dockerfile和构建缓存

Docker将每一步结束之后提交的镜像层当作缓存。

然而有些时候我们必须确保之前的缓存被覆盖掉。例如,如果已经缓存了之前的第三步,即 apt-get update 但是我们必须确保接下来安装的软件是最新版本,那就必须忽略缓存功能。可以使用docker build 的–no-cache 标志。

docker build --no-cache -t="zhangyang/static_web" .

构建基于缓存的Dockerfile模板

我们可以在Dockerfile文件中使用ENV指令来设置一个环境变量,此环境变量用来指明该模板最后的更新时间。
Dockerfile模板文件示例如下:

FROM Ubuntu14.04
MAINTAINER zhangyang "[email protected]"
ENV REFRESHED_AT 2014-07-01
RUN apt-get -qq update

博主在上述文件创建了一个环境变量REFRESHED_AT。
也就是说,在每次需要刷新构建的时候,只要修改ENV指令中的日期值就可以重置缓存,包缓存会被update成为最新值。

查看新镜像

docker images zhangyang/static_web 

这里写图片描述

docker history zhangyang/static_web

这条命令会显示镜像构建过程

此命令详细显示了镜像构建的每一层,以及其Docker指令

从新镜像启动容器时的端口设置

-p标志指定容器在运行时开放哪些端口给宿主机
-P(大写)标志将Dockerfile文件中的EXPOSE指定的端口全部开放

从新镜像启动一个容器:

docker run -d -p 80 --name static_web_2 zhangyang/static_web / nginx -g "daemon off;"

上述命令运行了一个名为static_web_2的新容器,选项-d是告诉Docker在后台以分离(detached)方式运行,这种模式非常适合nginx这样需要长时间运行的进程。最后我们还指定了在容器中需要运行的命令:nginx -g “daemon off;”。这将以前台的方式运行nginx来作为我们的服务器。

-p选项把80端口开放给了宿主机,Docker可以有两种模式来开放端口:

  • 在宿主机上随即选取49153-65535的一个端口映射到容器的80端口
  • 指定具体的端口号映射到80端口

我们可以使用下面的命令来查看端口分配情况:

docker ps -l

也可以使用docker port ID 端口号 来查看被映射的宿主机上的具体端口号。

效果如下图所示:
docker学习笔记4.1-使用Dockerfile文件构建镜像_第5张图片


docker run -d -p 127.0.0.1:80:80 --name static_web_2 zhangyang/static_web \nginx -g "daemon off;"

也可以直接指定宿主机上的某一个端口映射给容器。但显然这样这能运行一个Docker不利于我们充分发挥Docker的优势。
如果非要指定宿主机的IP地址的话可以这样写:

docker run -d -p 127.0.0.1::80 --name static_web_2 zhangyang/static_web \nginx -g "daemon off;"

该命令会随机分配一个127.0.0.1上的端口映射到容器的80端口上

你可能感兴趣的:(docker)