《第一本Docker书》 学习笔记(三).用 Dockerfile 构建镜像

用 Dockerfile 构建镜像

我们不推荐使用 docker  commit 的方法来构建镜像。

推荐使用 Dockerfile 定义文件和 docker  build  命令来构建镜像。 Dockerfile 使用基本的基于 DSL 语法的指令来构建一个 Docker 镜像,之后使用 docker  build 命令基于该 Dockerfile 中的指令构建一个新的镜像。

此处用一个实例来演示用简单的 dockerfile 来构建镜像:

mkdir  static_web      #这里我们创建了一个目录,用来保存 Dockerfile ,这个目录我们用来作为构建环境 ( build  environment ) ,也叫上下文 ( context )  。 Docker 会在构建镜像时将构建上下文和该上下文中的文件和目录上传到 Docker 守护进程。这样 Docker 守护进程就能直接访问你想在镜像中存储的任何代码、文件或者其他数据。

cd  static_web

vim  Dockerfile

12

Dockerfile 由一系列指令和参数组成。每条指令都必须为大写字母,且要跟一个参数。例如此处的 FROM  ubuntu:14.04 。

Dockerfile 也是从上往下依序执行,所以应该根据实际需求合理安排顺序。

每条指令都会创建一个新的镜像层并对镜像进行提交。Docker 大体按照如下流程执行 Dockerfile 中的指令:

  • Docker 从基础镜像运行一个容器。
  • 执行一条指令,对容器做出修改。
  • 执行类似 docker  commit 的操作,提交一个新的镜像层。
  • Docker 再基于刚提交的镜像运行一个新的容器。
  • 执行 Dockerfile 中的下一条指令,直到所有的指令都执行完毕。

从上面看到,如果 Dockerfile 由于某些原因(如某条指令失败了)没有正常结束,那么你仍将得到一个可以使用的镜像,你可以基于该镜像运行一个具备交互功能的容器,使用最后创建的镜像进行调试。

每个 Dockerfile 的第一条指令都应该是 FROMFROM 指定一个已经存在的镜像,后续指令都基于此镜像进行,这个是基础镜像。

接着是 MATINTAINER 指令,指定镜像作者和邮件地址。

接着是三条 RUN 指令。 RUN 指令会在当前镜像中运行指定的命令(就是后面的参数)。

默认情况下, RUN 指令会在 shell 里使用命令包装器 /bin/sh  -c 来执行。如果当前环境不支持 shell 或者你不希望在 shell 中运行,可以使用 exec 格式的 RUN 指令:

RUN  [  “apt-get”,  “install”,  “-y”  “nginx”  ]

在这种方式中,使用数组来指定命令和传递参数。

接着是 EXPOSE 指令。 这条指令告诉 Docker 该容器内的应用程序会使用该容器的指定端口。出于安全原因, Docker 不会自动开启一个端口,这需要在运行容器的时候指定需要打开的端口。 可以指定多个EXPOSE 指令来向外部公开多个端口。

接着上面的 Dodckerfile ,可以开始构建一个新的镜像了:

docker  build  -t=”wangyanfu/nginx:v1″  .

docker  build 用来构建新镜像, -t  选项为新镜像设置了仓库和名称,此处仓库名 wangyanfu ,镜像名 nginx ,并且为 nginx 镜像加了一个 v1 的标签。注意最后还有一个 ” . ” 指定了Dockerfile 的路径为当前目录。

之后可以看到 Dockerfile 的每条指令都会被按顺序执行。

Dockerfile 和构建缓存

因为每一步构建都会将结果提交为镜像,这里我们可以将其看做缓存。如果不想使用缓存,可以在 docker build  后面加上 –no-cache 

查看新做好的镜像:

docker  images  wangyanfu/nginx:v1

如果想深入探求镜像是如何构建出来的,可以使用 docker  history  命令:

docker  history  wangyanfu/nginx:v1

23

从新镜像启动容器:

root@docker:~# docker  run  -d  -p  80:80  –name  my_nginx  wangyanfu/nginx:v1  nginx  -g  “daemon  off;”
-d :指定 Docker 以 分离 ( detached ) 的方式在后台运行。此处对于我们的 Nginx 守护进程非常适合。

nginx  -g  “daemon  off;”  指定容器中需要运行的命令。

-p : 指定公开端口。(这里一般是 宿主机端口:容器内端口 这种写法来绑定,也可以直接标注一个容器内端口,来绑定到宿主机的随机端口,还可以加上宿主机的具体网卡 :127.0.0.1:8080:80 ,还可以通过端口绑定时使用  /udp 后缀来指定 UDP 端口)

运行一个容器时, Docker 可以通过两种方式在宿主机上分配端口。

  • Docker 可以在宿主机中随机选择一个位于 49000~49900 的一个比较大的端口号来映射到容器中的 80 端口上。
  • 可以在 Docker 宿主机中指定一个具体的端口号来映射到容器中的 80 端口上。

docker  ps 命令可以查看端口映射的情况。

docker  port  wangyanfu/nginx:v1  80 可以查看到映射情况的容器。

-P : 对外公开 EXPOSE 命令公开的所有端口。

端口映射到宿主机后,我们就可以通过宿主机的IP进行访问了。

 

Dockerfile 指令

1. CMD

 CMD 指令用于指定一个容器启动时要运行的命令。和之前我们用过的 RUN 不一样的是, RUN 是指定镜像被构建时要运行的命令,而 CMD 是指定镜像被启动时要运行的命令。

CMD  [  “/bin/bash” ]   或者  CMD [ “/bin/bash”, “-l” ] 

需要注意的是,要运行的命令是存放在一个数组结构中的。这将告诉 Docker 按指定的原样来运行该命令。当然也可以不按照数组结构来指定命令,但这时候 Docker 会在指定的命令前面加上 /bin/sh  -c ,这在执行该命令的时候可能会导致意外失败。

最后,使用 dokcer  run 命令可以覆盖掉 CMD 的命令。 如果我们在 Dockerfile 里指定了 CMD 指令,而同时在 docker run 命令中也指定了要运行的命令,命令行中指定的命令会覆盖 Dockerfile中的 CMD 指令。

在 Dockerfile 中只能指定一条 CMD 指令。如果指定了多条 CMD 指令,也只有最后一条 CMD 会被使用。

2.ENTRYPOINT

ENTRYPOINT 和 CMD 类似,但不容易被覆盖,实际上 docker  run 命令行中指定的任何参数都会被当作参数再次传递给 ENTRYPOINT 指令中指定的命令。

ENTRYPOINT [ “/usr/bin/nginx” ]

ENTRYPOINT [ “/usr/bin/nginx”,  “-g”,  “daemon off;” ]

此处有个小技巧,可以使用 ENTRYPOINT 指定要运行的命令,然后再在 docker  run 的时候指定参数。

例如 Dockerfile 里面写上 ENTRYPOINT [ “/usr/bin/nginx” ] ,然后启动容器时 docker  run  -t  -i   镜像名  -g  “daemon  off;”

或者像这样:

ENTRYPOINT   [ “/usr/bin/nginx” ]

CMD  [  “-g”,  “daemon off;”  ]

如果想要覆盖,可以在加上参数 : docker run  –entrypoint 

3.WORKDIR

 WORKDIR 指令用来在从镜像创建一个新容器时,在容器内部设置一个工作目录,ENTRYPOINT 和/ 或 CMD 指定的程序会在这个目录下执行。

我们可以使用该指令为 Dockerfile 中后续的一系列指令设置工作目录,也可以为最终的容器设置工作目录。

docker  run  -w  覆盖。

4.ENV

5.USER

6.VOLUEM

7.ADD

8.COPY

9.ONBUILD

参考 http://docs.docker.com/reference/builder/

 

Proudly powered by WordPress | Theme: Code Blog by Crimson Themes.