引言
Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,而 Docker 容器则可以认为是软件的运行态。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。
Dockerfile介绍
通过下图可以看出使用 Dockerfile 定义镜像,运行镜像启动容器:
Docker 镜像是由 Dockerfile 构建而成,Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了 Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。最简单的形式是由FROM、ADD、VOLUME、CMD四个部分组成,我们可以写一个最简单的Dockerfile文件:
FROM ubuntu:14.04
ADD run.sh /
VOLUME /data
CMD ["./run.sh"]
FROM ubuntu:16.04
:设置基础镜像,此时会使用基础镜像ubuntu:16.04
的所有镜像层,为简单起见,图中将其作为一个整体展示
ADD run.sh /
:将 Dockerfile 所在目录的文件run.sh
加至镜像的根目录,此时新一层的镜像只有一项内容,即根目录下的run.sh
VOLUME /data
:设定镜像的 VOLUME,此 VOLUME 在容器内部的路径为/data
。需要注意的是,此时并未在新一层的镜像中添加任何文件,但更新了镜像的 json 文件,以便通过此镜像启动容器时获取这方面的信息。
CMD ["./run.sh"]
:设置镜像的默认执行入口,此命令同样不会在新建镜像中添加任何文件,仅仅在上一层镜像 json 文件的基础上更新新建镜像的 json 文件。
然后之后还有别的命令,我们本篇主要构建的是将我们自己的Python代码能够在docker本地上运行成功,并保存成镜像,推送到dockerhub上。
dockerfile书写规范
dockerfile除了上面最基础但又是比较重要的语法构成外,还有一些其它的命令同样能帮助我们完善docker镜像,下面参考Docker(三):Dockerfile 命令详解 对上述命令进行一个整体的概括与整理:
命令 | 说明 | 详解 |
---|---|---|
from | 指定基础镜像 | 必须为第一条非注释指令,多个from可以创建多个镜像,但from前需提交上次镜像ID |
run | 执行特定命令 | 位置没有限制,层级构建docker的命令 |
copy | 复制文件 | copy指令将从构建上下文目录中的文件复制到镜像内的目标路径 |
add | 高级复制命令 | 和copy有一样的功能,多了源路径可以是url的情况 |
env | 设置环境变量 | 设置环境变量,一般最好放前面 |
expose | 设置监听端口 | 若需要,在 docker run 时使用-P 参数来发布容器端口到 host 的某个端口上。 |
volume | 定义匿名卷 | 详情见下面的详细说明 |
workdir | 指定工作路径 | 通过设置工作路径,Dockerfile的其它命令都会在指定目录下执行 |
cmd | 容器启动命令 | 与run指令的区别在于,run会产生新的镜像,cmd在构建时不进行任何操作 |
onbuild | 设置镜像触发器 | 当所构建的镜像被用作其它镜像时将会被触发 |
上表中我们详细说明一下volume命令,因为再后面的docker-compose.xml中它也有着无法替代的作用,它的基本功能是创建挂载点,即向基于所构建镜像创始的容器添加卷,而一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
- 卷可以容器间共享和重用
- 容器并不一定要和其它容器共享卷
- 修改卷后会立即生效
- 对卷的修改不会对镜像产生影响
- 卷会一直存在,直到没有任何容器在使用它
VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。
dockerfile使用实例
下面我将通过我自己项目的例子来进行相关说明,首先我们要在我们项目的根目录下创建一个Dockerfile不带任何后缀的文件,然后在文件内部写下我们想要构建的镜像的配置信息,比如我这里的是:
FROM python:3.6
RUN mkdir -p /usr/lzj/Pro/ChatterBotmaster
WORKDIR /usr/lzj/Pro/ChatterBotmaster
# COPY pip.conf /root/pip/pip.conf
COPY requirements.txt /usr/lzj/Pro/ChatterBotmaster/
RUN pip install -r /usr/lzj/Pro/ChatterBotmaster/requirements.txt
RUN rm -rf /usr/lzj/Pro/ChatterBotmaster
COPY . /usr/lzj/Pro/ChatterBotmaster
CMD ["python","answermain.py"]
写得比较简单,虽然中途尝试过一些其它的方式,比如说直接再Ubuntu下进行制作镜像与启动,但那样步骤太多了,我发现有15步,影响速度又占用极大的空间,另外就是中途的时候有很多报错,所以我还是采用常规写法,然后上述的dockerfile指令中,第四条copy指令我不知道为什么一直提示我不存在该文件,我在其他路径将文件复制过去还是一样的错误,所以干脆我就注释掉了,中间的步骤我忘了截图,关于requirements文件,可以看我之前的一篇例子: 利用pip和pipreqs导出当前python环境下所依赖的包总结 ,我推荐是用pipreqs模块。
然后中间过程忘截图了,因为我构建镜像的那几天,网速很慢,中午吃饭的时候挂着,等到下午接近下班的时候看了下才成功,中间可能会有一些小错误,但对整体并不影响使用,步骤由之前15步缩短为8步,大致为:
Sending build context to Docker daemon 65.57MB
Step 1/8 : FROM python:3.6
---> 48c06762acf0
Step 2/8 : RUN mkdir -p /usr/lzj/Pro/ChatterBotmaster
---> Using cache
---> 010f2065bc65
Step 3/8 : WORKDIR /usr/lzj/Pro/ChatterBotmaster
---> Using cache
---> b5b9b0094d7d
Step 4/8 : COPY requirements.txt /usr/lzj/Pro/ChatterBotmaster/
---> Using cache
---> 0a8bb8854704
Step 5/8 : RUN pip install -r /usr/lzj/Pro/ChatterBotmaster/requirements.txt
---> Using cache
---> bb501a77da43
Step 6/8 : RUN rm -rf /usr/lzj/Pro/ChatterBotmaster
---> Using cache
---> 06e858f3575d
Step 7/8 : COPY . /usr/lzj/Pro/ChatterBotmaster
---> Using cache
---> b80ca79fe874
Step 8/8 : CMD ["python","answermain.py"]
---> Using cache
---> 406493b7842a
Successfully built 406493b7842a
Successfully tagged my-python-app:v1.0
构建成功后,我们就可以使用docker run命令进行启动:
然后如果当前linux服务器的端口是开放的,我们就可以在Windows上输入该Linux的ip地址加8080端口进行访问。那么到这里,一个简单的images就制作完成了,可以看我上一篇的镜像说明,提交到dockerhub中,以后需要的话,能直接pull拉取。
参考与推荐:
[1]. Docker(三):Dockerfile 命令详解
[3]. Dockerfile参考
[4]. docker容器极简教程