Docker 就像是用于 DevOps 的一把瑞士军刀,这一点已得到充分证明。但 Docker 托管的应用程序容器的用途不仅是在云中部署服务器。Docker 容器还可以在许多常见的开发场景中帮助开发和显著提高生产力。本教程将重点介绍 Docker,了解从开发人员角度讲它有何用途。我将介绍 Docker,解释基本概念和术语,并提供一系列实际的开发示例。
您会看到:
阅读配套教程 “使用 Docker 和 Bluemix 容器化 golang 应用程序”,将您的多语言探索扩展到 Go 编程语言。另外,了解通过 IBM Containers for Bluemix 将 Docker 化的三层应用程序部署到 Bluemix™ 有都没容易。
您可以在单个 Linux 系统上获得所有这些收益,而不会妨碍任何预设的配置。在了解一些示例后,您就能够轻松地运行各种 Docker 容器来提高日常开发工作流中的生产力。
Docker 是一个容器管理器。容器将应用程序和它的依赖项捆绑在一起。您从一个存储在存储库中的镜像实例化每个容器,在主机操作系统内隔离的虚拟化环境中运行容器。因为虚拟化技术(通常)是轻量型的,所以您可以同时运行多个容器:
了解镜像与容器之间的区别很重要。这两个概念紧密相关,但初学者常常难以了解它们之间的区别。
镜像 是一个静态的层集合。没有任何运行时行为与镜像关联。镜像存储在存储库中(例如 Docker Hub)。
容器 是一个从镜像启动的运行实例。尽管容器可以停止(并在此盘上临时冻结其状态),但它仍是一个容器。
潜在的混淆源于一个事实,那就是通过提交和保存容器,您可以将容器转换为镜像。在这种情况下,您可以将得到的镜像想作是运行的容器的 “冻干 (freeze-dried)” 版本。
您可以使用 Docker 容器管理器执行以下操作:
容器化的应用程序几乎可以在任何地方运行:桌面 PC 上、服务器上、公共云中,甚至是在一些移动电话上。
全新的 developerWorks Premium 会员计划提供了强大的开发工具和资源,包括 500 篇通过 Safari Books Online 提供的顶级技术文章(其中超过 100 篇文章是专门面向 Web 开发人员的)、最重要开发人员活动的大幅折扣、最新的 O'Reilly 大会的视频回放,等等。立即注册。
Linux 目前是得到最广泛使用和支持的 Docker 平台。Docker 所管理的容器化(轻量型虚拟化)技术在 Linux 平台上最成熟,使用了最新的 Linux 特性,比如 控制组 和 命名空间。
您可以通过 docker
命令行客户端来运行 Docker 容器管理器,该客户端有许多可用的开关和选项。这是运行容器化应用程序镜像(在这个例子中是 MySQL 数据库)的一个简化的命令:
docker run -d mysql:5.5
Docker 项目运行着可公开访问的 Docker Hub。用户可以注册并创建自己的容器化应用程序镜像存储库,然后推送镜像来供大家共同使用。例如,您可以找到 Tomcat 服务器、Node.js 和大多数流行的开源数据库的镜像。Docker Hub 的操作理念与 GitHub 相同,因为应用程序镜像是全球 DevOps 和开发人员社区共享和协同创建的。
举例而言,运行 docker run -d mysql:5.5
命令时,如果还没有将 mysql
(5.5 版)容器化应用程序镜像存储在本地,就会自动从 Docker Hub 拉取(下载)它。
还可以使用 docker
命令行客户端来构建容器化应用程序镜像。一种方式是从 Dockerfile
构建镜像 — 一个包含如何安装、设置和配置一个应用程序和它的依赖项的说明的文本文件。
使用 docker
命令行客户端构建容器化镜像的另一种方法是以交互方式设计它们。您在一个运行的容器内手动安装和配置一个应用程序和它的依赖项,然后提交容器并保存为镜像。
一个 Docker 镜像包含一些层,每层大体相当于在安装一组应用程序期间写入磁盘的更改。Docker 管理这些层,并帮助在添加或删除这些镜像时高效地存储和重用。举例而言,一个 mysql
镜像中的层可能包含 Linux 操作系统、Perl、共享库、MySQL 安装和一种基本的 MySQL 配置:
从 Dockerfile
构建容器化镜像或设计自定义容器时,通常不会从头开始。相反,您的工作以现有的 Dockerfile
或一个来自 Docker Hub 的镜像为基础。这样,开发人员和操作人员就能够以彼此的工作为基础,协同创建和管理一组有用的镜像。
将镜像发送到镜像存储库(比如 Docker Hub)的命令是 docker push
。下载镜像以供本地使用的命令是 docker pull
。
“即使使用 Java、Tomcat、Node.js、Python 和 CouchDB 进行开发,也不需要安装它们中的任何一个。这是在开发工作流中使用 Docker 的美妙之处。”
在开始之前,需要一个安装并运行 Docker 的 Linux 系统。要安装 Docker,可以按照适合您的 Linux 发行版的 安装说明 进行操作。
如果无法直接访问 Linux 系统,可以依靠云。大多数云主机都提供了随时可运行的虚拟服务器或虚拟机,只需几分钟就可以为它们配备 Linux 并(通过 SSH 或基于 Web 的终端)连接到它们。这些主机通常与 Docker 兼容。
本教程中的示例假设您在 Linux 系统上运行 Docker。如果您已经在 Mac OS X 或另一个非 Linux 系统上运行 Docker,您的容器可能会在一个由虚拟机管理程序虚拟化的额外虚拟机(常常为 VirtualBox)内运行。在这种情况下,您需要相应地修改示例中的命令才能继续操作。
运行以下命令来检查您的 Docker 版本:
docker --version
拉取镜像后,请注意指明已存在一个层的消息。Docker 通过层来管理在镜像创建期间写入磁盘的更改,这有助于高效地管理镜像更改集。例如,基础 Ubuntu 镜像或核心实用程序的安装可被多个镜像共享 — 节省了宝贵的磁盘空间和下载时间。
如果您运行 1.8.3 或更高版本,您的系统现在已经设置好。即使使用 Java、Tomcat、Node.js、Python 和 Apache CouchDB 进行开发,也不需要安装或卸载它们中的任何一个。这是在开发工作流中使用 Docker 的美妙之处。
第一次从 Docker Hub pull
(拉取)一个镜像时,必须将它下载到本地 PC 的存储库。根据您的网络访问速度,下载可能很耗时,但对镜像的后续使用将会很快。
运行以下命令来拉取您将在示例中使用的所有镜像:
docker pull node:0.10.40 docker pull java docker pull tomcat:8 docker pull webratio/ant docker pull python:3.5 docker pull frodenas/couchdb
有关每个镜像的更多信息,请访问 Docker Hub 的 node
、java
、tomcat
、webratio/ant
、python
和 frodenas/couchdb
页面。
现在,在设置完成后,就可以使用 Docker 处理一个 Node.js 应用程序来进行我们的探索了。
代码发行版中的 javascript 目录(参见 下载)包含一个使用 Node.js 编写的网络商店示例应用程序的源代码。该应用程序(最初由 Lauren Schaefer 设计和编写)使用了 Express Web 框架和 Jade Node 模板引擎。(有关这个应用程序的更多信息,请参阅 “Bluemix 基础:将一个示例 Node.js 应用程序部署到云中。”)通过使用 Docker,您可以在您的计算机上使用这个应用程序,无需安装 Node.js 或它的任何依赖项— 或者排除包安装冲突。
主要程序在 app.js 中。CSS 和关联的 JavaScript 文件在 javascript/public/static 中。Jade 模板在 javascript/view 中。
运行以下命令来安装此应用程序的 Node.js 依赖项:
docker run -it --rm --name lllnode -v "$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 npm install
此命令将会启动 Node 容器,将当前应用程序目录挂载到容器中,然后在应用程序上运行 npm install
:
docker run � node:0.10.40
,它创建一个容器实例并运行您之前拉取的 node:0.10.40
镜像。-it
开关指定您想要一个前台交互式终端。(备用模式是分离的后台进程,可以使用 -d
指定它。)--rm
开关指定执行清理,表示在您退出容器后,Docker 会立即删除它。如果没有指定此开关,该容器会以停止状态持久保存在磁盘上,而且您可以从中断点开始重新启动它。但是,对于忘记删除容器实例的用户而言,重新启动容器是磁盘耗尽的常见来源。如果不使用 --rm
,那么任何时候都能运行以下命令来查看您遗留下了多少陈旧的停止容器(数量可能会让您吃惊):docker ps -a
--name lllnode
选项显式命名容器,这对在其他 Docker 命令中引用该容器很有用。如果没有显式命名容器,Docker 会为它分配一个生成的文本名称 — 这个名称通常没什么意义。您还可以通过内部 ID(一个很长、对人类不友好的十六进制字符串)来引用该容器。-v "$PWD":/usr/src/myapp
选项创建一个卷挂载点。将您当前的工作目录 ($PWD
) 挂载为容器内的 /usr/src/myapp。然后可从该容器内访问应用程序的 Node.js 源代码(或您当前的工作目录中可能拥有的其他任何 Node.js 源代码)。-w /usr/src/myapp
选项设置您运行的命令的工作目录。在这个示例中,工作目录更改为挂载的卷。docker run
命令末尾的 npm install
命令在工作目录上的容器内运行。最终结果是您通过容器在当前目录上运行 npm install
— 而不安装 Node.js 或它的任何前提软件。在命令输出中,您可以看到 npm
正在运行的所有依赖项:
在安装依赖项后,可以通过容器运行该应用程序。使用此命令(将它键入为一行):
docker run -it --rm --name lllnode --env PORT=8011 --net="host" -v "$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 node app.js
这个命令类似于您之前运行的命令。但请注意,要在容器内运行的命令现在是 node app.js
,它将启动应用程序。
查看 app.js 的内容。您会找到以下行:
var appEnv = cfenv.getAppEnv(); app.listen(appEnv.port, appEnv.bind, function() { console.log("server starting on " + appEnv.url); });
这些行导致 Express Web 服务器在 PORT
环境变量指定的端口上监听。为了在容器中设置此环境变量,您刚运行的 docker
命令使用 --env PORT=8011
选项。
此外,该命令的 --net="host"
选项导致容器使用主机操作系统内部的网络堆栈(仅用于开发用途)。然后该应用程序在主机上的端口 8011 上进行监听。
在浏览器中访问 http://localhost:8011/,您可以在其中看到基于运行的容器的 Lauren's Lovely Landscapes 印刷品商店:
您随时可以退出容器来修改代码或修复错误,然后再次运行容器— 所有操作在几秒内即可完成,不会让开发环境变得杂乱。
现在您已确信 Docker 只需几秒即可启动并运行一个 Node.js 应用程序,您可能想知道它如何更轻量型地处理一些工作 — 比如 Java EE 开发。很高兴为您解答。
假设您刚刚阅读了我的 “使用 Vaadin 实现全堆栈 Java Web 开发” 教程,并渴望试用我的 Java EE Vaadin 示例。但您没有安装 JDK,而且不想因为花一下午时间笨拙地安装一个 JDK 而将系统弄得一团糟。Docker 可以拯救您!
代码下载 的 java 目录中的 ArticleViewer.war 文件是一个包含来自 Vaadin 教程的多个 Vaadin UI 组件的应用程序。您可以通过 Docker 在 Tomcat 8 服务器上运行 ArticleViewer.war。第一步是从您之前拉取的镜像启动一个 Tomcat 8 容器实例:
docker run -it --rm -p 8888:8080 --name=tomcat_server -v $PWD:/mnt tomcat:8
这个命令现在看起来可能很熟悉。为了更方便引用,容器名为 tomcat_server
。您目前的工作目录在容器内挂载为 /mnt。
-p 8888:8080
选项告诉 Docker 将主机系统的端口 8888 映射到容器的(内部)端口 8080。在 tomcat
镜像的 Dockerfile
中,您可以看到 Tomcat 在容器内的端口 8080 上执行监听。
通过浏览器访问 http://localhost:8888/,您可以在其中看到熟悉的 Tomcat 8 服务器欢迎页面:
请注意您保持容器在交互式模式下运行(通过 -it
开关)。在该模式下,会在标准输出中连续显示日志,以方便开发。
现在,容器内挂载的目录 /mnt 是您当前的工作目录,ActiveViewer.war 位于该目录中。
将 ActiveViewer.war 从 /mnt 复制到 Tomcat 8 的 webapps 目录,它会在这里自动部署:
docker exec tomcat_server cp /mnt/ArticleViewer.war /usr/local/tomcat/webapps
这一次不需要使用 docker run
命令,因为 tomcat_server
容器已在运行。相反,您连接到运行的容器并运行一个命令。所以您使用了 docker exec
,提供 cp /mnt/ArticleViewer.war /usr/local/tomcat/webapps
命令作为整个命令的最后一部分。
观看 tomcat_server
窗口中的日志,查看来自 ArticleViewer
应用程序部署的日志轨迹。
现在,在浏览器中访问应用程序的 URL(http://localhost:8888/ArticleViewer/)来打开正在运行的应用程序。单击左侧列表中的一篇文章,在右侧查看文章内容:
在继续后面的操作之前,停下来思考片刻。您没有在系统上下载或安装 JDK 或 Tomcat 8。只需几秒即可在一个功能全面的 Tomcat 8 服务器上运行 Vaadin 应用程序的代码 — 这得益于 Docker。
您刚才已经看到,可以使用 Docker 轻松地部署用于测试的 Web 应用程序。也可以通过 Docker 同样轻松地从 Java 源代码编译和构建 Web 应用程序 — 同上面一样,无需让您的开发系统变得一团糟或花很长时间安装前提软件。
将目录更改为 代码发行版 中的 java/LaurenLandscapesJava。这个目录中包含您在 Node.js 示例中看到的 Lauren's Lovely Landscapes 应用程序的一个 Java 版本。(如果想了解该代码的更详细描述,请阅读 “Bluemix 基础:将一个示例 Java 应用程序部署到云中”。)
build.xml 文件是一个标准的 Apache Ant 构建文件,它包含编译代码和构建 WAR 文件的指令。通过使用 webratio Apache Ant 镜像,可以在更改代码后(或其他任何时刻)快速编译和构建 WAR:
docker run -it --rm -v "$PWD":/mnt webratio/ant bash -c 'cd /mnt; ant'
您现在已经熟悉了这个 docker run
命令中的所有内容。该命令在作为 /mnt 挂载在容器内的当前工作目录内运行 Ant 构建工具。Ant 编译 src 子目录中的所有 Java 源代码,然后构建并绑定 WAR 文件,将它作为 lauren.war 放在 dist 子目录中。
将 lauren.war 从 java/LaurenLandscapesJava/dist 目录复制到 java 目录:
cp dist/lauren.war ..
您可以使用此命令将 lauren.war 应用程序部署到 Tomcat 8:
docker exec tomcat_server cp /mnt/lauren.war /usr/local/tomcat/webapps
此命令附加到运行的 tomcat_server
容器,并将 lauren.war 文件复制到 Tomcat 8 的 webapps 子目录中用于自动部署。
现在,在浏览器中访问 http://localhost:8888/lauren/,您可以在其中看到在您的 Docker 化 Tomcat 8 上运行的 Lauren's Lovely Landscape 的 Java 版本。
假设作为一位多语言开发人员的您希望暂时不执行 Java 编码,探索 Python Bottle Web Framework 提供的可能性。为了帮助您快速探索 Python Web 应用程序开发,避免麻烦的安装和依赖项带来的痛苦,Docker 再次挽救了您。
更改到代码发行版的 python/Laurens.Lovely.Landscapes 目录。该目录中包含 Lauren's Lovely Landscape 应用程序的 Python 版本 — 为 Bottle Web 框架而编写。模板(.tpl 文件)位于 views 子目录中。(有关该代码的更多信息,请查阅 “Bluemix 和 DevOps Services 简介,第 1 部分:部署和更新一个简单应用程序。”)还可以在关联的 Bluemix DevOps Services 存储库 中找到此代码的一个版本。
运行这个 Python 应用程序 — 而不将 Python 安装在您的系统上— 通过以下 Docker 命令(将它们键入为一行):
docker run -it --rm --name lllpython -p 8000:8000 -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:3.5 python wsgi.py
现在在浏览器中访问 http://localhost:8000/,您可以在其中看到正在运行的 Lauren's Lovely Landscapes 应用程序的 Python 版本。
在 Python 中开发时,您可以更改代码并重新运行之前的命令来进行测试。运行 Docker 容器就像运行安装在本地的开发工具一样快。
大多数现代 Web 应用程序都涉及 3 层:浏览器作为客户端;一个中间层应用服务器,比如 Express、Tomcat 8 或 Bottle;以及一个后端数据库。通过使用 Docker,您可以快速添加一个数据库,无需将它安装在您的开发系统上。
在这个最后的示例中,您将一个 Apache CouchDB 数据库服务器添加到您的开发环境中。您可以使用 CouchDB API(它与 IBM Cloudant NoSQL 数据库完全兼容)在本地测试 CouchDB 或 Cloudant 代码。
更改到源代码发行版中的数据库目录。这个目录中包含 Lauren's Lovely Landscapes 应用程序的高级 Node.js 版本。此版本从 CouchDB(或 Cloudant)抓取印刷品商店的库存信息。该网络商店依据可用印刷品的库存来动态更改外观。(您可以在 “Bluemix 基础:将 Cloudant NoSQL 数据库添加到您的 Node.js 应用程序中” 中找到该代码的更多信息。)
要启动 Apache CouchDB 的一个实例,可以使用这个 Docker 命令(将它键入为一行):
docker run -d --name couchdb -p 5984:5984 -e COUCHDB_USERNAME=user -e COUCHDB_PASSWORD=abc123 -e COUCHDB_DBNAME=prints -v $PWD/data:/data frodenas/couchdb
该命令使用 COUCHDB_USERNAME
、COUCHDB_PASSWORD
和 COUCHDB_DBNAME
环境变量来配置实例,以便与代码中使用的值匹配。当前的工作目录在容器内挂载为 /data。CouchDB 将数据写入此目录中,使您可以重新启动容器而不丢失数据。
请注意,在这个示例中,您使用了 -d
选项运行该容器,而不是使用 -it --rm
选项。-d
选项启动分离的 CouchDB 实例。您可以使用 docker ps
命令查看所有正在运行的分离的 docket 容器。
接下来安装应用程序的 Node.js 依赖项:
docker run -it --rm --name llldepends -v "$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 npm install
Apache CouchDB 实例还没有任何数据。使用以下命令(将它键入为一行)来运行 dataseeder.js 代码,该代码在 Apache CouchDB 实例中创建一个文档,以便在商店中填充库存:
docker run -it --rm --name dataseeder --net="host" -v "$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 node dataseeder.js
在端口 8011 上运行 lllnode
应用程序:
docker run -it --rm --name lllnode --env PORT=8011 --net="host" -v "$PWD":/usr/src/myapp -w /usr/src/myapp node:0.10.40 node app.js
在浏览器中访问 http://localhost:8011/ 来打开 Lauren's Lovely Landscapes 商店:
您可以看到澳大利亚的印刷品已脱销。该产品类别突出显示为红色,无法选中。
为了模拟对澳大利亚印刷品补货的过程,您将访问 Apache CouchDB 文档并直接修改库存水平。
Apache CouchDB 提供了一个简单的 GUI(名为 Futon)来访问存储的文档。在浏览器中访问 http://127.0.0.1:5984/_utils/ 来打开 Futon GUI:
在 Futon 中,选择 prints
。打开文档并展开编号为 3 的库存项。双击澳大利亚印刷品以打开文档进行编辑。将 quan
字段从 0
更改到 3
。单击右侧的小型绿色勾号图标,然后单击左上角的 Save Document:
数据库中的数量更新后,在浏览器中重新加载页面 http://localhost:8011/。您可以看到商店现在已屯满货。澳大利亚印刷品不再标记为红色,而且可以选中。
使用 3 层 Web 应用程序时,Docker 简化了中间层应用程序编码的开发工作流,方便了即时本地部署后端数据库来实现测试。
在这个竞争激烈的时代,您承受不起没有将 Docker 整合进开发工作流中的生活。通过消除反复安装和卸载相互依赖的复杂开发人员包和工具的需求,Docker 可以缩短您的开发时间和探索时间。利用 Docker 来提高您的多语言开发智商,显著提高您的开发生产力。
描述 | 名字 | 大小 |
---|---|---|
代码示例 | code_docker.zip | 22MB |