Docker: Node.js

如何使用和部署带有Docker的Node.js应用程序

👋 欢迎来到 Stackhero 文档!

Stackhero 提供现成的 Docker 云 CaaS (Containers as a Service) 解决方案,具有众多优势,包括:

  • 只需一个 docker-compose up,即可轻松将您的容器部署到生产环境
  • 使用 HTTPS 保护的可定制域名(例如,https://api.your-company.comhttps://www.your-company.comhttps://backoffice.your-company.com)。
  • 专用私有 VM提供的最佳性能强大安全性
  • 只需点击即可轻松更新

节省时间简化您的生活:只需 5 分钟即可尝试 Stackhero 的 Docker CaaS 云托管 解决方案,并将您的容器部署到生产环境!

本指南为开发Node.js应用程序并快速轻松地将其部署到生产环境提供了坚实的基础。

不需要事先了解Docker。所有设置都已准备好以确保顺畅的体验;您只需在计算机上安装Docker即可。

此文档适用于希望使用现代、可扩展技术部署Node.js应用程序的初学者和有经验的用户,无需不必要的复杂性。

此解决方案的主要特点包括:

  • 💪 简单设置,最小化努力
  • 🐳 使用Docker进行开发和生产环境
  • 🔄 使用nodemon在代码更改时自动重新加载Node.js
  • 🚀 单命令部署到生产环境
  • 🔒 TLS证书管理以确保HTTPS加密安全
  • 🚧 支持暂存和预生产平台
  • 🧱 模块化和可扩展的架构

如果您的计算机尚未安装Docker,可以从Docker官方网站下载。要验证Docker是否正常运行,请打开终端并运行docker version。您应该看到版本信息且没有错误。

安装Docker后,克隆以下样板库:

git clone https://github.com/stackhero-io/nodejsWithDockerGettingStarted/
cd nodejsWithDockerGettingStarted

然后,通过运行make development-start启动开发平台,或使用make help查看所有可用命令。

要启动开发平台,请运行:

make development-start

此命令构建Docker镜像,运行它,并执行在my-app/package.json中定义的dev脚本(相当于运行npm run dev)。

在此示例中,创建了一个使用Express的简单REST API。您可以通过访问http://localhost:5000查看API。页面应显示“Hello World”。

接下来,在您喜欢的IDE中打开文件my-app/src/app.js并修改以下行:

res.send('Hello World');

将其更改为:

res.send('Updated!');

保存文件。Node.js代码将自动重新加载,刷新http://localhost:5000将反映更新后的API响应。

恭喜 - 您现在拥有一个完全可操作的开发平台!

如果需要安装其他软件包,可以运行make development-shell以访问容器shell。进入后,使用NPM运行npm install <package>或使用Yarn运行yarn add <package>来安装所需的软件包。

如果您有一个现有的Node.js项目想要与Docker集成,请按照以下步骤操作:

  1. 在您的项目中创建一个名为my-app的新目录。

  2. 将所有项目文件移动到my-app目录中,排除.gitignore.git文件。

  3. 从样板中复制dockersecretsMakefile到项目的根目录。

  4. 编辑项目中的.gitignore文件并添加以下行:

    node_modules/
    secrets/*.production
    secrets/*.staging
    

此样板假设您的应用程序监听端口5000。如果您更喜欢其他端口,可以编辑docker/docker-compose.development.yml文件,然后使用make development-start重新启动环境。

如果您希望指定不同的Node.js版本,请按照以下步骤操作:

  1. 打开定义应用程序Docker镜像的文件docker/my-app.dockerfile
  2. 找到第一行FROM node:<version>-alpine
  3. <version>替换为您选择的Node.js版本。建议使用长期支持(LTS)版本。您可以在Node.js网站上查看最新的LTS版本。例如,要使用最新的LTS版本(当前为22),将该行更新为FROM node:22-alpine。如果您更喜欢特定的版本号,可以使用类似FROM node:22.13.0-alpine的格式。
  4. 保存对Dockerfile的更改。

在文件secrets/my-app.development中为开发平台设置环境变量。

对于生产环境,请使用secrets/my-app.production文件。

不要将secrets/my-app.production文件提交到您的Git存储库!此文件包含敏感信息,默认在样板的.gitignore中被忽略,以防止意外共享。

如果您的Node.js应用程序需要存储文件(例如用户上传),请考虑使用对象存储服务,例如MinIO。对象存储服务可以帮助您的应用程序无缝扩展,同时减少潜在问题。

如果您更喜欢本地存储文件,请确保始终使用Docker卷。直接在容器中存储文件可能导致数据丢失。此样板提供了一个挂载在/persistent的卷,用于安全存储文件。

除非您创建了自定义卷并确定配置,否则切勿在/persistent目录之外存储持久数据。/persistent之外存储文件将导致数据丢失!

您可以轻松修改此样板以添加暂存环境。为此:

  1. 创建docker/docker-compose.production.yml的副本,并将其命名为docker/docker-compose.staging.yml。此文件定义了暂存环境的容器和配置。
  2. 创建包含暂存所需敏感信息的秘密文件secrets/my-app.staging,例如数据库密码或API密钥。
  3. Makefile中,找到标记为“Staging platform”的部分并取消注释。

最后,运行make help以查看现在可用的新暂存命令。

如果您还没有Stackhero for Docker服务,可以从您的Stackhero仪表板轻松创建一个。它将在大约2分钟内激活。

如果您是Stackhero的新用户,可以免费试用Docker容器云托管一个月。

在将应用程序部署到生产环境之前,您需要准备一些配置文件:

  1. secrets/global.production.example复制到secrets/global.production
  2. 编辑secrets/global.production并将<XXXXXX>.stackhero-network.com替换为来自Stackhero仪表板的Docker服务主机名。
  3. secrets/my-app.production.example复制到secrets/my-app.production
  4. 编辑secrets/my-app.production并插入您的凭据。
  5. 更新docker/docker-compose.production.yml,将<XXXXXX>.stackhero-network.com替换为您的Docker服务主机名。

部署到生产环境很简单:运行:

make production-deploy

此命令创建一个Docker容器,传输您的项目数据,并将其发送到生产环境中的Docker服务。打开浏览器并导航到您的Docker服务主机名(例如,https://<XXXXXX>.stackhero-network.com)。您应该看到您的REST API回复“Hello World”。

您还可以使用make production,它会部署您的容器并显示实时日志。

要监控生产环境或排除故障,可以使用以下命令查看日志:

  • 要流式传输实时日志,请运行:make production-logs-live
  • 要检索所有存储的日志,请运行:make production-logs
  • 要检索特定日期的日志(将YYYY-MM-DD替换为所需日期),请运行:make production-logs | grep "YYYY-MM-DD"

如果您希望使用不同的域名而不是https://<XXXXXX>.stackhero-network.com,Stackhero for Docker集成了Traefik以简化域管理。Traefik为您处理HTTP路由和TLS加密(HTTPS)。

以下是自定义域名的一些示例:

  • 要通过您的容器my-app在端口5000上提供api.my-company.com并使用TLS加密,请更新docker/docker-compose.production.yml文件中的labels部分:

        labels:
          - "traefik.enable=true" # 启用Traefik以将流量路由到此容器
          - "traefik.http.routers.my-app.rule=Host(`api.my-company.com`)" # 定义主机
          - "traefik.http.routers.my-app.tls.certresolver=letsencrypt" # 使用letsencrypt获取TLS证书
          - "traefik.http.services.my-app.loadbalancer.server.port=5000" # 指定端口5000
    
  • 要通过您的容器my-app在端口5000上提供my-company.com并将所有请求从www.my-company.com重定向到my-company.com,请在同一文件中更新labels部分:

        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.my-app.rule=Host(`my-company.com`) || Host(`www.my-company.com`)" # 包含两个域名
          - "traefik.http.routers.my-app.tls.certresolver=letsencrypt"
          - "traefik.http.services.my-app.loadbalancer.server.port=5000" # 指定端口5000
    
          # 将www.my-company.com重定向到my-company.com:
          - "traefik.http.routers.my-app.middlewares=redirect-www"
          - "traefik.http.middlewares.redirect-www.redirectregex.regex=^https://www.my-company.com/(.*)"
          - "traefik.http.middlewares.redirect-www.redirectregex.replacement=https://my-company.com/$${1}"
          - "traefik.http.middlewares.redirect-www.redirectregex.permanent=true"
    

不要忘记为my-company.comwww.my-company.com配置DNS,以便每个都指向您的Docker服务的CNAME,地址为https://<XXXXXX>.stackhero-network.com