mcpField
R
resource-naming

resource-naming

github.com/loxosceles-dev云与 DevOps128 次安装
代码仓库

关于 resource-naming

这是一份面向 AWS 基础设施团队的资源命名参考技能,涵盖跨项目和环境的命名约定。它规定项目、资源名称、环境的格式,并提供各类服务的示例与说明。

主要功能

  1. 01项目-资源-环境命名格式
  2. 02环境后缀使用说明
  3. 03多种 AWS 资源命名模式
  4. 04S3 名称冲突时添加后缀
  5. 05CDK 实现示例

适用场景

  1. 01为开发和生产环境命名资源
  2. 02减少不同项目间的命名冲突
  3. 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}
组成部分
  1. 项目前缀(必需)

    • 项目的简短标识符(2-4 个字符)
    • 仅限小写字母
    • 示例:cme、aip、app
    • 标识资源所属的项目
  2. 资源名称(必需)

    • 描述资源的用途
    • 使用小写字母和连字符
    • 示例:job-extractor、opportunities、website
  3. 环境后缀(必需)

    • dev - 开发环境
    • prod - 生产环境
    • staging - 预发布环境(可选)
    • local - 本地开发(仅用于配置,绝不部署)
    • 为保持一致性,始终放在最后
为什么采用此模式?
  • ✅ 项目所有权明确:前缀标识资源所属项目
  • ✅ 环境位置一致:始终位于末尾
  • ✅ 名称简短:除非为确保唯一性所必需,否则不包含账户/区域
  • ✅ 符合 AWS 最佳实践:使用小写字母和连字符
  • ✅ 便于筛选:可在 AWS 控制台中按前缀筛选
  • ✅ 支持多个项目:多个项目共用一个账户时,可清晰区分
  • ✅ 防止冲突:环境后缀可防止开发/生产资源相互覆盖

账户策略:单账户与多账户

两种部署方式

选项 1:单账户(开发和生产环境位于同一个 AWS 账户)

  • 成本较低(无跨账户复杂性)
  • IAM 和网络配置更简单
  • 需要环境后缀来防止冲突

选项 2:多账户(开发和生产环境使用不同的 AWS 账户)

  • 隔离性和安全性更好
  • 账单和成本跟踪相互独立
  • 仍需要环境后缀来确保安全
为什么始终需要环境后缀

即使使用不同的 AWS 账户,环境后缀也能提供关键的安全保障:

  1. 防止人为错误:立即看出当前操作的是哪个环境

    # 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!
    
  2. 避免账户混淆:在账户间切换时防止出错

    # 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
    
  3. 面向未来:账户策略可能会发生变化

    • 从单账户起步,之后拆分为多账户
    • 为优化成本而合并账户
    • 在现有账户中添加预发布环境
  4. 保持一致性:同一命名模式适用于所有场景

    • 本地开发
    • 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

从旧名称迁移

审计阶段
  1. 列出账户中的所有 AWS 资源
  2. 找出名称中未包含环境的资源
  3. 找出未包含项目前缀的资源
  4. 记录受影响的环境
  5. 制定迁移策略
迁移阶段
  1. 使用正确的名称部署新资源
  2. 将数据从旧资源迁移到新资源
  3. 更新应用程序以使用新资源
  4. 验证新资源正常工作
  5. 验证后删除旧资源

验证

如何验证隔离情况

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 账户就不需要命名
  • 在“临时”或“测试”资源中省略环境名称
  • 对不同资源类型使用不同的命名模式
  • 未验证环境变量就进行部署

相关模式


总结

关键规则:

  1. 每个 AWS 资源名称都必须包含项目前缀
  2. 每个 AWS 资源名称都必须包含环境标识符
  3. 使用模式:{project}-{resource-name}-{environment}

原因:

  • 防止资源冲突和数据损坏
  • 明确项目所有权
  • 支持安全地将多个环境部署到同一账户
  • 便于识别和管理资源

做法:在所有资源名称中一致地使用 ${projectPrefix} 和 ${environment} 变量。

验证:将 dev 和 prod 都部署到同一账户,并确认不存在冲突。

请记住:这不是可选项。这是一种关键模式,可防止生产事故并实现清晰的资源管理。


持续改进

如果开发者纠正了本技能本应避免的行为,请提出对此技能的具体修订建议,以避免今后出现同样的问题。

评论

支持 Markdown