最近我加入了一个新的开发团队,项目中要求将使用了 React + NestJS + MongoDB 技术栈的应用部署到预发布环境(以下简称为 Staging 环境)。

同时我们的测试团队成员(兼职甲方、产品经理、老板…… 开玩笑)并非技术背景出身,因此一个稳定且易于访问的测试环境至关重要。

这篇文章只是记录了我当时是如何部署我的项目的,并不会给出全能的方案。实际的操作还需要根据你们自己的项目来进行修改。

例如我的包管理器都是使用的 yarn。如果你偏向于使用 npm,那就要把文章中和 yarn 相关的命令改成用 npm 的。

这篇文档也有可能因为时间而过时,所以请仔细查阅该文章的发布时期。

前言

什么是 Staging 环境?

在软件开发中,Staging 环境是模拟生产环境的一个重要环节。它通常是生产环境的一个精确副本,用于在将新功能或修复部署到最终用户可见的生产环境之前进行全面的测试。

Staging 环境的主要目的很简单:在真实或接近真实的条件下测试应用、尽早发现潜在的 Bug、性能问题和配置错误。

对于我们的项目而言,Staging 环境将是我向非技术背景的测试人员展示最新进展、收集反馈的关键桥梁。一个易于访问且稳定的 Staging 环境能够让他们更专注于应用的实际功能和用户体验,而无需关注底层的技术细节(主要他们也不懂啦)。

我的想法

为了更好地将我们的 React + NestJS + MongoDB 应用推送到这个测试环境,并确保开发流程的顺畅,我初步制定了一套以 Cloudflare Pages 和 AWS Elastic Beanstalk 为核心的部署方案:

  • 前端 React 应用将部署在 Cloudflare Pages 上,利用其快速的全球 CDN 和便捷的部署流程
  • 后端 NestJS 应用和 MongoDB 数据库,我计划使用 AWS Elastic Beanstalk 进行管理和部署,MongoDB 就用 MongoDB Atlas
  • 项目还有用到对象存储,开发环境里我使用的是 MinIO,不过在生产环境里我计划换成 AWS S3,因此 Staging 环境中也是如此

在代码管理方面,我们团队选择了 Atlassian 的工具。我计划采用一套清晰且严格的 Git 分支策略,结合 Bitbucket Pipelines 的自动化部署能力,力求在每次功能开发完成后,能够快速、可靠地将变更推送到 Staging 环境。这不仅能提高我们的开发效率,也能让测试团队及时体验到最新的功能。

接下来,我将详细记录我在搭建和使用这个 Staging 环境过程中遇到的挑战、采取的解决方案以及一些经验总结,希望能为自己和有类似需求的开发者提供一些参考。

客户端部署

Cloudflare Pages 非常适合部署静态站点和单页应用(我也常用 Netlify)。

创建 Cloudflare Pages 应用

  1. 进入 Cloudflare 控制台,在左侧菜单栏中找到 Compute (Workers) 选项:

    alt text

  2. 点击 Create 来创建 Pages 应用:

    alt text

  3. 选择 Pages 标签后,这里可以选择 导入已存在的 Git 仓库 或者 直接上传构建后的客户端代码

    因为决定使用 BitBucket Pipeline 和 Wrangler CLI,我就选择了后者:

    alt text

    什么是 BitBucket Pipelines?

    BitBucket Pipelines 是 Atlassian 提供的一项持续集成和持续交付(也就是 CI / CD)服务,直接集成在 BitBucket 代码托管平台中。

    它允许你使用 YAML 文件定义自动化工作流程,例如代码构建、测试、部署等。

    每当你向仓库推送代码、创建 Pull Request 或满足其他触发条件时,Pipelines 就会按照你的配置自动执行定义好的步骤。

  4. 填写项目名称,之后会用到。

    创建项目后会要求上传一个项目的静态资源文件,最快的方案是下载 Cloudflare 提供的 Demo,然后直接上传这个:

    alt text

  5. 为了让 BitBucket Pipelines 能够安全地与 Cloudflare API 交互,我们需要在 BitBucket 客户端仓库中添加两个敏感的环境变量:

    • CLOUDFLARE_API_TOKEN:用于认证 Cloudflare API 请求的令牌
    • CLOUDFLARE_ACCOUNT_ID:Cloudflare 账号 ID

    首先是令牌。点击右上角的小人图标、点击 Profile、点击左侧菜单栏的 API Tokens 选项、点击页面中的 Create Token 按钮:

    alt text

  6. 创建令牌的页面中,点击 Create Custom Token 一栏的 Get started 按钮:

    alt text

  7. 填写令牌名称;

    在权限中选择 Cloudflare PagesEdit

    在账号资源中选择你自己的邮箱:

    alt text

    创建完毕后记下该令牌(不要泄露给他人,务必保管好)。

  8. 账号 ID 更好找。随便点击 Cloudflare 图标或者什么的返回到控制台,抬头看一下 URL 就能看到:

    alt text

Cloudflare Pages 的环境 URL

Cloudflare Pages 会根据你推送代码的分支自动创建不同的环境 URL:

  • 生产环境 URL:当你推送代码到你的生产分支时(Cloudflare 默认将 main 分支视为生产分支,但你可以在 Pages 应用的设置中更改),Cloudflare 会将该分支的最新部署发布到你的 自定义域名(如果你已经设置了)以及一个 Cloudflare 提供的 .pages.dev 子域名。这个 URL 通常是你的最终用户访问的地址
  • 预览环境 URL:对于所有其他的非生产分支(例如 staging 分支),Cloudflare Pages 会自动为每次推送创建一个唯一的预览 URL。这些 URL 的格式通常是 [commit-hash]-[你的Pages应用名称].pages.dev

alt text

.env 变量的迁移

与传统的服务器端应用不同,前端应用通常在构建时就需要确定环境变量的值。Cloudflare Pages 提供了几种管理环境变量的方式:

  1. Cloudflare Pages 控制台:你可以在你的 Cloudflare Pages 应用的设置中,找到 Environment variables 选项,在这里你可以添加、编辑和删除环境变量。你在控制台中设置的环境变量会在你的应用构建时被注入
  2. _headers 文件或 wrangler.toml:对于一些特定的配置,例如 HTTP headers,你可以通过在你的构建输出目录中添加 _headers 文件或在项目根目录下配置 wrangler.toml 文件来管理。但这通常不用于存储敏感的环境变量

对于我的 Staging 环境,我得在 Cloudflare Pages 控制台中为我的应用配置相应的环境变量(比方说不同环境的服务端 API)。我们可以在设置里随意切换生产或者预览环境,然后添加变量或者密钥:

alt text

创建 BitBucket Pipelines

  1. 来到客户端的 BitBucket 仓库,现在我们要添加这两个环境变量了。

    点击左侧菜单栏中的 Repository settings

    alt text

  2. 接着点击 Repository variables

    alt text

  3. 在环境变量页面中,填写以下内容:

    • CLOUDFLARE_API_TOKEN
    • CLOUDFLARE_ACCOUNT_ID

    两个值在被添加时都要确保勾选上 Secured

    alt text

    将这些敏感信息存储为 BitBucket 的仓库变量而不是直接写在 Pipeline 配置文件中,可以提高安全性。

  4. 在仓库中创建一个 bitbucket-pipelines.yml 文件:

    bitbucket-pipelines.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    pipelines:
    branches:
    staging:
    - step:
    name: Build and Deploy Frontend to Staging
    image: node:20.18.3
    script:
    # - npm install -g yarn
    - yarn install
    - yarn build
    - yarn global add wrangler
    - export CLOUDFLARE_API_TOKEN=$CLOUDFLARE_API_TOKEN
    - export CLOUDFLARE_ACCOUNT_ID=$CLOUDFLARE_ACCOUNT_ID
    - wrangler pages publish dist --project-name [cloudflare应用名称] --branch staging
    caches:
    - node
    • pipelines 是定义了所有自动化流程的顶层键
    • branches 指定了哪些分支会触发特定的 Pipeline 流程
    • staging 表示只有当代码推送到 staging 分支时,才会执行以下定义的步骤
    • - step 定义了一个独立的构建和部署步骤。一个 Pipeline 可以包含多个 step,它们会按照顺序执行
      • name 为该步骤指定了一个易于理解的名称,方便在 Bitbucket Pipelines 的界面上查看执行状态
      • image 指定了运行该步骤所使用的 Docker 镜像。这里我们选择了 node:20.18.3,因为我的本地 Node 版本就是这个,你也可以换成你自己的
      • script 定义了在该步骤中要执行的 Shell 命令:
        • # - npm install -g yarn 原本的意图是全局安装 yarn 包管理器,这是因为 node:20.18.3 的镜像里已经预先安装了 yarn、还会导致错误。如果你在后续的 Pipeline 执行中遇到了 没找到 yarn 的错误,就取消注释这一行吧
        • yarn install 安装项目的所有依赖包
        • yarn build 执行 React 应用的构建脚本,这会生成用于部署的静态资源文件,默认情况下这些文件会输出到项目根目录下的 dist 或者 build 文件夹中
        • yarn global add wrangler 全局安装 Cloudflare 的命令行工具 wranglerwrangler 用于与 Cloudflare API 进行交互,例如部署 Pages 应用
        • export CLOUDFLARE_API_TOKEN=$CLOUDFLARE_API_TOKEN 将 Bitbucket 仓库变量 CLOUDFLARE_API_TOKEN 导出为 Pipeline 运行环境中的环境变量。$ 符号用于引用仓库变量
        • export CLOUDFLARE_ACCOUNT_ID=$CLOUDFLARE_ACCOUNT_ID 同样地将 Bitbucket 仓库变量 CLOUDFLARE_ACCOUNT_ID 导出为环境变量
        • wrangler pages publish dist --project-name [cloudflare应用名称] --branch staging 是执行部署的关键命令。它使用 wrangler pages publish 命令将 dist 文件夹中的内容上传并部署到你的 Cloudflare Pages 应用。--project-name 后面需要替换成你在 Cloudflare 中创建的 Pages 应用的实际名称。--branch staging 告诉 Cloudflare 这是针对 staging 分支的部署
      • caches 定义了需要缓存的目录,以便在后续的 Pipeline 执行中加快依赖安装速度。这里我们缓存了 node_modules 目录

    现在每当我们向 staging 分支推送新的 commit 时,Bitbucket Pipelines 会自动构建我的前端应用,并使用 wrangler 将构建产物部署到 Cloudflare Pages。Cloudflare 会为这次特定的提交创建一个新的预览部署,并生成一个新的、唯一的预览 URL。这意味着我的测试人员可以同时访问到不同 commit 对应的不同预览版本,这在进行特定功能的测试或对比不同版本时非常有用。

服务端部署

AWS Elastic Beanstalk (EB)正是为此而生的 PaaS 服务,它可以帮助我们轻松部署、管理和扩展 Web 应用程序和服务。