文章目录
  1. 1. 简单的Dockerfile例子
  2. 2. 稍微复杂点的例子

Dockerfile是docker构建镜像的推荐方式,Dockerfile使用基本的基于DSL语法的指令构建Docker镜像,之后使用docker build命令基于该Dockerfile中的指令构建一个新的镜像。

简单的Dockerfile例子

下面的例子是创建一个nginx为反向代理的web服务器的docker容器。

  • 首先创建一个构建环境(文件目录),用来存放Dockerfile等其他构建文件,因此这个环境也被称为上下文(context)或者构建上下文(build context)。
  • 其次创建Dockerfile

$ mkdir sample_web

Dockerfile

1
2
3
4
5
6
7
FROM ubuntu:14.04
MAINTAINER Richard Li "lirui.sep@gmail.com"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo 'Hello from docker' \
>/usr/share/nginx/html/index.html
EXPOSE 80

然后在构建目录下输入下面的docker命令:
$ docker build -t="nutshell/sample_web" .
注意命令的最后是一个“.”是告诉docker在当前目录下去寻找Dockerfile
一切正常,完成镜像构建。
下面就需要从新镜像启动容器,还记得启动容器的docker命令是什么嘛?
对就是 docker run <image name>
注意到我们的这个镜像是nginx,需要长时间运行的守护进程,查看docker run --help 的帮助文档后可以使用 -d 这个参数使容器以detach的方式在后台运行

于是我们就有了下面启动容器的docker命令:

1
2
$ docker run -d -p 80 --name static_web nutshell/sample_web \
nginx -g "daemon off;"

运行后没有报错,说明容器启动成功,这时候使用docker ps -l查看容器的运行情况。

1
2
CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                   NAMES
04a89ad553a8 nutshell/sample_website "nginx -g 'daemon ..." 27 minutes ago Up 13 seconds 0.0.0.0:32770->80/tcp static_website

这里再来解释下命令中的 -p 参数,上面例子中的-p 80的含义是docker在运行时在宿主机上 随机选择一个大端口号映射并连接到容器的80端口上。
在上面的例子中宿主机的端口是 32770
你会问了,那么我可不可以指定宿主机的端口?
可以,当然可以,具体的格式是 -p <host port>:<container port>
比如上面的例子中我们想将宿主机的8081端口映射到容器的80端口,那么启动的命令就可以这样写:

1
2
$ docker run -d -p 8081:80 --name static_web nutshell/sample_web \
nginx -g "daemon off;"

细心的你可能已经发现了,在dockerfile的最后一行EXPOSE 80好像在整个过程中并没有什么卵用啊,是的,至少在这个时间点还没有什么卵用。
如果使用 -P (注意大小写)
这个参数会将dockerfile中EXPOSE的端口绑定到宿主机上的一个随机端口上。
当然如果你对容器的端口映射到宿主机的端口不太清楚,可以使用docker port <container ID> <container port>查询:
以上面的容器为例:

1
$ docker port 04a89ad553a8 80

好了,可以在宿主机上验证下了

1
$ curl localhost:32770

返回

1
Hello from docker

一个最简单的nginx web docker容器就搞定了。

稍微复杂点的例子

还是上面的例子,我们注意到在启动的时候还附加了一个nginx的命令,这个难道不能写到dockerfile里么?
当然可以,使用dockerfile的

  • CMD
  • ENTRYPOINT就可以了。

ENTRYPOINT为例,只需在dockerfile的最后添加:

1
ENTRYPOINT ["nginx","-g","daemon off;"]

或者

1
CMD ["nginx","-g","daemon off;"]

重新build,重新run一个新容器,一切照旧,成功。
到这里你会问,既然一样为什么还要用两个指令?

正解是: CMD指令的命令可以被 “docker run” 后的命令覆盖,而ENTRYPOINT不会。(事实上,如果确实需要,可以在运行docker run 命令时 –entrypoint 来覆盖ENTRYPOINT指令)

是不是像点样子了?
其实还有空间可以提升,如果nginx的默认网页我们希望可以通过外部的文件部署替换,该怎么办?

  • ADD
  • COPY

只需将原dockerfile中的这一句

1
RUN echo 'Hello from docker' /usr/share/nginx/html/index.html

替换为

1
ADD project/index.html /usr/share/nginx/html/index.html

或者

1
COPY project/index.html /usr/share/nginx/html/index.html

重新build,重新run一个新容器,一切照旧,成功。

同样的,你会问,既然一样为什么要用两个命令?

正解是:当源文件是压缩文件的时候,目标文件是文件夹时就不一样了,ADD会自动提取,解压; 而COPY仅仅是拷贝

这样是不是就有点样子了?
其实dockerfile还有其他5个指令:

  • WORKDIR
    指定一个容器的工作目录
  • ENV
    设置容器的环境变量
  • USER
    指定用什么样的用户运行
  • VOLUME
    添加可以在容器间共享数据或者持久化数据的“卷”
  • ONBUILD
    为镜像添加触发器
文章目录
  1. 1. 简单的Dockerfile例子
  2. 2. 稍微复杂点的例子