关于 resource-naming
这是一份面向 AWS 基础设施团队的资源命名参考技能,涵盖跨项目和环境的命名约定。它规定项目、资源名称、环境的格式,并提供各类服务的示例与说明。
主要功能
- 01项目-资源-环境命名格式
- 02环境后缀使用说明
- 03多种 AWS 资源命名模式
- 04S3 名称冲突时添加后缀
- 05CDK 实现示例
适用场景
- 01为开发和生产环境命名资源
- 02减少不同项目间的命名冲突
- 03在 CDK 中统一资源名称
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ loxosceles-dev/ dev-skills --skill resource-naming安装后在 Claude Code 中输入/resource-naming确认已加载。
详细介绍
AWS 资源命名约定
这是一个参考模式。 学习其方法,并根据你的上下文调整——不要照搬。
状态:🔴 关键模式
类别:基础设施
适用范围:所有项目中的所有 AWS 资源
概述
本文档定义了 AWS 资源的标准命名约定。遵循这些模式可确保:
- 清晰标识项目所有权
- 隔离环境并确保安全
- 统一识别资源
- 在 AWS 控制台中轻松筛选和管理
- 防止资源冲突和数据损坏
标准命名模式
核心格式
{project}-{resource-name}-{environment}
组成部分
-
项目前缀(必需)
- 项目的简短标识符(2-4 个字符)
- 仅限小写字母
- 示例:
cme、aip、app - 标识资源所属的项目
-
资源名称(必需)
- 描述资源的用途
- 使用小写字母和连字符
- 示例:
job-extractor、opportunities、website
-
环境后缀(必需)
dev- 开发环境prod- 生产环境staging- 预发布环境(可选)local- 本地开发(仅用于配置,绝不部署)- 为保持一致性,始终放在最后
为什么采用此模式?
- ✅ 项目所有权明确:前缀标识资源所属项目
- ✅ 环境位置一致:始终位于末尾
- ✅ 名称简短:除非为确保唯一性所必需,否则不包含账户/区域
- ✅ 符合 AWS 最佳实践:使用小写字母和连字符
- ✅ 便于筛选:可在 AWS 控制台中按前缀筛选
- ✅ 支持多个项目:多个项目共用一个账户时,可清晰区分
- ✅ 防止冲突:环境后缀可防止开发/生产资源相互覆盖
账户策略:单账户与多账户
两种部署方式
选项 1:单账户(开发和生产环境位于同一个 AWS 账户)
- 成本较低(无跨账户复杂性)
- IAM 和网络配置更简单
- 需要环境后缀来防止冲突
选项 2:多账户(开发和生产环境使用不同的 AWS 账户)
- 隔离性和安全性更好
- 账单和成本跟踪相互独立
- 仍需要环境后缀来确保安全
为什么始终需要环境后缀
即使使用不同的 AWS 账户,环境后缀也能提供关键的安全保障:
-
防止人为错误:立即看出当前操作的是哪个环境
# Without environment suffix aws lambda list-functions → job-extractor # Which environment is this? # With environment suffix aws lambda list-functions → job-extractor-prod # Clear: this is production! -
避免账户混淆:在账户间切换时防止出错
# You think you're in dev account, but you're actually in prod # Without suffix: You might delete "job-extractor" thinking it's dev # With suffix: You see "job-extractor-prod" and stop immediately -
面向未来:账户策略可能会发生变化
- 从单账户起步,之后拆分为多账户
- 为优化成本而合并账户
- 在现有账户中添加预发布环境
-
保持一致性:同一命名模式适用于所有场景
- 本地开发
- CI/CD 流水线
- AWS 控制台
- CloudFormation/CDK 代码
实际场景
# You're debugging an issue and need to check Lambda logs
# You have AWS CLI configured with multiple profiles
# Scenario 1: Without environment suffix
aws lambda get-function --function-name job-extractor --profile prod-account
# ⚠️ Is this the right function? Hard to tell from name alone
# Scenario 2: With environment suffix
aws lambda get-function --function-name job-extractor-prod --profile prod-account
# ✅ Name confirms you're looking at production resource
# ✅ Immediate visual confirmation prevents mistakes
规则:无论采用哪种账户策略,都始终包含环境后缀。这一安全层无需成本,却能避免代价高昂的错误。
关键:环境后缀为何重要
问题
如果资源名称中没有环境标识符,开发和生产资源部署到同一个 AWS 账户时就会发生冲突,导致覆盖和数据损坏。
实际影响
Lambda 函数(名称中没有环境标识):
// ❌ WRONG
functionName: 'job-data-extractor'
// GitHub Actions deploys dev
ENVIRONMENT=dev → Lambda: job-data-extractor
// GitHub Actions deploys prod
ENVIRONMENT=prod → Lambda: job-data-extractor // OVERWRITES dev!
DynamoDB 表(名称中没有环境标识):
// ❌ WRONG
tableName: `opportunities-${account}-${region}`
// Both environments use SAME table
// Result: Dev and prod data MIXED!
解决方案
始终在资源名称中包含环境标识:
// ✅ CORRECT
functionName: `job-data-extractor-${environment}`
tableName: `opportunities-${environment}`
// Results:
// dev: job-data-extractor-dev, opportunities-dev
// prod: job-data-extractor-prod, opportunities-prod
特定资源的命名模式
Lambda 函数
模式:{project}-{function-name}-{environment}
示例:
// ✅ CORRECT
functionName: `cme-job-extractor-${environment}`
functionName: `aip-data-sync-${environment}`
// Results:
// cme-job-extractor-dev
// cme-job-extractor-prod
// aip-data-sync-dev
原因:Lambda 名称在每个账户内必须唯一。环境后缀可防止开发和生产环境之间发生冲突。
DynamoDB 表
模式:{project}-{table-name}-{environment}
示例:
// ✅ CORRECT
tableName: `cme-opportunities-${environment}`
tableName: `aip-user-sessions-${environment}`
// Results:
// cme-opportunities-dev
// cme-opportunities-prod
可选扩展模式(需要确保唯一性时):
tableName: `{project}-{table-name}-${environment}-${account}-${region}`
// Example:
// cme-opportunities-dev-123456-us-east-1
原因:表名在每个账户中都必须唯一。环境后缀对于防止数据混淆至关重要。
S3 存储桶
模式:{project}-{bucket-purpose}-{environment}(发生冲突时添加随机后缀)
示例:
// ✅ CORRECT
bucketName: `cme-website-${environment}`
bucketName: `aip-assets-${environment}`
// Results:
// cme-website-dev
// cme-website-prod
发生冲突时(存储桶名称已被全局占用):
bucketName: `cme-website-${environment}-x7k2m`
// Results:
// cme-website-dev-x7k2m
// cme-website-prod-p9n4q
重要说明:
- 存储桶名称必须在所有 AWS 账户中全局唯一
- 仅使用小写字母、数字和连字符(不要使用下划线)
- 如果部署因 "BucketAlreadyExists" 失败,请添加随机后缀
- 后缀格式:5 个随机的小写字母数字字符
原因:存储桶名称必须全局唯一。先使用简洁模式,仅在需要时添加后缀。
API Gateway
模式:{PROJECT} API - {environment}(显示名称,项目名大写)
示例:
// ✅ CORRECT
restApiName: `CME API - ${environment}`
restApiName: `AIP API - ${environment}`
// Results:
// CME API - dev
// CME API - prod
原因:这是供人查看的显示名称。在 AWS Console 中使用大写形式以便阅读。
CloudFront 分配
模式:注释字段:{Project Name} - {environment}
示例:
Career Match Engine - dev
AI Portfolio - prod
标签:Environment: dev 或 Environment: prod
原因:CloudFront ID 会自动生成。使用注释和标签进行识别。
Lambda 层
模式:{project}-{layer-name} 或 {project}-{layer-name}-{environment}
示例:
// Shared across environments
layerName: 'cme-common-layer'
layerName: 'aip-utils-layer'
// Environment-specific
layerName: `cme-config-layer-${environment}`
注意:层通常会在多个环境间共享。环境后缀可选。
原因:层采用版本管理。在多个环境间共享可减少重复。
Lambda 层代码组织
目标:为每个 Lambda 提供所需内容,同时避免代码重复。这是在部署大小与代码复用之间的权衡,应根据具体情况评估。
层结构:按作用范围和可复用性组织
layers/
common/ # Truly shared utilities (3+ consumers)
nodejs/
logger.mjs
response-builder.mjs
config-loader.mjs
validation.mjs
feature-utils/ # Feature-specific utilities
nodejs/
feature-operations.mjs
feature-schemas.mjs
external-sdks/ # Third-party integrations
nodejs/
package.json # npm dependencies
sdk-wrapper.mjs
组织共享代码:
通用层 - 用于广泛使用的实用工具:
- 通用辅助工具(日志记录、验证、响应格式化)
- 被 3 个或更多不同功能使用
- 不包含特定于功能的逻辑
功能层 - 用于特定功能的共享代码:
- 特定领域的操作和架构
- 被该功能内的 2 个或更多函数使用
- 包含特定于功能的逻辑
集成层 - 用于外部依赖项:
- 第三方 SDK 软件包
- 外部服务的封装器
- 隔离版本管理
使用多个层:
// Function can reference multiple layers
const myFunction = new Function({
layers: [
commonLayer, // Generic utilities
featureALayer, // Feature A utilities
featureBLayer // Feature B utilities (if needed)
]
});
决策指南:
- 通用实用工具 →
common层 - 特定于功能的代码 → 功能层
- 外部软件包 → 集成层
- 跨功能需求 → 引用多个层
权衡:
- 层越多 = 单个 Lambda 越轻量,但复杂性越高
- 层越少 = 设置越简单,但部署包越大
- 根据项目需求进行平衡
示例场景:多个功能使用的 API 架构
- 如果是通用内容:移至
common层 - 如果特定于功能:保留在功能层,其他功能引用它
- 不要重复:使用层组合
SQS 队列
模式:{project}-{queue-name}-{environment}
示例:
queueName: `cme-job-processing-${environment}`
queueName: `aip-notifications-${environment}`
SNS 主题
模式:{project}-{topic-name}-{environment}
示例:
topicName: `cme-alerts-${environment}`
topicName: `aip-events-${environment}`
EventBridge 规则
模式:{project}-{rule-name}-{environment}
示例:
ruleName: `cme-daily-sync-${environment}`
ruleName: `aip-cleanup-${environment}`
Step Functions
模式:{project}-{state-machine-name}-{environment}
示例:
stateMachineName: `cme-workflow-${environment}`
stateMachineName: `aip-pipeline-${environment}`
Secrets Manager
模式:{project}/{environment}/{secret-name}
示例:
secretName: `cme/${environment}/api-key`
secretName: `aip/${environment}/db-password`
SSM 参数
模式:/{project}/{environment}/{namespace}/{key}
示例:
/cme/dev/lambda/job-extractor/LLM_API_KEY
/cme/prod/api/corsAllowedOrigins
/aip/dev/frontend/api-endpoint
注意:为保持历史兼容性,在 SSM 中使用 camelCase 格式的项目名称。
CloudWatch Log Groups
模式:/aws/lambda/{project}-{function-name}-{environment}
示例:
/aws/lambda/cme-job-extractor-dev
/aws/lambda/cme-recruiter-chat-prod
/aws/lambda/aip-data-sync-dev
注意:由 Lambda 自动生成,并自动遵循 Lambda 命名规则。
CDK 实现模式
Construct 属性
export interface ResourceConstructProps {
projectPrefix: string; // 'cme', 'aip', etc.
environment: string; // 'dev', 'prod', 'staging'
account: string;
region: string;
}
Lambda 函数
const myFunction = new lambda.Function(this, 'MyFunction', {
functionName: `${props.projectPrefix}-my-function-${props.environment}`,
runtime: lambda.Runtime.NODEJS_22_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
environment: {
ENVIRONMENT: props.environment,
PROJECT: props.projectPrefix
}
});
DynamoDB 表
const myTable = new dynamodb.Table(this, 'MyTable', {
tableName: `${props.projectPrefix}-my-table-${props.environment}`,
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: props.environment === 'prod'
? cdk.RemovalPolicy.RETAIN
: cdk.RemovalPolicy.DESTROY
});
S3 存储桶
const myBucket = new s3.Bucket(this, 'MyBucket', {
bucketName: `${props.projectPrefix}-my-bucket-${props.environment}`,
removalPolicy: props.environment === 'prod'
? cdk.RemovalPolicy.RETAIN
: cdk.RemovalPolicy.DESTROY,
autoDeleteObjects: props.environment !== 'prod'
});
环境变量设置
必需的环境变量
# Must be set before deployment
export ENVIRONMENT=dev # or 'prod', 'staging', etc.
export PROJECT_PREFIX=myapp # Short project identifier
部署脚本
#!/bin/bash
set -e
if [ -z "$ENVIRONMENT" ]; then
echo "Error: ENVIRONMENT is not set"
echo "Usage: ENVIRONMENT=dev ./deploy.sh"
exit 1
fi
if [ -z "$PROJECT_PREFIX" ]; then
echo "Error: PROJECT_PREFIX is not set"
echo "Usage: PROJECT_PREFIX=myapp ENVIRONMENT=dev ./deploy.sh"
exit 1
fi
echo "Deploying $PROJECT_PREFIX to environment: $ENVIRONMENT"
cdk deploy --all
GitHub Actions
name: Deploy
on:
push:
branches:
- main # Deploys to prod
- develop # Deploys to dev
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set environment
run: |
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
echo "ENVIRONMENT=prod" >> $GITHUB_ENV
else
echo "ENVIRONMENT=dev" >> $GITHUB_ENV
fi
echo "PROJECT_PREFIX=myapp" >> $GITHUB_ENV
- name: Deploy
run: |
echo "Deploying $PROJECT_PREFIX to $ENVIRONMENT"
./deploy.sh
验证清单
部署任何资源之前,请确认:
- 以项目前缀开头(
cme-、aip-等) - 以环境名称结尾(
-dev、-prod、-staging) - 使用小写字母和连字符(API Gateway 显示名称除外)
- 不硬编码环境值(使用变量)
- 名称清楚地描述资源用途
- 遵循模式:
{project}-{resource-name}-{environment} - 在部署前设置环境变量
常见陷阱
❌ 陷阱 1:环境值硬编码
// ❌ WRONG - Hardcoded 'dev'
bucketName: `my-app-dev`
// ✅ CORRECT - Use variable
bucketName: `my-app-${environment}`
❌ 陷阱 2:缺少环境变量
// ❌ WRONG - No environment
functionName: 'my-function'
// ✅ CORRECT - Include environment
functionName: `my-function-${environment}`
❌ 陷阱 3:模式不一致
// ❌ WRONG - Inconsistent
functionName: `my-function-${environment}` // Has environment
tableName: `my-table` // Missing environment
// ✅ CORRECT - Consistent
functionName: `my-function-${environment}`
tableName: `my-table-${environment}`
❌ 陷阱 4:缺少项目前缀
// ❌ WRONG - No project identification
functionName: `job-extractor-${environment}`
// ✅ CORRECT - Include project prefix
functionName: `cme-job-extractor-${environment}`
❌ 陷阱 5:误以为使用不同账户就不需要环境后缀
// ❌ WRONG ASSUMPTION
// "We use different AWS accounts for dev/prod, so we don't need environment in names"
functionName: 'job-extractor' // No environment suffix
// ✅ CORRECT - Always include environment
functionName: `job-extractor-${environment}`
// REALITY:
// - Human error: You might be in wrong account without realizing
// - Visual confirmation: Name tells you it's prod even if you're confused about account
// - Account strategy might change (single → multi or multi → single)
// - Consistency: Same pattern works for single and multi-account setups
// - Safety layer: Costs nothing, prevents costly mistakes
从旧名称迁移
审计阶段
- 列出账户中的所有 AWS 资源
- 找出名称中未包含环境的资源
- 找出未包含项目前缀的资源
- 记录受影响的环境
- 制定迁移策略
迁移阶段
- 使用正确的名称部署新资源
- 将数据从旧资源迁移到新资源
- 更新应用程序以使用新资源
- 验证新资源正常工作
- 验证后删除旧资源
验证
如何验证隔离情况
AWS 控制台检查:
# List all Lambda functions
aws lambda list-functions --query 'Functions[*].FunctionName'
# Should see:
# - cme-my-function-dev
# - cme-my-function-prod
# ✅ Clear project and environment separation
# NOT:
# - my-function
# ❌ No project or environment identifier
DynamoDB 检查:
# List all tables
aws dynamodb list-tables
# Should see:
# - cme-my-table-dev
# - cme-my-table-prod
# ✅ Clear separation
部署测试:
# Deploy dev
ENVIRONMENT=dev ./deploy.sh
# Deploy prod
ENVIRONMENT=prod ./deploy.sh
# Verify:
# - No resource overwrites
# - Both environments coexist
# - No conflicts or errors
快速参考
✅ 应该
- 在所有资源名称中包含项目前缀
- 在所有资源名称中包含
${environment} - 为所有资源使用一致的命名模式
- 在部署前验证环境变量已设置
- 测试部署到同一账户的 dev 和 prod 环境
- 在项目 README 中记录命名约定
❌ 不应该
- 硬编码环境值('dev'、'prod')
- 在资源名称中省略项目前缀
- 认为使用不同的 AWS 账户就不需要命名
- 在“临时”或“测试”资源中省略环境名称
- 对不同资源类型使用不同的命名模式
- 未验证环境变量就进行部署
相关模式
总结
关键规则:
- 每个 AWS 资源名称都必须包含项目前缀
- 每个 AWS 资源名称都必须包含环境标识符
- 使用模式:
{project}-{resource-name}-{environment}
原因:
- 防止资源冲突和数据损坏
- 明确项目所有权
- 支持安全地将多个环境部署到同一账户
- 便于识别和管理资源
做法:在所有资源名称中一致地使用 ${projectPrefix} 和 ${environment} 变量。
验证:将 dev 和 prod 都部署到同一账户,并确认不存在冲突。
请记住:这不是可选项。这是一种关键模式,可防止生产事故并实现清晰的资源管理。
持续改进
如果开发者纠正了本技能本应避免的行为,请提出对此技能的具体修订建议,以避免今后出现同样的问题。