使用DockerCompose将Node.js应用程序容器化以进行开发

来自菜鸟教程
跳转至:导航、​搜索

介绍

如果您正在积极开发应用程序,使用 Docker 可以简化您的工作流程以及将应用程序部署到生产环境的过程。 在开发中使用容器具有以下好处:

  • 环境是一致的,这意味着您可以为项目选择所需的语言和依赖项,而不必担心系统冲突。
  • 环境是隔离的,因此更容易解决问题和加入新的团队成员。
  • 环境是可移植的,允许您打包并与他人共享您的代码。

本教程将向您展示如何使用 Docker 为 Node.js 应用程序设置开发环境。 您将使用 Docker Compose 创建两个容器——一个用于 Node 应用程序,另一个用于 MongoDB 数据库。 因为这个应用程序适用于 Node 和 MongoDB,所以我们的设置将执行以下操作:

  • 将宿主机上的应用代码与容器内的代码同步,方便开发过程中的更改。
  • 确保对应用程序代码的更改无需重新启动即可工作。
  • 为应用程序的数据创建一个受用户和密码保护的数据库。
  • 保留这些数据。

在本教程结束时,您将拥有一个在 Docker 容器上运行的鲨鱼信息应用程序:

先决条件

要遵循本教程,您将需要:

  • 运行 Ubuntu 18.04 的开发服务器,以及具有 sudo 权限和活动防火墙的非 root 用户。 有关如何设置这些的指导,请参阅此 初始服务器设置指南
  • 按照 如何在 Ubuntu 18.04 上安装和使用 Docker 的步骤 1 和 2 安装在您的服务器上的 Docker。
  • 按照 如何在 Ubuntu 18.04 上安装 Docker Compose 的第 1 步,在您的服务器上安装 Docker Compose。

第 1 步 — 克隆项目并修改依赖项

构建此设置的第一步是克隆项目代码并修改其 package.json 文件,其中包括项目的依赖项。 我们将 nodemon 添加到项目的 devDependencies 中,指定我们将在开发期间使用它。 使用 nodemon 运行应用程序可确保在您更改代码时自动重新启动应用程序。

首先,从 DigitalOcean 社区 GitHub 帐户 克隆 nodejs-mongo-mongoose 存储库。 此存储库包含 如何将 MongoDB 与您的节点应用程序集成 中描述的设置中的代码,它解释了如何使用 Mongoose 将 MongoDB 数据库与现有的节点应用程序集成。

将存储库克隆到名为 node_project 的目录中:

git clone https://github.com/do-community/nodejs-mongo-mongoose.git node_project

导航到 node_project 目录:

cd node_project

使用 nano 或您喜欢的编辑器打开项目的 package.json 文件:

nano package.json

在项目依赖项下方和右大括号上方,创建一个包含 nodemon 的新 devDependencies 对象:

~/node_project/package.json

...
"dependencies": {
    "ejs": "^2.6.1",
    "express": "^4.16.4",
    "mongoose": "^5.4.10"
  },
  "devDependencies": {
    "nodemon": "^1.18.10"
  }    
}

完成编辑后保存并关闭文件。

在项目代码到位并修改其依赖项后,您可以继续为容器化工作流重构代码。

第 2 步 — 配置您的应用程序以使用容器

为容器化工作流修改我们的应用程序意味着使我们的代码更加模块化。 容器提供环境之间的可移植性,我们的代码应该通过尽可能与底层操作系统分离来反映这一点。 为了实现这一点,我们将重构我们的代码,以更好地利用 Node 的 process.env 属性,该属性返回一个对象,其中包含有关运行时用户环境的信息。 我们可以在我们的代码中使用这个对象在运行时使用环境变量动态分配配置信息。

让我们从我们的主要应用程序入口点 app.js 开始。 打开文件:

nano app.js

在内部,您将看到 port constant 的定义,以及使用此常量指定应用程序将侦听的端口的 侦听函数

~/home/node_project/app.js

...
const port = 8080;
...
app.listen(port, function () {
  console.log('Example app listening on port 8080!');
});

让我们重新定义 port 常量,以允许在运行时使用 process.env 对象进行动态分配。 对常量定义和 listen 函数进行以下更改:

~/home/node_project/app.js

...
const port = process.env.PORT || 8080;
...
app.listen(port, function () {
  console.log(`Example app listening on ${port}!`);
});

我们的新常量定义使用运行时传入的值或 8080 动态分配 port。 同样,我们重写了 listen 函数以使用 模板字面量 ,它将在侦听连接时插入端口值。 因为我们将在其他地方映射我们的端口,所以这些修订将阻止我们随着环境的变化而不断地修改这个文件。

完成编辑后,保存并关闭文件。

接下来,我们将修改我们的数据库连接信息以删除任何配置凭据。 打开 db.js 文件,其中包含以下信息:

nano db.js

目前,该文件执行以下操作:

  • 导入 Mongoose,我们用来为我们的应用程序数据创建模式和模型的 Object Document Mapper (ODM)。
  • 将数据库凭据设置为常量,包括用户名和密码。
  • 使用 mongoose.connect 方法 连接到数据库。

有关该文件的更多信息,请参阅如何将MongoDB与您的节点应用程序集成步骤3

我们修改文件的第一步是重新定义包含敏感信息的常量。 目前,这些常量如下所示:

~/node_project/db.js

...
const MONGO_USERNAME = 'sammy';
const MONGO_PASSWORD = 'your_password';
const MONGO_HOSTNAME = '127.0.0.1';
const MONGO_PORT = '27017';
const MONGO_DB = 'sharkinfo';
...

您可以使用 process.env 对象来捕获这些常量的运行时值,而不是硬编码此信息。 将块修改为如下所示:

~/node_project/db.js

...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;
...

完成编辑后保存并关闭文件。

此时,您已修改 db.js 以使用应用程序的环境变量,但您仍需要一种方法将这些变量传递给您的应用程序。 让我们创建一个 .env 文件,其中包含您可以在运行时传递给应用程序的值。

打开文件:

nano .env

该文件将包含您从 db.js 中删除的信息:应用程序数据库的用户名和密码,以及端口设置和数据库名称。 请记住使用您自己的信息更新此处列出的用户名、密码和数据库名称:

~/node_project/.env

MONGO_USERNAME=sammy
MONGO_PASSWORD=your_password
MONGO_PORT=27017
MONGO_DB=sharkinfo

请注意,我们已经 删除了 最初出现在 db.js 中的主机设置。 我们现在将在 Docker Compose 文件级别定义我们的主机,以及有关我们的服务和容器的其他信息。

完成编辑后保存并关闭此文件。

因为您的 .env 文件包含敏感信息,您需要确保它包含在项目的 .dockerignore.gitignore 文件中,这样它就不会复制到您的版本控制或容器。

打开您的 .dockerignore 文件:

nano .dockerignore

将以下行添加到文件的底部:

~/node_project/.dockerignore

...
.gitignore
.env

完成编辑后保存并关闭文件。

此存储库中的 .gitignore 文件已经包含 .env,但请随时检查它是否存在:

nano .gitignore

~~/node_project/.gitignore

...
.env
...

至此,您已经成功地从项目代码中提取了敏感信息,并采取了措施来控制这些信息被复制的方式和位置。 现在,您可以为您的数据库连接代码添加更多健壮性,以针对容器化工作流程对其进行优化。

第 3 步 — 修改数据库连接设置

我们的下一步将是通过添加代码来处理我们的应用程序无法连接到我们的数据库的情况,从而使我们的数据库连接方法更加健壮。 在使用 Compose 处理容器时,将这种级别的弹性引入应用程序代码是 推荐的做法

打开db.js进行编辑:

nano db.js

您将看到我们之前添加的代码,以及 Mongo 连接 URI 的 url 常量和 Mongoose connect 方法:

~/node_project/db.js

...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;

const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

mongoose.connect(url, {useNewUrlParser: true});

目前,我们的 connect 方法接受一个选项,告诉 Mongoose 使用 Mongo 的 新 URL 解析器 。 让我们为这个方法添加更多选项来定义重新连接尝试的参数。 除了新的 URL 解析器选项之外,我们可以通过创建一个包含相关信息的 options 常量来做到这一点。 在 Mongo 常量下方,为 options 常量添加以下定义:

~/node_project/db.js

...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;

const options = {
  useNewUrlParser: true,
  reconnectTries: Number.MAX_VALUE,
  reconnectInterval: 500, 
  connectTimeoutMS: 10000,
};
...

reconnectTries 选项告诉 Mongoose 继续无限期地尝试连接,而 reconnectInterval 定义连接尝试之间的时间间隔(以毫秒为单位)。 connectTimeoutMS 将 10 秒定义为 Mongo 驱动程序在连接尝试失败之前将等待的时间段。

我们现在可以在 Mongoose connect 方法中使用新的 options 常量来微调我们的 Mongoose 连接设置。 我们还将添加一个 promise 来处理潜在的连接错误。

目前,Mongoose connect 方法如下所示:

~/node_project/db.js

...
mongoose.connect(url, {useNewUrlParser: true});

删除现有的 connect 方法并将其替换为以下代码,其中包括 options 常量和承诺:

~/node_project/db.js

...
mongoose.connect(url, options).then( function() {
  console.log('MongoDB is connected');
})
  .catch( function(err) {
  console.log(err);
});

如果连接成功,我们的函数会记录适当的消息; 否则它将 捕获 并记录错误,以便我们进行故障排除。

完成的文件将如下所示:

~/node_project/db.js

const mongoose = require('mongoose');

const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;

const options = {
  useNewUrlParser: true,
  reconnectTries: Number.MAX_VALUE,
  reconnectInterval: 500,
  connectTimeoutMS: 10000,
};

const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

mongoose.connect(url, options).then( function() {
  console.log('MongoDB is connected');
})
  .catch( function(err) {
  console.log(err);
});

完成编辑后保存并关闭文件。

您现在已经为应用程序代码添加了弹性,以处理应用程序可能无法连接到数据库的情况。 使用此代码,您可以继续使用 Compose 定义您的服务。

第 4 步 — 使用 Docker Compose 定义服务

重构代码后,您就可以使用服务定义编写 docker-compose.yml 文件了。 Compose 中的 service 是一个正在运行的容器,并且服务定义(您将包含在 docker-compose.yml 文件中)包含有关每个容器映像如何运行的信息。 Compose 工具允许您定义多个服务来构建多容器应用程序。

然而,在定义我们的服务之前,我们将在我们的项目中添加一个名为 wait-for 的工具,以确保我们的应用程序仅在数据库启动任务完成后才尝试连接到我们的数据库。 此包装脚本使用 netcat 来轮询特定主机和端口是否正在接受 TCP 连接。 使用它,您可以通过测试数据库是否准备好接受连接来控制应用程序连接到数据库的尝试。

尽管 Compose 允许您使用 depends_on 选项 指定服务之间的依赖关系,但此顺序基于容器是否正在运行而不是它的就绪状态。 使用 depends_on 对我们的设置来说不是最佳选择,因为我们希望我们的应用程序仅在数据库启动任务(包括将用户和密码添加到 admin 身份验证数据库)完成时进行连接。 关于使用wait-for等工具控制启动顺序的更多信息,请参见Compose文档中的相关建议。

打开一个名为 wait-for.sh 的文件:

nano wait-for.sh

将以下代码粘贴到文件中以创建轮询函数:

~/node_project/app/wait-for.sh

#!/bin/sh

# original script: https://github.com/eficode/wait-for/blob/master/wait-for

TIMEOUT=15
QUIET=0

echoerr() {
  if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
}

usage() {
  exitcode="$1"
  cat << USAGE >&2
Usage:
  $cmdname host:port [-t timeout] [-- command args]
  -q | --quiet                        Do not output any status messages
  -t TIMEOUT | --timeout=timeout      Timeout in seconds, zero for no timeout
  -- COMMAND ARGS                     Execute command with args after the test finishes
USAGE
  exit "$exitcode"
}

wait_for() {
  for i in `seq $TIMEOUT` ; do
    nc -z "$HOST" "$PORT" > /dev/null 2>&1
    
    result=$?
    if [ $result -eq 0 ] ; then
      if [ $# -gt 0 ] ; then
        exec "$@"
      fi
      exit 0
    fi
    sleep 1
  done
  echo "Operation timed out" >&2
  exit 1
}

while [ $# -gt 0 ]
do
  case "$1" in
    *:* )
    HOST=$(printf "%s\n" "$1"| cut -d : -f 1)
    PORT=$(printf "%s\n" "$1"| cut -d : -f 2)
    shift 1
    ;;
    -q | --quiet)
    QUIET=1
    shift 1
    ;;
    -t)
    TIMEOUT="$2"
    if [ "$TIMEOUT" = "" ]; then break; fi
    shift 2
    ;;
    --timeout=*)
    TIMEOUT="${1#*=}"
    shift 1
    ;;
    --)
    shift
    break
    ;;
    --help)
    usage 0
    ;;
    *)
    echoerr "Unknown argument: $1"
    usage 1
    ;;
  esac
done

if [ "$HOST" = "" -o "$PORT" = "" ]; then
  echoerr "Error: you need to provide a host and port to test."
  usage 2
fi

wait_for "$@"

添加完代码后保存并关闭文件。

使脚本可执行:

chmod +x wait-for.sh

接下来,打开docker-compose.yml文件:

nano docker-compose.yml

首先,通过将以下代码添加到文件中来定义 nodejs 应用程序服务:

~/node_project/docker-compose.yml

version: '3'

services:
  nodejs:
    build:
      context: .
      dockerfile: Dockerfile
    image: nodejs
    container_name: nodejs
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_USERNAME=$MONGO_USERNAME
      - MONGO_PASSWORD=$MONGO_PASSWORD
      - MONGO_HOSTNAME=db
      - MONGO_PORT=$MONGO_PORT
      - MONGO_DB=$MONGO_DB 
    ports:
      - "80:8080"
    volumes:
      - .:/home/node/app
      - node_modules:/home/node/app/node_modules
    networks:
      - app-network
    command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js

nodejs 服务定义包括以下选项:

  • build:这定义了 Compose 构建应用程序映像时将应用的配置选项,包括 contextdockerfile。 如果你想使用像 Docker Hub 这样的注册表中的现有镜像,你可以使用 image 指令 来代替,其中包含有关你的用户名、存储库和镜像标签的信息。

  • context:这定义了映像构建的构建上下文——在这种情况下,是当前项目目录。

  • dockerfile:指定当前项目目录中的 Dockerfile 作为 Compose 将用来构建应用程序映像的文件。 有关此文件的更多信息,请参阅 如何使用 Docker 构建 Node.js 应用程序

  • imagecontainer_name:这些将名称应用于图像和容器。

  • restart:定义重启策略。 默认为 no,但我们已将容器设置为重启,除非它停止。

  • env_file:这告诉 Compose 我们想从位于我们构建上下文中的名为 .env 的文件中添加环境变量。

  • environment:使用此选项允许您添加您在 .env 文件中定义的 Mongo 连接设置。 请注意,我们没有将 NODE_ENV 设置为 development,因为如果未设置 NODE_ENV,这是 Express 的 默认 行为。 转移到生产环境时,您可以将其设置为 production启用视图缓存和不太详细的错误消息 。 另请注意,我们已将 db 数据库容器指定为主机,如 Step 2 中所述。

  • ports:这会将主机上的端口 80 映射到容器上的端口 8080

  • volumes:我们在这里包括两种类型的坐骑:

    • 第一个是 bind mount ,它将我们在主机上的应用程序代码挂载到容器上的 /home/node/app 目录。 这将有助于快速开发,因为您对主机代码所做的任何更改都将立即填充到容器中。
    • 第二个是命名为 node_modules。 当 Docker 运行应用程序 Dockerfile 中列出的 npm install 指令时,npm 将在容器上创建一个新的 node_modules 目录,其中包含运行所需的包应用程序。 然而,我们刚刚创建的绑定挂载将隐藏这个新创建的 node_modules 目录。 由于主机上的 node_modules 是空的,绑定会将一个空目录映射到容器,覆盖新的 node_modules 目录并阻止我们的应用程序启动。 命名的 node_modules 卷通过持久化 /home/node/app/node_modules 目录的内容并将其挂载到容器中来解决此问题,隐藏绑定。

    使用这种方法时要记住以下几点

    • 您的绑定会将容器上 node_modules 目录的内容挂载到主机,并且该目录将归 root 所有,因为命名卷是由 Docker 创建的。
    • 如果您在主机上有一个预先存在的 node_modules 目录,它将覆盖在容器上创建的 node_modules 目录。 我们在本教程中构建的设置假定您确实 有一个预先存在的 node_modules 目录,并且您不会在您的 npm主持人。 这与应用程序开发的 十二因素方法 保持一致,它最大限度地减少了执行环境之间的依赖关系。
  • networks:这指定我们的应用服务将加入 app-network 网络,我们将在文件底部定义。

  • command:此选项可让您设置 Compose 运行图像时应执行的命令。 请注意,这将覆盖我们在应用程序 Dockerfile 中设置的 CMD 指令。 在这里,我们使用 wait-for 脚本运行应用程序,该脚本将轮询端口 27017 上的 db 服务以测试数据库服务是否准备好。 一旦准备就绪测试成功,脚本将执行我们设置的命令,/home/node/app/node_modules/.bin/nodemon app.js,以nodemon启动应用程序。 这将确保我们将来对代码所做的任何更改都会重新加载,而无需重新启动应用程序。

接下来,通过在应用服务定义下方添加以下代码来创建 db 服务:

~/node_project/docker-compose.yml

...
  db:
    image: mongo:4.1.8-xenial
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME
      - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD
    volumes:  
      - dbdata:/data/db   
    networks:
      - app-network  

我们为 nodejs 服务定义的一些设置保持不变,但我们还对 imageenvironmentvolumes 进行了以下更改] 定义:

  • image:要创建此服务,Compose 将从 Docker Hub 中提取 4.1.8-xenial Mongo 映像。 我们正在固定一个特定的版本,以避免将来随着 Mongo 图像的变化而发生冲突。 有关版本固定的更多信息,请参阅 Dockerfile 最佳实践 上的 Docker 文档。
  • MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORDmongo 映像使这些 环境变量 可用,以便您可以修改数据库实例的初始化。 MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD一起在admin鉴权数据库中创建一个root用户,并保证容器启动时鉴权是开启的。 我们使用 .env 文件中的值设置了 MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD,我们使用 env_file 选项将其传递给 db 服务. 这样做意味着我们的 sammy 应用程序用户将成为数据库实例上的 root 用户,可以访问该角色的所有管理和操作权限。 在生产中工作时,您需要创建一个具有适当范围权限的专用应用程序用户。 <$>[注] 笔记: 请记住,如果您使用现有数据目录启动容器,这些变量将不会生效。 <$>
  • dbdata:/data/db:命名卷dbdata将持久化存储在Mongo的默认数据目录/data/db中的数据。 这将确保您在停止或删除容器的情况下不会丢失数据。

我们还使用 networks 选项将 db 服务添加到 app-network 网络。

最后一步,将卷和网络定义添加到文件底部:

~/node_project/docker-compose.yml

...
networks:
  app-network:
    driver: bridge

volumes:
  dbdata:
  node_modules:  

用户定义的桥接网络 app-network 支持我们的容器之间的通信,因为它们位于同一个 Docker 守护程序主机上。 这简化了应用程序内的流量和通信,因为它打开了同一桥接网络上容器之间的所有端口,同时不向外界公开任何端口。 因此,我们的 dbnodejs 容器可以相互通信,我们只需要暴露端口 80 以便前端访问应用程序。

我们的顶级 volumes 键定义了体积 dbdatanode_modules。 当 Docker 创建卷时,卷的内容存储在由 Docker 管理的主机文件系统 /var/lib/docker/volumes/ 的一部分中。 每个卷的内容都存储在 /var/lib/docker/volumes/ 下的目录中,并被挂载到使用该卷的任何容器中。 这样,即使我们删除并重新创建 db 容器,我们的用户将创建的鲨鱼信息数据将保留在 dbdata 卷中。

完成的 docker-compose.yml 文件将如下所示:

~/node_project/docker-compose.yml

version: '3'

services:
  nodejs:
    build:
      context: .
      dockerfile: Dockerfile
    image: nodejs
    container_name: nodejs
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_USERNAME=$MONGO_USERNAME
      - MONGO_PASSWORD=$MONGO_PASSWORD
      - MONGO_HOSTNAME=db
      - MONGO_PORT=$MONGO_PORT
      - MONGO_DB=$MONGO_DB
    ports:
      - "80:8080"
    volumes:
      - .:/home/node/app
      - node_modules:/home/node/app/node_modules
    networks:
      - app-network
    command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js 

  db:
    image: mongo:4.1.8-xenial
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME
      - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD
    volumes:     
      - dbdata:/data/db
    networks:
      - app-network  

networks:
  app-network:
    driver: bridge

volumes:
  dbdata:
  node_modules:  

完成编辑后保存并关闭文件。

准备好服务定义后,您就可以启动应用程序了。

第 5 步 — 测试应用程序

准备好 docker-compose.yml 文件后,您可以使用 docker-compose up 命令创建服务。 您还可以通过使用 docker-compose down 停止和删除容器来测试您的数据是否会持续存在。

首先,通过运行带有 -d 标志的 docker-compose up 来构建容器映像并创建服务,然后在后台运行 nodejsdb 容器:

docker-compose up -d

您将看到确认您的服务已创建的输出:

Output...
Creating db ... done
Creating nodejs ... done

您还可以通过显示服务的日志输出来获取有关启动过程的更多详细信息:

docker-compose logs 

如果一切都已正确启动,您将看到如下内容:

Output...
nodejs    | [nodemon] starting `node app.js`
nodejs    | Example app listening on 8080!
nodejs    | MongoDB is connected
...
db        | 2019-02-22T17:26:27.329+0000 I ACCESS   [conn2] Successfully authenticated as principal sammy on admin

您还可以使用 docker-compose ps 检查容器的状态:

docker-compose ps

您将看到指示您的容器正在运行的输出:

Output Name               Command               State          Ports        
----------------------------------------------------------------------
db       docker-entrypoint.sh mongod      Up      27017/tcp           
nodejs   ./wait-for.sh db:27017 --  ...   Up      0.0.0.0:80->8080/tcp

随着您的服务运行,您可以在浏览器中访问 http://your_server_ip。 您将看到如下所示的登录页面:

单击获取鲨鱼信息按钮。 您将看到一个带有输入表单的页面,您可以在其中输入鲨鱼名称和对该鲨鱼一般特征的描述:

在表格中,添加您选择的鲨鱼。 出于演示的目的,我们将 Megalodon Shark 添加到 Shark Name 字段,并将 Ancient 添加到 Shark Character 字段:

单击提交按钮。 您将看到一个页面,其中向您显示此鲨鱼信息:

作为最后一步,我们可以测试如果您删除数据库容器,您刚刚输入的数据是否会保留。

返回您的终端,键入以下命令以停止和删除您的容器和网络:

docker-compose down

注意我们是 not 包括 --volumes 选项; 因此,我们的 dbdata 卷不会被删除。

以下输出确认您的容器和网络已被删除:

OutputStopping nodejs ... done
Stopping db     ... done
Removing nodejs ... done
Removing db     ... done
Removing network node_project_app-network

重新创建容器:

docker-compose up -d

现在回到鲨鱼信息表:

输入您选择的新鲨鱼。 我们将使用 Whale SharkLarge

单击 Submit 后,您将看到新鲨鱼已添加到数据库中的鲨鱼集合中,而您已经输入的数据不会丢失:

您的应用程序现在在启用了数据持久性和代码同步的 Docker 容器上运行。

结论

按照本教程,您已经使用 Docker 容器为您的 Node 应用程序创建了开发设置。 通过提取敏感信息并将应用程序的状态与应用程序代码解耦,您使您的项目更加模块化和可移植。 您还配置了一个样板 docker-compose.yml 文件,您可以根据开发需求和要求的变化对其进行修改。

随着您的开发,您可能有兴趣了解有关为容器化和 Cloud Native 工作流程设计应用程序的更多信息。 有关这些主题的更多信息,请参阅 为 Kubernetes 构建应用程序为 Kubernetes 现代化应用程序

要了解有关本教程中使用的代码的更多信息,请参阅 如何使用 Docker 构建 Node.js 应用程序如何将 MongoDB 与您的节点应用程序集成。 有关使用容器使用 Nginx 反向代理部署 Node 应用程序的信息,请参阅 如何使用 Nginx、Let's Encrypt 和 Docker Compose 保护容器化的 Node.js 应用程序