由浅入深 docker 系列: (2) docker 构建

在上一篇教程里,我们学会了docker的使用,也体验了docker的隔离性,在里面随意增删软件,不用的时候直接删除镜像容器,很方便。但是,还有问题,如果你的朋友也想试用你的软件,怎么办呢?或者你换了台电脑,又要重新pull然后在docker里install么?

当然不用,我们说过docker具有快速部署的优点。今天我们学习怎么构建我们自己的docker镜像。


一:docker commit

最直观的思路,自然是将我们的容器保存下来。而docker也为此提供了很方便的命令,即 docker commit。其格式为

docker commit -a "author" -m "message" <exiting-container> <hub-user>/<repo-name>[:<tag>]

是不是很像 git的commit命令?其中 exiting-container为你的容器名称或 id,hub-user 为你登录的 DockerHub 用户名,repo-name 为你想给新镜像起的名字。

镜像构建成功之后,就可以分享了

你可以使用 docker save <image> | gzip > fileName 将 image 保存为文件,然后拷贝给他人,再通过 docker load -i fileName导入使用。

这么做太麻烦了。推荐方式是使用 docker push 命令将其推送到 DockerHub,当然你需要先登录。

我把上次的 ubuntu 做了commit,并 push 到了 DockerHub,成功之后就可以在DockerHub看到自己的镜像了,之后可以随时拉取使用。

另外,通过docker history 可以看到容器的创建历史,我们可以试下。

我们发现,在软件内部增删软件、文件等操作在这里都无法体现,因此我们的镜像事实上成了一个黑盒,没有文档就不知道其具体有什么功能,即使你添加了文档,经过一次次更改文档很可能也没有同步了,非常不方便别人或者自己以后使用。事实上,docker 提供了更方便强大的方式构建镜像,即 Dockerfile。

另外,commit 方式在特定场景下也有其用途,比如程序崩溃、被入侵后保存现场时,就很有用。


二:Dockerfile

Dockerfile 是一个文本文件,其内包含了一条条的指令,描述我们的镜像该如何构建,就像我们程序的源码。在这之前,补充一个知识,就是我们的 docker 镜像文件事实上是分层的。你应该注意到拉取 ubuntu 的时候,它pull 了很多次。而分层的操作也方便不同镜像间共享相同的层,这显著的节省了客户机的存储空间以及下载时间。

例如,我再拉取一个 nginx 镜像,你会发现第一层已经存在了,直接复用。

为什么要讲这个?因为 Dockfile 的每一条指令的内容,就是描述该层应当如何构建。

我们首先来定制一个 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 容器依然会自动退出。

同样你可以将其推送到 DockerHub,或者仅仅将你的 Dockerfile 分享给他人就可使用。另外,你可以将 Dockerfile 与你的代码一同上传 github 或其他系统,更方便你的应用环境搭建,也可以进行docker 的版本管理。甚至,你还可以设置Docker Hub结合Github自动化构建镜像

接下介绍常用的 Dockerfile 命令。

1. FROM 命令
FROM为指定基础镜像,像之前我们基于官方 nginx 进行定制,这样可以省略大量的重复工作。DockerHub 上有大量的镜像,ubuntu、mysql、php、python 等等,一定要选择合适的作为基础镜像,比如开发 django 就选用 python 或者django 镜像,而不要去用 php 镜像。

2. 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

3. COPY 命令

COPY 命令用于将文件拷贝到镜像中。

COPY <源路径> <目标路径>
你可以将需要的文件拷贝到镜像内,注意这里源路径是相对路径,即相对上文构建命令里的最后一个参数所指定的目录(上文例子为.),不能随意引用其它文件。另外,尽量不要在构建目录里放入无关文件,因为 docker 会将目录下所有文件打包发送给服务进程,如图所示

4. CMD命令

CMD 命令为容器启动时的默认命令,因为容器其实本质是一个进程(后面会细讲)。比如 ubuntu 镜像默认CMD 命令为/bin/bash,因此事实上我们只要执行 docker run -it ubuntu就可以得到一个交互式 shell。如果我们传入其它命令,比如 执行 docker run ubuntu uname,容器就会执行我们指定的命令。

以上就是最常用的Dockerfile 命令,建议大家自己尝试构建一个,会有更深的体会。另外还有很多命令以及细节,可以参考这篇教程,写的特别好,强烈推荐。

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 1年前 自动加精
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!