多环境管理最佳实践
本指南将帮助您构建完善的多环境管理体系,实现开发、测试、预发布和生产环境的有效隔离与协同。在企业级应用开发中,合理的环境管理不仅能保障生产系统的稳定性,还能显著提升团队的开发效率和交付质量。我们将从基础概念出发,逐步深入到实战案例和最佳实践,帮助您建立适合自己团队的环境管理策略。
理解多环境管理的价值
在开始配置多环境之前,让我们先理解为什么需要维护多个独立的运行环境。许多团队在早期只有一个环境,开发和生产混在一起。这种模式在项目初期可能还能运转,但随着团队规模扩大和业务复杂度提升,问题会逐渐暴露:开发调试可能影响线上服务,新功能无法充分验证就上线,配置错误直接影响用户,故障定位困难等等。
环境隔离的核心价值
多环境管理最重要的价值在于风险隔离。开发环境中的实验性代码、未完成的功能、不稳定的依赖都被限制在开发边界内,不会影响到为真实用户提供服务的生产环境。这种隔离让开发者可以自由地尝试新想法,不必担心破坏现有系统。
其次是配置差异化的需求。不同环境对资源的需求差异巨大。开发环境追求快速迭代,可以使用较低的配置节省成本;生产环境则需要高可用、高性能的配置来保障服务质量。如果所有环境使用相同的配置,要么开发成本过高,要么生产性能不足。
第三是安全管理的考虑。生产环境通常部署在 VPC 专有网络中,配置严格的访问控制和审计日志,使用独立的数据库和 API 密钥。开发环境则可以使用更宽松的配置,方便团队成员访问和调试。如果不区分环境,要么安全性不足,要么开发效率低下。
第四是成本优化的机会。开发和测试环境可以使用按需计费,在非工作时间自动停止或降低配置。生产环境则需要预留资源保障服务稳定。通过合理的环境划分,可以在保证服务质量的前提下显著降低总体成本。
最后是测试验证的需要。新功能在合并到生产之前,需要经过多层验证。单元测试在开发环境运行,集成测试在测试环境运行,压力测试和业务验证在预发布环境运行。每个环境承担特定的验证职责,共同保障代码质量。
常见的环境类型
典型的多环境体系包含四个核心环境,每个环境有明确的定位和特点。
**开发环境(Development)**是开发者的日常工作场所。这个环境追求快速迭代,配置较低以节省成本,通常由个人或小团队独占使用。开发环境允许频繁的代码变更,甚至可以包含未完成的功能。部署流程高度自动化,每次代码提交都会触发自动部署。监控和日志配置相对简单,主要用于调试而非长期分析。
**测试环境(Testing)**用于质量保证团队进行功能测试和集成测试。这个环境运行相对稳定的代码版本,配置略高于开发环境但仍然有所限制。测试环境通常在团队内共享,需要一定的版本管理和访问协调。部署频率低于开发环境但仍然较高,通常每天会有多次部署。测试环境会配置较完整的监控和日志,用于问题定位和性能分析。
**预发布环境(Staging)**是生产环境的镜像,配置与生产完全一致或高度相似。这个环境用于最终验证,确保代码在生产环境的配置下能够正常运行。预发布环境运行即将发布的版本,通常连接生产数据库的只读副本,使用与生产相同的网络配置和安全策略。只有经过预发布环境验证的代码才能进入生产,这是上线前的最后一道防线。
**生产环境(Production)**为真实用户提供服务,要求最高的稳定性和性能。这个环境使用最高规格的配置,部署在 VPC 专有网络中,配置完整的监控、告警、备份和灾难恢复机制。生产环境的变更需要经过严格的审批流程,部署频率相对较低,通常采用灰度发布等稳妥的策略。任何影响生产环境的操作都需要详细记录和审计。
选择配置管理策略
配置管理是多环境体系的基础,合理的配置策略能够平衡灵活性和可维护性。AgentRun 支持多种配置方式,理解它们的优劣可以帮助您做出适合的选择。
多配置文件方案
最直观的方式是为每个环境创建独立的配置文件。在项目根目录创建 s.dev.yaml、s.test.yaml、s.staging.yaml、s.prod.yaml 等文件,每个文件包含该环境的完整配置。
project/
├── s.yaml # 基础配置或默认配置
├── s.dev.yaml # 开发环境完整配置
├── s.test.yaml # 测试环境完整配置
├── s.staging.yaml # 预发布环境完整配置
├── s.prod.yaml # 生产环境完整配置
└── code/
└── ...
这种方式的最大优势是配置清晰明确。每个文件是自包含的,阅读某个环境的配置不需要在多个文件间跳转。环境之间完全隔离,修改一个环境的配置不会影响其他环境。在版本控制中,每个环境的变更历史也是独立的,便于追踪和回滚。
然而,多配置文件方案也有明显的缺点。配置重复较多,特别是那些所有环境都相同的部分,如代码路径、启动命令等,需要在每个文件中重复定义。当这些公共配置需要修改时,必须同步更新所有文件,容易遗漏或不一致。随着环境数量增加,维护成本呈线性增长。
变量注入方案
另一种方式是使用单一配置文件,通过变量注入来实现环境差异化。Serverless Devs 支持从环境变量读取配置值:
edition: 3.0.0
name: agentrun-app
access: default
vars:
region: ${env(REGION, 'cn-hangzhou')}
env: ${env(ENV, 'dev')}
cpu: ${env(CPU, '1.0')}
memory: ${env(MEMORY, '2048')}
resources:
my-agent:
component: agentrun
props:
region: ${vars.region}
agent:
name: agent-${vars.env}
cpu: ${vars.cpu}
memory: ${vars.memory}
使用时通过环境变量指定配置:
# 开发环境
ENV=dev CPU=1.0 MEMORY=2048 s deploy
# 生产环境
ENV=prod CPU=2.0 MEMORY=4096 s deploy
变量注入方案的优势是配置集中,只有一个文件需要维护。修改公共配置只需要在一处更改。配置参数化后,可以灵活组合,甚至可以通过 CI/CD 系统动态注入。
缺点是配置不够直观。阅读配置文件时,需要想象不同变量值下的实际配置。复杂的环境差异难以用简单的变量表达,容易导致配置文件充满条件判断。调试时需要确认环境变量的值,增加了复杂度。
推荐的混合模式
实践中最有效的方式是结合两种方案的优点,使用继承和组合来管理配置。首先创建一个基础配置文件定义所有环境的公共部分,然后每个环境的配置文件继承基础配置并覆盖特定部分。
# s.base.yaml - 公共配置(不直接部署)
edition: 3.0.0
vars:
region: cn-hangzhou
code_src: ./code
code_language: python3.12
code_command:
- python3
- app.py
# s.dev.yaml - 开发环境(继承基础配置)
edition: 3.0.0
name: dev-agentrun-app
access: default
extend:
- s.base.yaml
vars:
env: dev
resources:
my-agent:
component: agentrun
props:
region: ${vars.region}
agent:
name: agent-${vars.env}
code:
src: ${vars.code_src}
language: ${vars.code_language}
command: ${vars.code_command}
# 开发环境特定配置
cpu: 1.0
memory: 2048
environmentVariables:
ENVIRONMENT: ${vars.env}
LOG_LEVEL: debug
这种方式下,公共配置集中在 s.base.yaml,各环境配置文件只包含差异化部分。修改公共配置只需要修改基础文件,所有环境自动生效。同时每个环境的完整配置仍然清晰可见,继承关系明确。
这种混合模式适合大多数项目,既保持了配置的可维护性,又不失灵活性。接下来我们通过一个完整的实战案例来展示如何应用这个方案。
构建完整的多环境案例
让我们通过一个真实场景来演示多环境管理的完整实践。假设我们正在开发一个 AI 客服应用,需要为其搭建完整的环境体系。
项目结构设计
首先规划项目的目录结构。良好的组织能够让团队成员快速理解项目布局,降低维护成本:
ai-customer-service/
├── .github/
│ └── workflows/ # CI/CD 工作流
│ ├── deploy-dev.yml
│ ├── deploy-test.yml
│ ├── deploy-staging.yml
│ └── deploy-prod.yml
├── code/ # 应用代码
│ ├── app.py # 主入口
│ ├── requirements.txt # Python 依赖
│ ├── agent/ # Agent 逻辑
│ │ ├── __init__.py
│ │ ├── handler.py
│ │ └── tools.py
│ └── utils/ # 工具函数
│ └── logger.py
├── config/ # 环境配置模板
│ ├── dev.env.example
│ ├── test.env.example
│ ├── staging.env.example
│ └── prod.env.example
├── scripts/ # 部署和运维脚本
│ ├── deploy.sh
│ └── health-check.sh
├── s.dev.yaml # 开发环境配置
├── s.test.yaml # 测试环境配置
├── s.staging.yaml # 预发布环境配置
├── s.prod.yaml # 生产环境配置
├── .gitignore
├── .env.example # 环境变量模板
└── README.md
code 目录包含应用的核心代码,按模块组织。config 目录存放各环境的配置模板,这些模板不包含实际的密钥,只定义需要哪些配置项。scripts 目录包含自动化脚本,用于简化部署和运维操作。根目录的配置文件定义了各环境的 AgentRun 部署配置。
配置开发环境
开发环境的配置应该追求简洁和快速迭代。创建 s.dev.yaml:
edition: 3.0.0
name: dev-ai-customer-service
access: default
vars:
region: cn-hangzhou
env: dev
account_id: ${env(ACCOUNT_ID)}
resources:
ai-agent:
component: agentrun
props:
region: ${vars.region}
agent:
name: ai-customer-service-${vars.env}
description: "AI Customer Service - Development Environment"
code:
src: ./code
language: python3.12
command:
- python3
- app.py
# 开发环境使用低配置
cpu: 1.0
memory: 2048
diskSize: 512
timeout: 600
port: 9000
instanceConcurrency: 10
# 允许公网访问,方便调试
internetAccess: true
# 开发环境变量
environmentVariables:
ENVIRONMENT: ${vars.env}
LOG_LEVEL: debug
DEBUG: "true"
MODEL_NAME: ${env(DEV_MODEL_NAME, 'dev-model')}
SANDBOX_NAME: ${env(DEV_SANDBOX_NAME, 'dev-sandbox')}
API_KEY: ${env(DEV_API_KEY, 'dev-key')}
# RAM 角色
role: acs:ram::${vars.account_id}:role/agentRunRole
开发环境的关键特点是配置简单且成本低。CPU 和内存都是最小可用配置,磁盘空间也只分配 512MB。日志级别设为 debug,方便查看详细的执行过程。环境变量中的模型和沙箱名称都提供了默认值,即使不配置环境变量也能运行。
没有配置 VPC 网络和日志服务,这些在开发阶段不是必需的。Agent 直接暴露在公网上,开发者可以从任何地方访问,无需 VPN。这种宽松的配置加快了开发速度,但绝不应该用于生产环境。
配置测试环境
测试环境需要更稳定的配置和更完善的监控。创建 s.test.yaml:
edition: 3.0.0
name: test-ai-customer-service
access: default
vars:
region: cn-hangzhou
env: test
account_id: ${env(ACCOUNT_ID)}
resources:
ai-agent:
component: agentrun
props:
region: ${vars.region}
agent:
name: ai-customer-service-${vars.env}
description: "AI Customer Service - Testing Environment"
code:
src: ./code
language: python3.12
command:
- python3
- app.py
# 测试环境使用中等配置
cpu: 1.5
memory: 3072
diskSize: 512
timeout: 600
port: 9000
instanceConcurrency: 20
internetAccess: true
# 测试环境变量
environmentVariables:
ENVIRONMENT: ${vars.env}
LOG_LEVEL: info
DEBUG: "false"
MODEL_NAME: ${env(TEST_MODEL_NAME)}
SANDBOX_NAME: ${env(TEST_SANDBOX_NAME)}
API_KEY: ${env(TEST_API_KEY)}
role: acs:ram::${vars.account_id}:role/agentRunRole
# 测试环境配置日志服务
logConfig:
project: test-agentrun-logs
logstore: customer-service-logs
测试环境的配置比开发环境略高,CPU 增加到 1.5 核,内存增加到 3GB,并发数提升到 20。这些调整确保测试环境能够承受一定的压力,更接近真实场景。
日志级别调整为 info,只记录关键信息而不包括调试细节。配置了 SLS 日志服务,测试过程中产生的日志会被持久化存储,方便问题排查和分析。环境变量不再提供默认值,必须明确配置,这强制团队维护清晰的配置文档。
配置预发布环境
预发布环境应该尽可能接近生产环境,作为上线前的最后验证。创建 s.staging.yaml:
edition: 3.0.0
name: staging-ai-customer-service
access: production # 使用生产环境凭证
vars:
region: cn-hangzhou
env: staging
account_id: ${env(ACCOUNT_ID)}
resources:
ai-agent:
component: agentrun
props:
region: ${vars.region}
agent:
name: ai-customer-service-${vars.env}
description: "AI Customer Service - Staging Environment"
code:
src: ./code
language: python3.12
command:
- python3
- app.py
# 预发布环境与生产配置一致
cpu: 2.0
memory: 4096
diskSize: 1024
timeout: 900
port: 9000
instanceConcurrency: 50
# 使用生产 VPC 配置
vpcConfig:
vpcId: ${env(PROD_VPC_ID)}
vSwitchIds:
- ${env(PROD_VSWITCH_ID_1)}
- ${env(PROD_VSWITCH_ID_2)}
securityGroupId: ${env(PROD_SECURITY_GROUP_ID)}
internetAccess: true
# 预发布环境变量
environmentVariables:
ENVIRONMENT: ${vars.env}
LOG_LEVEL: info
DEBUG: "false"
MODEL_NAME: ${env(STAGING_MODEL_NAME)}
SANDBOX_NAME: ${env(STAGING_SANDBOX_NAME)}
API_KEY: ${env(STAGING_API_KEY)}
# 连接生产数据库的只读副本
DB_HOST: ${env(STAGING_DB_HOST)}
DB_PORT: ${env(STAGING_DB_PORT)}
role: acs:ram::${vars.account_id}:role/agentRunRole
# 使用生产日志项目
logConfig:
project: prod-agentrun-logs
logstore: customer-service-staging-logs
# 预发布端点
endpoints:
- name: staging
description: "Staging endpoint for pre-production testing"
预发布环境的配置与生产完全一致:相同的 CPU、内存、磁盘配置,相同的 VPC 网络,相同的并发设置。这确保了在预发布环境验证通过的代码,在生产环境也能正常运行。
预发布环境通常连接生产数据库的只读副本,可以用真实数据进行测试而不会影响生产数据。日志也写入生产日志项目,但使用独立的 logstore,便于与生产日志区分。
配置生产环境
生产环境需要最高的配置和最严格的安全策略。创建 s.prod.yaml:
edition: 3.0.0
name: prod-ai-customer-service
access: production
vars:
region: cn-hangzhou
env: prod
account_id: ${env(ACCOUNT_ID)}
resources:
ai-agent:
component: agentrun
props:
region: ${vars.region}
agent:
name: ai-customer-service-${vars.env}
description: "AI Customer Service - Production Environment"
code:
src: ./code
language: python3.12
command:
- python3
- app.py
# 生产环境高配置
cpu: 2.0
memory: 4096
diskSize: 1024
timeout: 900
port: 9000
instanceConcurrency: 50
# 生产 VPC 配置
vpcConfig:
vpcId: ${env(PROD_VPC_ID)}
vSwitchIds:
- ${env(PROD_VSWITCH_ID_1)}
- ${env(PROD_VSWITCH_ID_2)}
securityGroupId: ${env(PROD_SECURITY_GROUP_ID)}
internetAccess: true
# 生产环境变量
environmentVariables:
ENVIRONMENT: ${vars.env}
LOG_LEVEL: warning # 生产环境只记录警告和错误
DEBUG: "false"
MODEL_NAME: ${env(PROD_MODEL_NAME)}
SANDBOX_NAME: ${env(PROD_SANDBOX_NAME)}
API_KEY: ${env(PROD_API_KEY)}
# 生产数据库
DB_HOST: ${env(PROD_DB_HOST)}
DB_PORT: ${env(PROD_DB_PORT)}
# 监控配置
ENABLE_METRICS: "true"
METRICS_ENDPOINT: ${env(METRICS_ENDPOINT)}
role: acs:ram::${vars.account_id}:role/agentRunRole
# 生产日志配置
logConfig:
project: prod-agentrun-logs
logstore: customer-service-prod-logs
# 生产端点配置
endpoints:
- name: production
version: "1"
description: "Production endpoint - stable version"
- name: canary
version: "2"
description: "Canary endpoint for gradual rollout"
weight: 0.0 # 初始不分配流量
生产环境的日志级别设为 warning,只记录警告和错误,减少日志量并降低成本。启用了性能指标收集,通过 ENABLE_METRICS 和 METRICS_ENDPOINT 配置将指标上报到监控系统。
定义了两个端点:production 指向稳定版本,canary 用于灰度发布。初始时 canary 的权重为 0,不接收流量。发布新版本时,逐步提高 canary 的权重,实现平滑过渡。
管理环境变量和敏感信息
不同环境需要不同的配置参数,特别是数据库连接、API 密钥等敏感信息。合理管理这些配置是多环境体系的重要组成部分。
创建配置模板
在 config 目录为每个环境创建配置模板。这些模板定义了需要哪些配置项,但不包含实际值。以开发环境为例,创建 config/dev.env.example:
# 开发环境配置模板
# 阿里云配置
ACCOUNT_ID=123456789
# 模型和沙箱
DEV_MODEL_NAME=dev-qwen-model
DEV_SANDBOX_NAME=dev-sandbox
# API Keys
DEV_API_KEY=dev-api-key-xxxxx
# 数据库(开发环境使用本地或开发数据库)
DEV_DB_HOST=dev-db.example.com
DEV_DB_PORT=3306
生产环境的模板 config/prod.env.example 则包含更多配置项:
# 生产环境配置模板(实际值通过 CI/CD Secrets 注入)
# 阿里云配置
ACCOUNT_ID=123456789
# VPC 配置
PROD_VPC_ID=vpc-xxxxx
PROD_VSWITCH_ID_1=vsw-xxxxx
PROD_VSWITCH_ID_2=vsw-yyyyy
PROD_SECURITY_GROUP_ID=sg-xxxxx
# 模型和沙箱
PROD_MODEL_NAME=prod-qwen-max
PROD_SANDBOX_NAME=prod-sandbox
# API Keys(实际值留空,通过 Secrets 管理)
PROD_API_KEY=
# 数据库
PROD_DB_HOST=prod-db.example.com
PROD_DB_PORT=3306
# 监控
METRICS_ENDPOINT=https://metrics.example.com
团队成员可以复制这些模板为实际的配置文件(如 config/dev.env),填入自己的值。配置模板应该提交到版本控制,而实际配置文件则应该在 .gitignore 中排除。
本地开发的配置加载
在本地开发时,可以从配置文件加载环境变量。修改部署脚本,在执行部署命令前加载对应环境的配置:
# 加载环境变量
ENV_FILE="config/${ENV}.env"
if [ -f "$ENV_FILE" ]; then
echo "Loading environment variables from ${ENV_FILE}"
set -a
source "$ENV_FILE"
set +a
else
echo "Warning: Environment file ${ENV_FILE} not found"
fi
# 执行部署
s deploy -t "s.${ENV}.yaml"
这样开发者只需要维护本地的配置文件,不需要手动设置大量环境变量。
CI/CD 中的配置管理
在 CI/CD 流水线中,敏感信息应该通过平台的 Secrets 功能管理。以 GitHub Actions 为例,在仓库设置中添加 Secrets,然后在工作流中引用:
- name: Deploy to production
env:
ACCOUNT_ID: ${{ secrets.ALIYUN_ACCOUNT_ID_PROD }}
PROD_VPC_ID: ${{ secrets.PROD_VPC_ID }}
PROD_MODEL_NAME: ${{ secrets.PROD_MODEL_NAME }}
PROD_API_KEY: ${{ secrets.PROD_API_KEY }}
run: |
s deploy -t s.prod.yaml --assume-yes
这种方式确保敏感信息不会出现在代码仓库中,也不会暴露在日志中。不同环境使用不同的 Secrets,实现了配置隔离。
构建自动化部署脚本
手动输入部署命令容易出错,特别是需要记住不同环境的配置文件名和参数。编写统一的部署脚本可以简化操作并减少错误。
设计通用部署脚本
创建 scripts/deploy.sh,封装部署的完整流程:
#!/bin/bash
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 使用说明
usage() {
echo "Usage: $0 <environment> [options]"
echo ""
echo "Environments:"
echo " dev - Development environment"
echo " test - Testing environment"
echo " staging - Staging environment"
echo " prod - Production environment"
echo ""
echo "Options:"
echo " --skip-build Skip build step"
echo " --skip-test Skip tests"
exit 1
}
# 检查参数
if [ $# -eq 0 ]; then
usage
fi
ENV=$1
shift
SKIP_BUILD=false
SKIP_TEST=false
# 解析选项
while [[ $# -gt 0 ]]; do
case $1 in
--skip-build)
SKIP_BUILD=true
shift
;;
--skip-test)
SKIP_TEST=true
shift
;;
*)
echo "Unknown option: $1"
usage
;;
esac
done
# 验证环境
case $ENV in
dev|test|staging|prod)
CONFIG_FILE="s.${ENV}.yaml"
;;
*)
echo -e "${RED}Error: Invalid environment '$ENV'${NC}"
usage
;;
esac
# 检查配置文件
if [ ! -f "$CONFIG_FILE" ]; then
echo -e "${RED}Error: Configuration file '$CONFIG_FILE' not found${NC}"
exit 1
fi
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Deploying to ${YELLOW}${ENV}${GREEN} environment${NC}"
echo -e "${GREEN}========================================${NC}"
# 加载环境变量
ENV_FILE="config/${ENV}.env"
if [ -f "$ENV_FILE" ]; then
echo -e "${YELLOW}Loading environment variables from ${ENV_FILE}${NC}"
set -a
source "$ENV_FILE"
set +a
fi
# 运行测试
if [ "$SKIP_TEST" = false ]; then
echo -e "${YELLOW}Running tests...${NC}"
cd code
pip install -q -r requirements.txt
pip install -q flake8
if ! flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics; then
echo -e "${RED}Tests failed!${NC}"
exit 1
fi
cd ..
echo -e "${GREEN}Tests passed!${NC}"
fi
# 构建
if [ "$SKIP_BUILD" = false ]; then
echo -e "${YELLOW}Building application...${NC}"
s build -t "$CONFIG_FILE"
echo -e "${GREEN}Build completed!${NC}"
fi
# 生产环境需要确认
if [ "$ENV" = "prod" ]; then
echo -e "${RED}========================================${NC}"
echo -e "${RED}WARNING: Deploying to PRODUCTION${NC}"
echo -e "${RED}========================================${NC}"
read -p "Are you sure you want to continue? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo -e "${YELLOW}Deployment cancelled${NC}"
exit 0
fi
fi
# 部署
echo -e "${YELLOW}Deploying...${NC}"
s deploy -t "$CONFIG_FILE" --assume-yes
# 获取部署信息
echo -e "${GREEN}Deployment completed!${NC}"
echo -e "${YELLOW}Fetching deployment info...${NC}"
s info -t "$CONFIG_FILE"
# 健康检查
echo -e "${YELLOW}Running health check...${NC}"
sleep 10
ENDPOINT_URL=$(s info -t "$CONFIG_FILE" 2>/dev/null | grep -oP 'https://[^\s]+' | head -1)
if [ -n "$ENDPOINT_URL" ]; then
echo -e "${YELLOW}Testing endpoint: ${ENDPOINT_URL}${NC}"
if curl -f "${ENDPOINT_URL}/openai/v1/chat/completions" \
-X POST \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "health check"}], "stream": false}' \
> /dev/null 2>&1; then
echo -e "${GREEN}✓ Health check passed!${NC}"
else
echo -e "${YELLOW}⚠ Health check failed, but deployment succeeded${NC}"
fi
fi
# 生产环境发布版本
if [ "$ENV" = "prod" ]; then
echo -e "${YELLOW}Publishing production version...${NC}"
VERSION_DESC="Production release $(date '+%Y-%m-%d %H:%M:%S')"
s version publish --description "$VERSION_DESC" -t "$CONFIG_FILE"
echo -e "${GREEN}Version published!${NC}"
fi
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Deployment to ${YELLOW}${ENV}${GREEN} completed!${NC}"
echo -e "${GREEN}========================================${NC}"
这个脚本实现了完整的部署流程:参数验证、环境配置加载、代码测试、应用构建、部署确认、健康检查和版本发布。使用时只需要指定环境名称:
# 部署到开发环境
./scripts/deploy.sh dev
# 部署到生产环境
./scripts/deploy.sh prod
# 跳过测试快速部署
./scripts/deploy.sh dev --skip-test
脚本包含了安全保护措施。部署到生产环境时会要求确认,防止误操作。使用颜色输出区分不同类型的信息,提高可读性。自动执行健康检查验证部署结果。
集成 CI/CD 自动化
手动部署适合本地开发,但在团队协作中应该使用自动化流水线。将多环境管理集成到 CI/CD 中,可以确保部署的一致性和可追溯性。
开发环境的自动部署
创建 .github/workflows/deploy-dev.yml,配置开发环境的自动部署:
name: Deploy to Development
on:
push:
branches:
- develop
env:
NODE_VERSION: '18'
PYTHON_VERSION: '3.12'
jobs:
deploy-dev:
runs-on: ubuntu-latest
environment:
name: development
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: |
npm install -g @serverless-devs/s
cd code
pip install -r requirements.txt
- name: Configure credentials
run: |
s config add \
--AccountID ${{ secrets.ALIYUN_ACCOUNT_ID }} \
--AccessKeyID ${{ secrets.ALIYUN_ACCESS_KEY_ID }} \
--AccessKeySecret ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }} \
--alias default
- name: Deploy using script
env:
ACCOUNT_ID: ${{ secrets.ALIYUN_ACCOUNT_ID }}
DEV_MODEL_NAME: ${{ secrets.DEV_MODEL_NAME }}
DEV_SANDBOX_NAME: ${{ secrets.DEV_SANDBOX_NAME }}
DEV_API_KEY: ${{ secrets.DEV_API_KEY }}
run: |
chmod +x scripts/deploy.sh
./scripts/deploy.sh dev
当代码推送到 develop 分支时,这个工作流自动触发,将最新代码部署到开发环境。环境变量从 GitHub Secrets 读取,确保敏感信息不会暴露。部署过程完全自动化,不需要人工干预。
生产环境的分阶段部署
生产环境的部署需要更谨慎的策略。创建 .github/workflows/deploy-prod.yml,实现先部署到预发布环境验证,然后部署到生产:
name: Deploy to Production
on:
push:
branches:
- main
workflow_dispatch:
env:
NODE_VERSION: '18'
PYTHON_VERSION: '3.12'
jobs:
# 先部署到 Staging 验证
deploy-staging:
runs-on: ubuntu-latest
environment:
name: staging
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup tools
run: |
npm install -g @serverless-devs/s
- name: Configure credentials
run: |
s config add \
--AccountID ${{ secrets.ALIYUN_ACCOUNT_ID_PROD }} \
--AccessKeyID ${{ secrets.ALIYUN_ACCESS_KEY_ID_PROD }} \
--AccessKeySecret ${{ secrets.ALIYUN_ACCESS_KEY_SECRET_PROD }} \
--alias production
- name: Deploy to staging
env:
ACCOUNT_ID: ${{ secrets.ALIYUN_ACCOUNT_ID_PROD }}
PROD_VPC_ID: ${{ secrets.PROD_VPC_ID }}
PROD_VSWITCH_ID_1: ${{ secrets.PROD_VSWITCH_ID_1 }}
PROD_VSWITCH_ID_2: ${{ secrets.PROD_VSWITCH_ID_2 }}
PROD_SECURITY_GROUP_ID: ${{ secrets.PROD_SECURITY_GROUP_ID }}
STAGING_MODEL_NAME: ${{ secrets.STAGING_MODEL_NAME }}
STAGING_SANDBOX_NAME: ${{ secrets.STAGING_SANDBOX_NAME }}
STAGING_API_KEY: ${{ secrets.STAGING_API_KEY }}
run: |
chmod +x scripts/deploy.sh
./scripts/deploy.sh staging --skip-test
# 部署到生产环境(需要手动批准)
deploy-prod:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup tools
run: npm install -g @serverless-devs/s
- name: Configure credentials
run: |
s config add \
--AccountID ${{ secrets.ALIYUN_ACCOUNT_ID_PROD }} \
--AccessKeyID ${{ secrets.ALIYUN_ACCESS_KEY_ID_PROD }} \
--AccessKeySecret ${{ secrets.ALIYUN_ACCESS_KEY_SECRET_PROD }} \
--alias production
- name: Deploy to production
env:
ACCOUNT_ID: ${{ secrets.ALIYUN_ACCOUNT_ID_PROD }}
PROD_VPC_ID: ${{ secrets.PROD_VPC_ID }}
PROD_VSWITCH_ID_1: ${{ secrets.PROD_VSWITCH_ID_1 }}
PROD_VSWITCH_ID_2: ${{ secrets.PROD_VSWITCH_ID_2 }}
PROD_SECURITY_GROUP_ID: ${{ secrets.PROD_SECURITY_GROUP_ID }}
PROD_MODEL_NAME: ${{ secrets.PROD_MODEL_NAME }}
PROD_SANDBOX_NAME: ${{ secrets.PROD_SANDBOX_NAME }}
PROD_API_KEY: ${{ secrets.PROD_API_KEY }}
METRICS_ENDPOINT: ${{ secrets.METRICS_ENDPOINT }}
run: |
chmod +x scripts/deploy.sh
./scripts/deploy.sh prod --skip-test
这个工作流包含两个任务:deploy-staging 先将代码部署到预发布环境,deploy-prod 在预发布成功后部署到生产。deploy-prod 任务配置了 environment: production,在 GitHub 仓库设置中可以为这个环境要求审批,实现人工把关。
这种分阶段部署策略提供了多层保护。代码先在与生产配置相同的预发布环境验证,确认无问题后才进入生产。即使出现问题,影响范围也被限制在预发布环境。
环境管理最佳实践
在理解了多环境配置的基础上,让我们深入一些经过实践验证的最佳实践,帮助您建立更高效的环境管理体系。
配置分层与复用
避免在每个环境配置中重复相同的内容。将配置分为三个层次:
基础层包含所有环境共享的配置,如代码路径、启动命令、基础端口等。这些配置很少变化,定义在基础配置文件中。
环境层包含环境特定但相对固定的配置,如资源规格、网络配置、日志配置等。这些配置在环境创建时确定,之后很少修改。
运行时层包含运行时动态注入的配置,如 API 密钥、数据库连接等。这些配置可能需要定期更新,通过环境变量或 Secrets 管理。
这种分层策略让配置既不会过度分散,也不会混成一团。修改基础配置时,所有环境自动生效。修改某个环境的特定配置时,不会影响其他环境。
命名规范和标识
建立清晰的命名规范,让团队成员一眼就能识别资源属于哪个环境。推荐的命名格式是 <项目名>-<环境>-<组件>,例如:
- Agent Runtime:
ai-customer-service-dev,ai-customer-service-prod - 日志项目:
dev-logs,prod-logs - 配置文件:
s.dev.yaml,s.prod.yaml
一致的命名规范避免了混淆,特别是在同时操作多个环境时。在资源的描述字段中也明确标注环境名称,进一步降低误操作的风险。
环境差异化配置策略
不同环境的配置差异应该反映其不同的定位。开发环境追求快速迭代,使用最小可用配置,启用详细日志,不配置 VPC 和监控。测试环境追求稳定性,使用中等配置,配置基本的日志和监控。预发布环境追求一致性,配置与生产完全相同,用于最终验证。生产环境追求可靠性,使用高配置,配置完整的监控、告警和备份。
资源配置的具体建议:
| 配置项 | 开发 | 测试 | 预发布 | 生产 |
|---|---|---|---|---|
| CPU | 1.0 核 | 1.5 核 | 2.0 核 | 2.0 核 |
| 内存 | 2048 MB | 3072 MB | 4096 MB | 4096 MB |
| 并发数 | 10 | 20 | 50 | 50 |
| VPC | 否 | 否 | 是 | 是 |
| 日志 | 否/简单 | 基础 | 完整 | 完整 |
| 日志级别 | debug | info | info | warning |
这个配置梯度在成本和功能之间取得了平衡。开发和测试环境的低配置节省了大量成本,而预发布和生产环境的高配置保证了服务质量。
部署策略差异化
不同环境的部署策略也应该有所区分。开发环境应该实现完全自动化,每次代码提交都触发部署,无需任何审批。这让开发者能够快速验证想法,缩短反馈周期。
测试环境可以采用定时部署或特定分支触发,部署前需要通过代码审查,但不需要人工审批部署过程。这在保证代码质量的同时,仍然保持了较高的部署频率。
预发布环境的部署通常由技术负责人触发,作为生产部署的前置步骤。只有在预发布环境验证通过后,才会启动生产部署流程。
生产环境的部署需要最严格的控制。除了技术负责人的审批,还可能需要产品负责人或运维负责人的批准。采用金丝雀发布或蓝绿部署策略,确保问题影响范围可控。部署窗口可以限制在业务低峰时段,减少对用户的影响。
数据隔离和安全
数据隔离是多环境管理的关键安全措施。每个环境应该使用独立的数据存储,避免开发和测试操作影响生产数据。
开发环境使用开发数据库,可以包含模拟数据或脱敏的真实数据。测试环境同样使用独立的测试数据库,用于功能测试和性能测试。预发布环境可以连接生产数据库的只读副本,用真实数据验证但不会修改生产数据。生产环境使用生产数据库,配置严格的访问控制和备份策略。
模型和沙箱资源也应该环境隔离。开发环境可以使用免费或低成本的模型,测试环境使用与生产相同类型但规格较低的模型,生产环境使用最高性能的模型。这种分级使用在保证开发测试体验的同时,优化了成本结构。
成本优化策略
多环境体系如果管理不当,可能导致成本失控。通过合理的配置策略,可以在保证功能的前提下显著降低成本。
首先是资源配置的梯度分配。开发和测试环境使用低配置,生产环境使用高配置。这种差异化配置让大部分成本集中在真正产生价值的生产环境。
其次是按需使用非生产环境。开发环境可以配置较短的空闲超时,不活跃时自动释放资源。测试环境可以在非工作时间关闭或降低配置,工作时间再恢复。这些措施在不影响使用的前提下,减少了资源浪费。
第三是共享非关键资源。多个开发环境可以共享同一个 VPC 或日志项目,降低网络和存储成本。当然,生产环境的资源必须独享,不能为了节省成本而牺牲可靠性。
第四是定期清理不再使用的环境。功能开发完成后,对应的特性分支环境应该及时删除。过期的测试环境也应该清理,避免资源闲置。
监控和告警的分级
不同环境的监控需求差异很大,应该采用分级策略。开发环境不需要复杂的监控,基本的日志记录就足够。异常和错误直接在控制台输出,开发者可以实时查看。
测试环境需要基础的监控和日志服务,用于问题排查和性能分析。配置简单的告警规则,当出现持续错误或性能严重下降时通知相关人员。日志保留 7 天,平衡了可追溯性和存储成本。
生产环境需要完整的监控体系,包括性能指标、业务指标、错误率、响应时间等。配置多级告警规则,P0 级问题立即通知,P1 级问题 30 分钟内响应,P2 级问题工作时间处理。日志保留 30 天或更长,满足合规要求和深度分析需求。
预发布环境的监控配置与生产相同,用于验证监控策略的有效性。在预发布环境测试告警规则,确保生产环境的告警准确可靠。
环境切换和状态管理
在日常工作中,开发者经常需要在不同环境间切换,查看状态,执行操作。建立便捷的环境切换机制可以提高工作效率。
便捷的环境切换
推荐使用部署脚本统一环境切换入口:
# 部署到不同环境
./scripts/deploy.sh dev
./scripts/deploy.sh test
./scripts/deploy.sh staging
./scripts/deploy.sh prod
# 查看不同环境状态
./scripts/status.sh dev
./scripts/status.sh prod
也可以创建快捷命令脚本 scripts/env.sh:
#!/bin/bash
ENV=${1:-dev}
case $2 in
deploy)
./scripts/deploy.sh $ENV
;;
info)
s info -t s.$ENV.yaml
;;
logs)
s logs -t s.$ENV.yaml --tail
;;
*)
echo "Usage: $0 <env> [deploy|info|logs]"
echo "Example: $0 prod info"
;;
esac
使用时更加简洁:
# 查看生产环境信息
./scripts/env.sh prod info
# 查看开发环境日志
./scripts/env.sh dev logs
批量查看环境状态
创建脚本查看所有环境的状态:
#!/bin/bash
# scripts/status-all.sh
echo "========================================="
echo "AgentRun Environments Status"
echo "========================================="
echo ""
for env in dev test staging prod; do
echo "=== Environment: $env ==="
if s info -t s.$env.yaml > /dev/null 2>&1; then
STATUS=$(s info -t s.$env.yaml 2>/dev/null | grep "status:" | awk '{print $2}')
ENDPOINT=$(s info -t s.$env.yaml 2>/dev/null | grep -oP 'https://[^\s]+' | head -1)
echo "Status: $STATUS"
echo "Endpoint: $ENDPOINT"
else
echo "Status: Not deployed"
fi
echo ""
done
这个脚本遍历所有环境,显示其状态和访问地址,让您对整体情况一目了然。
故障处理和环境恢复
即使有完善的管理机制,环境仍然可能出现问题。建立清晰的故障处理流程,可以快速恢复服务。
开发环境的快速修复
开发环境出现问题时,最简单的方式是删除后重建:
# 删除有问题的环境
s remove -t s.dev.yaml -y
# 重新部署
./scripts/deploy.sh dev
这种"推倒重来"的方式在开发环境是可接受的,因为开发环境不承载重要数据,重建成本很低。
生产环境的谨慎处理
生产环境出现问题时需要更谨慎。首先通过日志和监控定位问题:
# 查看最近的错误日志
s logs --type fail --start-time "10 minutes ago" -t s.prod.yaml
# 查看实例状态
s instance list -t s.prod.yaml
如果是新版本引入的问题,通过端点切换快速回滚:
# 将生产流量切回稳定版本
s endpoint publish --endpoint-name production --target-version 1 -t s.prod.yaml
# 停止问题版本的流量
s endpoint publish --endpoint-name canary --weight 0.0 -t s.prod.yaml
如果是配置问题,修改配置后重新部署:
# 修复配置
vim s.prod.yaml
# 重新部署
./scripts/deploy.sh prod
关键是保持冷静,先停止问题的扩散(回滚或降级),再定位根本原因,最后彻底修复。整个过程应该有详细记录,用于后续的复盘和改进。
总结与展望
多环境管理是企业级应用开发的基础设施,它通过环境隔离保障了生产系统的稳定性,通过差异化配置优化了成本结构,通过分阶段验证提升了交付质量。
实施多环境管理的核心要点包括:首先是清晰的环境定位,每个环境有明确的用途和责任人;其次是配置的分层复用,避免重复和不一致;第三是部署的自动化,减少人为错误;第四是监控的分级,把资源用在刀刃上;第五是安全的优先,特别是生产环境的保护。
多环境管理不是一次性的项目,而是持续演进的过程。随着团队规模扩大、业务复杂度提升、技术栈变化,环境管理策略也需要相应调整。建议定期回顾和优化,收集团队反馈,持续改进。
从简单开始,先建立开发和生产两个环境,在实践中逐步完善。不要试图一开始就建立完美的体系,而是根据实际需求逐步演进。记住,环境管理的目标是服务于业务开发,而不是为了管理而管理。