Docker Compose 容器化 Node.js 应用:开发环境高效部署指南

引言

如果您正在积极开发一个应用程序,使用Docker可以极大地简化您的工作流程,并加速应用程序部署到生产环境的过程。在开发过程中采用容器化技术具有以下显著优势:

  • 环境一致性: 您可以自由选择项目所需的编程语言和依赖项,而无需担心系统冲突问题。
  • 环境隔离性: 有助于更轻松地排查问题,并加速新团队成员的上手过程。
  • 环境可移植性: 允许您轻松打包代码并与他人共享。

本教程将详细指导您如何使用Docker为Node.js应用程序搭建开发环境。您将利用Docker Compose创建两个容器:一个用于Node应用程序,另一个用于MongoDB数据库。鉴于该应用程序需要Node和MongoDB协同工作,您的设置将实现以下功能:

  • 将宿主机上的应用程序代码与容器内的代码同步,以便在开发过程中实时修改。
  • 确保应用程序代码的更改无需重启即可生效。
  • 为应用程序数据创建一个受用户和密码保护的数据库。
  • 持久化存储这些数据。

完成本教程后,您将拥有一个在Docker容器中运行的、功能完备的鲨鱼信息应用程序。

完整的鲨鱼收藏登录页面

前提条件

要顺利完成本教程,您需要满足以下条件:

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

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

首先,从Silicon Cloud社区的GitHub账户克隆nodejs-mongo-mongoose存储库。该存储库包含了在《如何将MongoDB与Node应用程序集成》中描述的设置代码,该说明了如何使用Mongoose将MongoDB数据库与现有的Node应用程序集成。

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

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

 

请进入node_project目录。

  1. cd node_project

 

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

  1. nano package.json

 

在项目依赖之下、闭合大括号之上,创建一个新的devDependencies对象,其中包括nodemon

以下是~/node_project/package.json的原文中文释义:

“~” 代表用户的 home 目录
“node_project” 是一个文件夹名字
“package.json” 是一个 JSON 格式的配置文件。

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

当您编辑完成后,保存并关闭文件。如果您使用的是nano文本编辑器,请按下CTRL+X,然后按Y,最后按ENTER

项目代码已设置完毕,相关依赖项也已修改,现在您可以开始重构代码以适应容器化工作流程。

第二步——配置您的应用程序以与容器协同工作

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

app.js开始,这是您的主应用程序入口点。打开文件:

  1. nano app.js

 

在文件内部,您将看到一个端口常量的定义,以及一个使用该常量来指定应用程序将监听的端口的监听函数。

在中国的母语中把以下内容改述一遍,只需要一种选项:
~/home/node_project/app.js

这是文章《使用Docker Compose 将 Node.js 应用程序进行容器化,用于开发》的第2部分(共10部分)。

内容片段:

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

通过使用 process.env 对象在运行时允许动态分配端口常量,重新定义端口常量。对常量定义和监听函数进行以下更改:

~/home/node_project/app.js 可以用以下的方式在中文中表达:

家目录/节点项目/app.js

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

您的新常量定义会动态地使用运行时传入的值或 8080 端口来分配端口。同样地,您已经重写了监听函数,使用了模板字面量,当监听连接时,它将插值端口值。因为您将在其他地方映射您的端口,这些修改将避免您不断修改此文件以适应环境变化。

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

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

  1. nano db.js

 

目前,该文件具有以下功能:

  • 导入 Mongoose,您正在使用的对象文档映射器(ODM),用于为您的应用程序数据创建模式和模型。
  • 将数据库凭据设置为常量,包括用户名和密码。
  • 使用 mongoose.connect 方法连接到数据库。

有关此文件的更多信息,请参见《如何将MongoDB与您的Node应用程序集成》第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 的中文翻译版本:~/node_project/db.js

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

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

在这一点上,您已经修改了 db.js 以与您的应用程序环境变量配合使用,但您仍然需要一种将这些变量传递给您的应用程序的方式。创建一个 .env 文件,并提供值以在运行时传递给您的应用程序。

打开文件。

  1. 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 文件。

  1. nano .dockerignore

 

请将以下内容添加到文件的底部:

只需要一种选项,以下是对“~/node_project/.dockerignore”进行中文本地化解释:

“只需一个路径选择,表示“~/node_project/.dockerignore”。”

...
.gitignore
.env

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

这个代码仓库中的 .gitignore 文件已经包含了 .env 文件,但是请随意检查它是否存在。

  1. nano .gitignore

 

~/node_project/.gitignore 只需要一个选项,用中文进行同义转述:“~/node_project/.gitignore 文件”。

...
.env
...

在这一点上,您已成功从项目代码中提取出敏感信息,并采取措施来控制这些信息的复制方式和位置。现在,您可以优化数据库连接代码,以适应容器化工作流程。

第三步 – 修改数据库连接设置

您下一步需要做的是通过添加处理应用程序无法连接到数据库的代码,使您的数据库连接方法更加强健可靠。当使用 Compose 来处理容器时,引入这种弹性水平到您的应用程序代码是一种推荐的做法。

打开 db.js 进行编辑。

  1. nano db.js

 

注意之前添加的代码,以及用于 Mongo 连接 URI 的 URL 常量和 Mongoose 连接方法。

~/node_project/db.js 的汉语本地化的一个选项就是:

这是文章《使用Docker Compose 将 Node.js 应用程序进行容器化,用于开发》的第3部分(共10部分)。

...
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 解析器。您可以在这个方法中添加选项来定义重新连接尝试的参数。通过创建一个 options 常量来包含相关信息,除了新的 URL 解析器选项。在您的 Mongo 常量下方,添加以下对 options 常量的定义:

请将以下内容以中文进行本地化改写:~/节点项目/数据库.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 将使 Mongo 驱动程序在连接尝试失败之前等待 10 秒钟。

现在您可以在 Mongoose 的 connect 方法中使用新的 options 常量来微调您的 Mongoose 连接设置。您还需要添加一个 Promise 来处理可能的连接错误。

目前,Mongoose 的连接方法如下所示:

~/节点项目/数据库.js

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

删除现有的连接方法,并用包含 options 常量和 Promise 的以下代码替换。

请将以下路径更改为本地文件路径:~/node_project/db.js

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

在成功连接的情况下,您的函数将记录一条适当的消息;否则,它将捕获并记录错误,以便您进行故障排除。

完成的文件将如下所示:

~/节点项目/数据库.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 已连接');
})
  .catch( function(err) {
  console.log(err);
});

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

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

第四步 – 使用 Docker Compose 定义服务

这是文章《使用Docker Compose 将 Node.js 应用程序进行容器化,用于开发》的第5部分(共10部分)。

在你重构了代码之后,你可以开始编写docker-compose.yml文件来定义你的服务。在Docker Compose中,服务是运行中的容器实例,而服务定义——即你在docker-compose.yml文件中配置的信息——包含了每个容器镜像如何运行的详细说明。Compose工具允许你定义多个服务,从而构建复杂的多容器应用程序。

在定义你的服务之前,你将向你的项目添加一个名为“wait-for”的工具。这个工具的目的是确保你的应用程序仅在数据库启动任务完全完成后才尝试连接数据库。这个包装脚本利用netcat来轮询特定的主机和端口,以确认它们是否接受TCP连接。通过测试数据库是否已准备好接受连接,它能有效控制应用程序连接数据库的时机。

尽管Compose允许你使用depends_on选项来指定服务之间的依赖关系,但这种顺序仅基于容器是否正在运行,而非其“就绪状态”。对于你的设置而言,depends_on并不是最佳选择,因为你希望应用程序仅在数据库启动任务(包括向管理员身份验证数据库添加用户和密码)完全完成后才进行连接。有关使用wait-for及其他工具控制启动顺序的更多信息,请参阅Compose文档中的相关建议。

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

nano wait-for.sh

输入以下代码到文件中以创建轮询函数:

~/node_project/app/wait-for.sh 的中文翻译为:~/node_project/app/等待.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

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

~/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

Node.js 服务定义包括以下选项:

  • build(构建): 此选项定义了当 Compose 构建应用程序镜像时将应用的配置选项,包括上下文(context)和 Dockerfile。如果您想使用来自 Docker Hub 等注册表的现有镜像,则可以使用 image 指令,并提供您的用户名、仓库和镜像标签信息。
  • context(上下文): 此选项定义了镜像构建的构建上下文——在本例中,即当前项目目录。
  • dockerfile: 此选项指定了当前项目目录中的 Dockerfile 作为 Compose 用于构建应用程序镜像的文件。有关此文件的更多信息,请参阅“如何使用 Docker 构建 Node.js 应用程序”。
  • image(镜像), container_name(容器名称): 这些选项用于为镜像和容器命名。
  • restart(重启策略): 此选项定义了重启策略。默认值为 no(不重启),但您已将容器设置为除非停止(unless-stopped)才重启。
  • env_file(环境变量文件): 此选项告诉 Compose 您希望从构建上下文中的名为 .env 的文件中添加环境变量。
  • environment(环境变量): 使用此选项可以添加您在 .env 文件中定义的 Mongo 连接设置。请注意,您没有将 NODE_ENV 设置为 development,因为如果未设置 NODE_ENV,这是 Express 的默认行为。当部署到生产环境时,您可以将其设置为 production 以启用视图缓存和更简洁的错误消息。另请注意,您已将 db 数据库容器指定为宿主,如第2步所述。
  • ports(端口映射): 此选项将宿主机的 80 端口映射到容器的 8080 端口。
  • volumes(卷): 您在此处包含了两种类型的挂载:
    1. 第一种是绑定挂载(bind mount),它将宿主机上的应用程序代码挂载到容器上的 /home/node/app 目录。这将促进快速开发,因为您对宿主机代码所做的任何更改都会立即同步到容器中。
    2. 第二种是命名卷(named volume),名为 node_modules。当 Docker 运行应用程序 Dockerfile 中列出的 npm install 指令时,npm 将在容器上创建一个新的 node_modules 目录,其中包含运行应用程序所需的包。然而,您刚刚创建的绑定挂载将隐藏这个新创建的 node_modules 目录。由于宿主机上的 node_modules 是空的,绑定挂载会将一个空目录映射到容器,从而覆盖新的 node_modules 目录并阻止您的应用程序启动。命名卷 node_modules 通过持久化 /home/node/app/node_modules 目录的内容并将其挂载到容器来解决此问题,从而避免了绑定挂载的影响。

注意:此部分是文章《使用Docker Compose 将 Node.js 应用程序进行容器化,用于开发》的第6部分(共10部分)。

使用这种方法时,请记住以下几点:

您的绑定会将容器中的 node_modules 目录内容挂载到主机上,并且该目录的所有者将是 root,因为这个命名卷是由 Docker 创建的。

如果主机上已经存在一个预先存在的 node_modules 目录,则会覆盖在容器中创建的 node_modules 目录。本教程中构建的设置假设您在主机上没有预先存在的 node_modules 目录,也不会在主机上使用 npm。这符合应用程序开发的十二要素方法,该方法最大限度地减少执行环境之间的依赖关系。

  • networks(网络):这指定了您的应用程序服务将加入 app-network 网络,您将在文件底部定义该网络。
  • command(命令):此选项允许您设置当 Compose 运行镜像时应执行的命令。请注意,这将覆盖您在应用程序 Dockerfile 中设置的 CMD 指令。在这里,您使用 wait-for 脚本运行应用程序,该脚本将轮询 db 服务的 27017 端口,以测试数据库服务是否就绪。一旦就绪性测试成功,脚本将执行您设置的命令 /home/node/app/node_modules/.bin/nodemon app.js,以使用 nodemon 启动应用程序。这将确保您对代码进行的任何未来更改都会被重新加载,而无需重新启动应用程序。

接下来,在应用程序服务定义之后添加以下代码来创建数据库服务。

~/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 服务,一些设置保持不变,但您还对镜像、环境和卷的定义进行了以下更改:

  • image(镜像):为了创建此服务,Compose 将从 Docker Hub 拉取 4.1.8-xenial 版本的 Mongo 镜像。您正在固定一个特定版本,以避免 Mongo 镜像更改可能导致的未来冲突。有关版本固定的更多信息,请参阅 Docker 关于 Dockerfile 最佳实践的文档。
  • MONGO_INITDB_ROOT_USERNAME, MONGO_INITDB_ROOT_PASSWORD:Mongo 镜像提供了这些环境变量,以便您可以修改数据库实例的初始化。MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD 一起在管理认证数据库中创建一个根用户,并确保容器启动时启用认证。您使用 .env 文件中的值设置了 MONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORD,并通过 env_file 选项将其传递给 db 服务。这样做意味着您的 sammy 应用程序用户将成为数据库实例上的根用户,拥有该角色所有的管理和操作权限。在生产环境中工作时,您会希望创建一个具有适当范围权限的专用应用程序用户。

注意:请记住,如果您使用已存在的数据目录启动容器,这些变量将不会生效。

  • dbdata:/data/db:命名卷 dbdata 将持久化存储在 Mongo 默认数据目录 /data/db 中的数据。这将确保在停止或移除容器的情况下,您不会丢失数据。

通过使用 networks 选项,db 服务也被添加到了 app-network 网络中。

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

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

volumes:
  dbdata:
  node_modules:  

用户定义的桥接网络 app-network 允许在同一 Docker 守护进程主机上的容器之间进行通信。这简化了应用程序内部的流量和通信,因为它在相同的桥接网络上为容器间通信开放了所有端口,同时不向外部暴露任何端口。因此,您的数据库容器和 Node.js 容器可以相互通信,您只需要暴露 80 端口以便前端访问应用程序。

您的顶级卷键定义了 dbdatanode_modules 两个卷。当 Docker 创建卷时,卷的内容存储在由 Docker 管理的主机文件系统的一部分,即 /var/lib/docker/volumes/ 中。每个卷的内容都存储在 /var/lib/docker/volumes/ 下的一个目录中,并被挂载到使用该卷的任何容器中。通过这种方式,即使您删除并重新创建数据库容器,您的用户创建的鲨鱼信息数据也将持久保存在 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:  

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

在您已经设置了服务定义之后,您就可以开始应用程序了。

第五步 – 测试应用程序

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

首先,通过运行带有 -d 标志的 docker-compose up 命令,构建容器镜像并创建服务,然后将在后台运行 nodejsdb 容器。

  1. docker-compose up -d

 

输出确认您的服务已经创建。

输出

这是文章《使用Docker Compose 将 Node.js 应用程序进行容器化,用于开发》的第10部分(共10部分)。

… Creating db … done

Creating nodejs … done

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

  1. docker-compose logs

 

如果一切启动正确,以下是输出结果。

输出

… 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命令来检查您的容器状态。

  1. docker-compose ps

 

输出表明您的容器正在运行。

输出

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

Everything Sharks Application Landing Page

点击“获取鲨鱼信息”按钮,进入一个包含输入表单的页面,您可以在页面上提交鲨鱼名称和鲨鱼一般特征描述。

Shark Info Form where you can enter a shark name and the characteristics of that shark

在表格中,添加您选择的一种鲨鱼。为了进行演示,请将“巨牙鲨”添加到鲨鱼名称栏,并在鲨鱼特征栏中添加“古老”。

Filled Shark Form

点击提交按钮,会将包含这些鲨鱼信息的页面显示给您。

Shark Output from the form you submitted

作为最后一步,测试一下您刚刚输入的数据是否会在删除数据库容器后继续存在。

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

  1. docker-compose down

 

请注意,您没有包括“–volumes”选项,因此您的“dbdata”卷不会被删除。

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

输出

Stopping nodejs … done

Stopping db … done

Removing nodejs … done

Removing db … done

Removing network node_project_app-network

重新创建容器

  1. docker-compose up -d

 

现在返回到鲨鱼信息表:

Shark Info Form

选择一种新的鲨鱼输入。本例将使用“座头鲸鲨”和“大型”:

Enter New Shark

一旦您点击提交按钮,您会注意到新的鲨鱼已经添加到您的数据库的鲨鱼收藏中,而且您之前输入的数据没有丢失。

Complete Shark Collection

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

结论

通过遵循本教程,您已经使用 Docker 容器为您的 Node 应用程序建立了开发环境。通过提取敏感信息并将应用程序状态与应用程序代码解耦,您使得您的项目更加模块化和易于携带。您还配置了一个模板化的 docker-compose.yml 文件,可以根据您的开发需求和要求进行修改。

随着您的发展,您可能对学习如何设计容器化和云原生工作流的应用程序更感兴趣。请参阅有关 Kubernetes 应用架构和 Kubernetes 应用现代化的更多信息。

请查看《如何使用Docker构建Node.js应用程序》和《如何将MongoDB集成到您的Node应用程序中》以了解本教程中使用的代码。如果想了解使用容器在Nginx反向代理上部署Node应用程序的信息,请查看《如何使用Nginx、Let’s Encrypt和Docker Compose保护容器化的Node.js应用程序》。

bannerAds