Docker for Devs:创建开发镜像


【编者的话】本文介绍如何利用Docker本地化卷来搭建开发环境。

【3 天烧脑式容器存储网络训练营 | 深圳站】本次培训以容器存储和网络为主题,包括:Docker Plugin、Docker storage driver、Docker Volume Pulgin、Kubernetes Storage机制、容器网络实现原理和模型、Docker网络实现、网络插件、Calico、Contiv Netplugin、开源企业级镜像仓库Harbor原理及实现等。

在本系列的第一部分,我们创建了应用程序的基础Docker镜像,并运行了该镜像的实例(称为容器)。我们也鉴证了Grayskull(译者注:希曼的死对头,作者也是暴露年龄啊)的力量……我的意思是:Docker!我们完成了所有典型的应用程序的安装和运行。请注意这里我们不是从本地主机,而是从容器内运行的。继续这个Docker for Developers系列,我们将介绍如何设置可编辑的应用程序开发环境的镜像。

起航

我们在本教程的这一部分中的目标是生成一个代表我们应用程序开发版本的镜像,并设置容器的必要组件以使其运行,这样我们才可以对文件系统进行更改并将其反映在容器中。
live-editing-in-container.gif

步骤1:创建一个开发镜像

让我们在应用程序的根目录中创建一个新的Docker镜像文件,这将是我们派生镜像的说明:
FROM express-prod-i 

ENV NODE_ENV=development 

CMD ["./initialize.sh"]

我们做了什么?

我们创建了一个新的Docker镜像文件:
  • 将从我们的制作镜像“express-prod-i”中获得基本镜像……
  • ……并创建容器本地ENV变量NODE_ENV,值为“development”。
  • 最后,我们指定我们要从WORKDIR运行一个名为“initialized.sh”的bash shell脚本。


步骤2:创建我们的初始化Bash Shell脚本

我们将在容器中初始化应用程序,而不是让它在创建映像时初始化。因此,这些应用程序启动步骤(例如“npm install”)将在容器启动时进行:

1,在项目根中创建一个名为“initialize.sh”的文件
2,将以下内容粘贴到“initialize.sh”中
npm install 
node bin/www

3,从终端/提示符导航到项目根目录并运行以下命令使bash shell脚本可执行:
chmod +x initialize.sh



注意:请记住,这些容器正在基于Linux的环境中运行,因此运行chmod系统命令会将指定文件的权限设置为可执行文件,在这种情况下指的是initialize.sh文件。

我们做了什么?

如果回想起来,我们在基本的express-prod-i镜像中指定了运行“npm install”命令,它将安装的NPM软件包作为容器的一部分。但是我们在这里
  1. 创建一个文件,其中包含每次从该映像生成的容器启动时,我们想要运行的命令。
  2. 设置权限,以便可以从容器内执行文件,并在容器启动时运行诸如“npm install”之类的初始化步骤。


步骤3:创建应用开发镜像

现在,我们有一个新的Docker镜像文件,我们已经准备好创建一个镜像了。

步骤3a:构建开发镜像

就像我们在上一个教程中所做的那样,创建一个新的镜像:

1,从终端/提示符导航到我们项目目录的根目录。
2,从您的终端/提示符在项目目录的根目录下执行以下命令,不要忘记最后的[空格]和“.”
docker build -t express-dev-i -f dev.dockerfile .

我们做了什么?

  1. 我们使用Docker build命令创建了一个新的镜像。
  2. 需要注意的是,我们使用了一个代表文件的新标志(-f),以指定我们希望它使用的哪个Docker文件。记住默认文件名是Dockerfile。
  3. 如前所述,使用标签(-t)标记指定镜像名称,并给它一个名称“express-dev-i”。


步骤3b:列出镜像

我们可以看到以前和新的镜像:
docker images

03.png

步骤4:使用卷生成并运行容器

我们现在有一个镜像代表我们的应用程序的开发版本,它使用我们的生产作为基础。我们现在想运行那个容器,但是有一些新的东西:卷。

一直以来,您可能一直在想,如果源代码驻留在容器中,我们将如何编辑源代码并将其反映在运行容器中,对吗?这是我们开始实现的主要目标之一,不是吗?

我之前提到,镜像是一组区分的只读分层文件系统。每层添加或替换其下面的层。我也提到容器是镜像的运行实例。但这不止于此。容器为镜像的底层只读文件系统提供读写层。
04.png

为了将这些读和写层结合在一起,Docker使用联合文件系统。来保证容器的状态变化不会反映在镜像中。任何文件更改都严格位于容器中。这带来了一个问题。当容器脱机时,在实例化容器的底层映像中不会保留任何更改。

因此,为了持久化容器的修改(以及其他好处),Docker开发了。简而言之,卷是存在于该联合文件系统之外的目录或文件,通常位于主机(读取:您的计算机)的文件系统上。

步骤4a:创建具有卷的开发容器

现在我们有一个表示应用程序开发版本的镜像,我们准备在主机上创建一个装载卷的容器,指向应用程序的源代码本地目录:


重要提示:如果您在本地容器外运行应用程序(例如,node bin / www),与我们在shell脚本initialization.sh中设置的命令一样,您的文件夹根目录中有一个本地的node_modules目录,请删除他们。
  1. 从终端/提示符导航到express应用程序根目录
  2. docker run -name express-dev-app -p 7000:3000 -v $(pwd):/var/app express-dev-i



注意:赋给卷-v标志的值被分解为主机目录和而后的容器WORKDIR工作目录,由(:)分隔。这仅与我们的设置相关,但指定的容器目录不一定是WORKDIR目录。

我们做了什么?

  • 使用Docker RUN命令,我们生成并启动了一个容器(镜像的实例)
  • 并使用-name标志给我们的容器使用“express-dev-app”的名字
  • 将主机7000上的本地端口映射到使用-p标志(与Dockerfile EXPOSE命令一起使用)的3000的内部容器端口
  • 使用卷-v标志,我们在主机上安装了一个卷,其中$(pwd)表示主机上的“当前工作目录”到容器“/var/app ”(被指定作为Docker文件中的WORKDIR)
  • 最后,指定镜像“express-dev-i”,并将其实例作为容器运行



提示:删除容器时,默认情况下不会删除卷。但是可以使用docker remove(rm)指定-v标志来删除关联的卷“docker rm -v [容器的名称或ID]”。

步骤4b:验证容器是否正在运行

如果一切都按计划进行,您应该在终端/提示中看到npm安装的结果与正在安装的节点模块的列表一起运行。我特意留下了脱离进程的-d标志,这样便于观察。

我们可以通过运行“列出运行中容器”命令来验证运行容器是否没有任何问题导致它停止运行:
docker ps

如果没有列出,您可以将ALL -a标志添加到上述命令中以显示所有容器,并查看“express-dev-app”容器是否列出了退出错误。

步骤4c:检查容器装载信息

在继续之前,我们可以使用以下INSPECT命令来查看有关此新容器的挂在的卷信息,这将显示一大堆容器信息:
docker inspect express-dev-app

05.png

我们做了什么?

  • 我们使用Docker INSPECT命令来查看有关我们的容器的JSON格式信息……
  • ……由“Mounts”部分组成,列出……
  • ……源,它指向我们在本地主机上指定的项目根目录,以及……
  • ……目的地,它指向容器中的WORKDIR目录。


步骤5:本地编辑源代码

这是你一直在等待的那一刻。我们将直接跳入,看看我们如何在本地进行源代码修改,并将它们反映在容器中。

重要信息 :请确保查看步骤6有关安装的本地源代码和容器的一些精彩提示,命令和说明。

步骤5a:验证运行Express应用程序

浏览器到http://localhost:7000
06.png

步骤5b:编辑源代码

1. 在根目录下,导航到/views目录并打开index.jade文件
2. 找到行
p Welcome to #{title} 

3. 编辑为
p Welcome to #{title} running in a container!

4. 回到浏览器中,刷新URL(或导航到)http://localhost:7000
07.png


我们做了什么?

我们没有必要重建或甚重新启动容器,去观察这个简单但却十分伟大的前端改变,这个改变反应了我们对容器内部的修改。

步骤6:Node_Modules本地驻留

如果您记得,我们删除了在创建最后一个容器之前可能存在于本地应用程序根目录中的任何node_modules文件夹。但是,如果再次查看,则会存在node_modules文件夹。这是为什么?

托管运行node.js应用程序所需的更改(例如安装所有依赖关系节点模块)将通过我们创建的已安装卷在本地进行映射。

步骤6a:与容器进行交互

我们可以通过连接到正在运行的容器来验证。我们可以在容器上打开一个bash shell,并检查有关工作目录的信息。

我们没有在分离模式下启动容器,所以您需要停止运行容器并使用Docker start命令重新启动,如上一个教程所示,或者您需要打开一个新的终端/提示符并连接:

1,
docker exec -it express-dev-app /bin/sh 

2,提示符下输入命令:ls -l
08.png

我们做了什么?

  • 我们使用EXEC命令将运行容器连接到……
  • ……使用-it标志提供交互式终端...
  • ……并指定我们想使用/bin/sh参数连接到bash shell。
  • 您应该注意到,当我们连接到容器时,我们将自动连接到工作的WORKDIR目录。
  • 我们使用列表命令ls -l来显示目录内容实际上显示了本地卷挂载主机目录的内容。


总结

我们在Docker for Developer教程中完成的似乎很简单,但功能非常强大。我们将应用程序设置模块化到容纳所有应用程序所需设置的容器,同时保持对在容器中运行应用程序的源代码的控制。

我们只是破解了应用程序开发以及Docker使用容器化的方式和方法。在下一个教程中,我们将使用并运行一个通用(同构)React.js应用程序,并将热模块重新加载到容器中,使培训更贴近实际应用场景。

原文链接:Docker for Devs: Creating a developer image(翻译:高洪涛)

===========================================
译者介绍
高洪涛,当当网架构师,开源数据库分库分表中间件Sharding-JDBC作者。目前从事Docker,Mesos相关工作

0 个评论

要回复文章请先登录注册