环境部署策略(Environment Deployment Strategy)是一个参考模式(reference pattern),强调学习其思路并适配自身场景,而不是照搬。它要解决的问题是:需要一套安全的部署实践,既能防止意外把代码部署到生产环境,又能支持快速的开发迭代。其解决方案是带部署限制的三层环境策略。
三层环境
- 本地(local):运行在开发者机器上;使用 dev 环境的云资源;不能部署(没有云资源);迭代快,无需等待部署。
- 开发(dev):部署到云端;镜像生产架构;可通过本地脚本或 GitHub Actions(合并到 dev 分支时)部署;用于测试和验证。
- 生产(prod):部署到云端;面向客户的线上环境;只能通过 GitHub Actions(合并到 main 分支时)部署;绝不从本地机器部署。
为什么采用这个模式
好处:安全性——生产环境免受本地误部署影响;速度——本地开发使用云端 dev 资源,无需本地基础设施;一致性——dev 镜像 prod,可在进入生产前发现问题;审计——所有 prod 部署都记录在 GitHub Actions 日志中;回滚——Git 历史便于回滚。
它可以防止:从开发者机器意外部署到生产;未测试代码进入生产;环境之间的配置漂移;“在我机器上能跑”的问题。
实现
环境配置示例:
# .env (local - not committed)
ENVIRONMENT=local
AWS_REGION=eu-central-1
# Uses dev resources
API_ENDPOINT=https://api-dev.example.com
# .env.dev (committed template)
ENVIRONMENT=dev
AWS_REGION=eu-central-1
API_ENDPOINT=https://api-dev.example.com
# .env.prod (committed template, secrets from SSM)
ENVIRONMENT=prod
AWS_REGION=eu-central-1
API_ENDPOINT=https://api.example.com
部署脚本示例:
// package.json
{
"scripts": {
"deploy:dev": "cdk deploy --all --context environment=dev",
"deploy:prod": "echo 'ERROR: Production can only be deployed via GitHub Actions' && exit 1"
}
}
GitHub Actions 工作流示例:
# .github/workflows/deploy.yml
name: Deploy
on:
pull_request:
types: [closed]
branches: [dev, main]
jobs:
deploy-dev:
if: github.base_ref == 'dev' && github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Dev
run: npm run deploy:dev
deploy-prod:
if: github.base_ref == 'main' && github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Production
run: cdk deploy --all --context environment=prod
部署流程
开发周期:开发者在本地工作(使用 dev 资源);提交到功能分支;向 dev 分支发起 PR;PR 合并后由 GitHub Actions 部署到 dev;在 dev 环境测试;从 dev 向 main 发起 PR;PR 合并后由 GitHub Actions 部署到 prod。
本地开发:
# Developer runs frontend locally
npm run dev
# Frontend connects to dev API
# No infrastructure deployment needed
# Fast iteration
Dev 部署(两种方式):
# Option 1: Local deployment (for quick testing)
npm run deploy:dev
# Option 2: GitHub Actions (on PR merge to dev)
# Automatic, tracked, consistent
Prod 部署(仅一种方式):只能通过 GitHub Actions(PR 合并到 main 时);尝试本地部署会返回错误信息。
CORS:本地共享 dev 后端
由于本地开发会访问已部署的 dev API,dev 环境的 CORS 必须同时允许两个来源:
# .env.dev (used by dev Lambda)
CORS_ALLOWED_ORIGINS=http://localhost:3010,https://dev.project.example.com
# .env.prod (only the production domain)
CORS_ALLOWED_ORIGINS=https://project.example.com
规则:为任何 dev 后端(API Gateway、Lambda)配置 CORS 时,始终在已部署的 dev 前端域名之外同时包含 http://localhost:<port>。否则本地开发会被 CORS 拦截,而已部署的 dev 前端仍可正常工作。
资源隔离
每个环境使用独立资源,所有资源名都包含环境标识:
// All resources include environment identifier
const bucket = new s3.Bucket(this, 'Bucket', {
bucketName: `${PROJECT_ID}-data-${environment}` // dev or prod
});
const table = new dynamodb.Table(this, 'Table', {
tableName: `${PROJECT_ID}-users-${environment}` // dev or prod
});
原因:防止 dev 与 prod 共享资源,避免数据损坏和冲突。
AWS CodePipeline 集成
替代方案:用 AWS CodePipeline 取代 GitHub Actions,可按环境拆分流水线:
// Separate pipelines per environment
const devPipeline = new codepipeline.Pipeline(this, 'DevPipeline', {
pipelineName: `${PROJECT_ID}-pipeline-dev`
});
const prodPipeline = new codepipeline.Pipeline(this, 'ProdPipeline', {
pipelineName: `${PROJECT_ID}-pipeline-prod`
});
GitHub Actions 触发示例:
- name: Trigger Dev Pipeline
run: aws codepipeline start-pipeline-execution --name ${PROJECT_ID}-pipeline-dev
- name: Trigger Prod Pipeline
run: aws codepipeline start-pipeline-execution --name ${PROJECT_ID}-pipeline-prod
好处:构建日志位于 AWS CloudWatch;使用基于 IAM 的权限(无需 GitHub secrets);与 AWS 服务集成。
变体
双环境(较简单的项目):dev 用于开发与测试,prod 仅用于生产。
四环境(企业级):local 开发者机器、dev 开发、staging 预生产测试、prod 生产。
相关模式
资源命名——如何按环境命名资源;环境校验——尽早校验环境配置;静态前端托管——部署流水线示例。
渐进改进
如果开发者纠正了本技能本应防止的行为,建议对本技能提出具体修订,以防未来出现同样的纠正。