在Docker容器中,我们可以随意的增删软件,不用的时候直接删除镜像容器,这是相当方便的。但是,如果有其他人想要试用你的软件,怎么办呢?或者你重新换了一台电脑,需要执行Docker pull然后 install吗?
答案肯定是不用,因为Docker具体快速部署的特点,接下来我们学习如何构建Docker镜像。
docker commit
最直观的思路应该是把我们创建的容器保存下来,可以通过docker commit命令,格式如下:
docker commit -a "author" -m "message" <exiting container> <hub-user>/<repo-name>:<tag>
该命令很像我们常用的git commit,其中exiting container 为容器名称或者ID,hub-user为登录docker-hub的用户名,repo-name为镜像名称,tag为镜像的标签。
镜像构建成功后就可以进行分享了。
你可以使用 docker save <image> | gzip > filename 将image保存为文件,然后拷贝给其他人,再通过docker load -i filename 导入使用。
以上操作和AI模型的操作很类似,先训练模型,训练好之后在save模型,再通过loadd导入模型,所以在计算机的很多领域,思想都是类似的。
这种方式略显麻烦,你可以通过docker push将镜像上传到Docker hub或者自己的私有镜像仓库中,之后就可以随时通过docker pull拉取使用了。
另外,我们可以通过docker history来查看镜像的构建历史,例如:
在这里我们可以发现,在软件内部增删软件、文件等操作在这里都无法体现,因此我们的镜像事实上成了一个黑盒,没有文档就不知道其具体有什么功能,即使你添加了文档,经过一次次更改文档很可能也没有同步了,非常不方便别人或者自己以后使用。事实上,docker 提供了更方便强大的方式构建镜像,即 Dockerfile。
另外,在commit方式在特定场景下也有其用途,比如程序崩溃、被入侵后保护现场。
Dockerfile
Dockerfile 是一个文本文件,其内包含了一条条的指令,描述我们的镜像该如何构建,就像我们程序的源码。在这之前,补充一个知识,就是我们的 docker 镜像文件事实上是分层的。你应该注意到拉取 ubuntu 的时候,它 pull 了很多次。而分层的操作也方便不同镜像间共享相同的层,这显著的节省了客户机的存储空间以及下载时间。
Dockerfile每条指令的内容就是描述该层如何构建的。接下来我们定制一个nginx镜像。
任意新建一个文件夹,新建一个文本文件,名为Dockerfile,内容如下:
FROM nginx
RUN echo "<h1> hello docker </h1>" > /usr/share/nginx/html/index.html
然后执行docker build命令构建镜像:
docker build -t <name>:<tag> path
可以发现新的镜像分为两层,注意命令后面有一个.,表示当前文件夹。
然后通过docker run启动容器:
这时访问 http://127.0.0.1:8080 应该就能看到我们的页面了。注意之前的镜像可能已经绑定了本机 8080 端口,你需要停止它或者换一个端口。还有 -d 参数表示后台运行,注意 -d 并不影响容器的运行时间,只是将其放到了后台,换句话说,如果你的容器本身没有运行不退出的进程,即使加了 -d 容器依然会自动退出。
当然我们也可以通过docker ps指令查看容器进程:
接下来介绍常用的dockerfile命令:
- FROM
FROM 为指定基础镜像,像之前我们基于官方 nginx 进行定制,这样可以省略大量的重复工作。DockerHub 上有大量的镜像,ubuntu、mysql、php、python 等等,一定要选择合适的作为基础镜像,比如开发 django 就选用 python 或者 django 镜像,而不要去用 php 镜像。
- RUN
RUN 命令即用来在容器中执行命令的,相当于你之前手动在 docker 里面执行命令。
其格式也很简单,RUN <command> 即可,command 可以是容器内能执行的任何命令。
这里说下本人的经验,RUN 命令不一定能成功执行,你不必一遍遍更改然后 build 实验,可以直接 run 一个基础镜像,然后去执行命令,等成功了再写入 Dockerfile,会方便很多。
另外,之前说过,每条命令会构建一层,所以不要写太多层 RUN,也不要只有一层,单独的功能模块组合到一层,更利于快速构建以及复用。比如下面这个例子:
FROM php:7.1.22-fpm
# Install PHP and composer dependencies
RUN apt-get update \
&& apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev \
&& RUN apt-get clean
# Install needed extensions
RUN docker-php-ext-install pdo pdo_mysql mcrypt zip gd
- COPY
COPY <源路径> <目标路径>
你可以将需要的文件拷贝到镜像内,注意这里源路径是相对路径,即相对上文构建命令里的最后一个参数所指定的目录(上文例子为.),不能随意引用其它文件。另外,尽量不要在构建目录里放入无关文件,因为 docker 会将目录下所有文件打包发送给服务进程.
- CMD
CMD 命令为容器启动时的默认命令,因为容器其实本质是一个进程(后面会细讲)。比如 ubuntu 镜像默认 CMD 命令为 /bin/bash,因此事实上我们只要执行 docker run -it ubuntu 就可以得到一个交互式 shell。如果我们传入其它命令,比如 执行 docker run ubuntu uname,容器就会执行我们指定的命令。
以上就是最常用的 Dockerfile 命令,建议大家自己尝试构建一个,会有更深的体会。另外还有很多命令以及细节,可以参考这篇教程,写的特别好,强烈推荐。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。