Skip to content

Bucket 管理

📦 Bucket 概述

Bucket(存储桶)是 S3 中用于存储对象的容器,类似于文件系统中的顶级目录。所有对象都必须存储在 Bucket 中。

🔑 Bucket 特性

命名规则

✅ 有效的 Bucket 名称:
- my-app-images
- company-backups-2024
- user.data.bucket

❌ 无效的 Bucket 名称:
- MyAppImages (不能有大写)
- my_app_images (不推荐使用下划线)
- 192.168.1.1 (不能是 IP 地址格式)
- -my-bucket (不能以连字符开头)
- my-bucket- (不能以连字符结尾)

规则:
1. 长度:3-63 个字符
2. 字符:小写字母、数字、连字符(-)、点号(.)
3. 格式:必须以字母或数字开头和结尾
4. 唯一性:全球唯一(跨所有 AWS 账户)
5. 不可更改:创建后无法重命名

Bucket 属性

javascript
Bucket 包含以下属性:
├── Name: 全局唯一名称
├── Region: 所属区域
├── Versioning: 版本控制
├── Encryption: 加密设置
├── Access Control: 访问控制
├── Lifecycle Rules: 生命周期规则
├── Tags: 标签
└── Logging: 日志记录

🚀 创建 Bucket

Node.js SDK

javascript
const AWS = require('aws-sdk');
const s3 = new AWS.S3({ region: 'us-east-1' });

// 基本创建
const createBucket = async (bucketName) => {
  try {
    await s3.createBucket({ 
      Bucket: bucketName 
    }).promise();
    console.log(`Bucket ${bucketName} created successfully`);
  } catch (err) {
    if (err.code === 'BucketAlreadyExists') {
      console.error('Bucket name already taken');
    } else if (err.code === 'BucketAlreadyOwnedByYou') {
      console.log('You already own this bucket');
    } else {
      console.error(err);
    }
  }
};

// 在特定区域创建
const createBucketInRegion = async (bucketName, region) => {
  const s3 = new AWS.S3({ region });
  
  const params = {
    Bucket: bucketName,
    CreateBucketConfiguration: {
      LocationConstraint: region  // 注意:us-east-1 不需要此参数
    }
  };
  
  try {
    await s3.createBucket(params).promise();
    console.log(`Bucket ${bucketName} created in ${region}`);
  } catch (err) {
    console.error(err);
  }
};

// 创建并设置 ACL
const createBucketWithACL = async (bucketName) => {
  try {
    await s3.createBucket({
      Bucket: bucketName,
      ACL: 'private'  // private | public-read | public-read-write
    }).promise();
    console.log('Bucket created with ACL');
  } catch (err) {
    console.error(err);
  }
};

AWS CLI

bash
# 创建 Bucket
aws s3 mb s3://my-bucket-name

# 在特定区域创建
aws s3 mb s3://my-bucket-name --region us-west-2

# 使用 s3api 创建(更多选项)
aws s3api create-bucket \
  --bucket my-bucket-name \
  --region us-west-2 \
  --create-bucket-configuration LocationConstraint=us-west-2

📋 列出 Bucket

列出所有 Bucket

javascript
const listBuckets = async () => {
  try {
    const result = await s3.listBuckets().promise();
    
    console.log('Your buckets:');
    result.Buckets.forEach(bucket => {
      console.log(`- ${bucket.Name} (Created: ${bucket.CreationDate})`);
    });
    
    return result.Buckets;
  } catch (err) {
    console.error(err);
  }
};

AWS CLI

bash
# 列出所有 Bucket
aws s3 ls

# 输出示例:
# 2024-01-01 12:00:00 my-app-images
# 2024-01-02 13:30:00 company-backups

🔍 获取 Bucket 信息

获取 Bucket 位置

javascript
const getBucketLocation = async (bucketName) => {
  try {
    const result = await s3.getBucketLocation({
      Bucket: bucketName
    }).promise();
    
    console.log(`Bucket location: ${result.LocationConstraint || 'us-east-1'}`);
    return result.LocationConstraint;
  } catch (err) {
    console.error(err);
  }
};

检查 Bucket 是否存在

javascript
const bucketExists = async (bucketName) => {
  try {
    await s3.headBucket({ Bucket: bucketName }).promise();
    return true;
  } catch (err) {
    if (err.code === 'NotFound') {
      return false;
    }
    throw err;
  }
};

🗑️ 删除 Bucket

删除空 Bucket

javascript
const deleteBucket = async (bucketName) => {
  try {
    // 先检查 Bucket 是否为空
    const objects = await s3.listObjectsV2({
      Bucket: bucketName,
      MaxKeys: 1
    }).promise();
    
    if (objects.Contents && objects.Contents.length > 0) {
      throw new Error('Bucket is not empty. Delete all objects first.');
    }
    
    await s3.deleteBucket({ Bucket: bucketName }).promise();
    console.log(`Bucket ${bucketName} deleted`);
  } catch (err) {
    console.error(err);
  }
};

删除非空 Bucket

javascript
const emptyAndDeleteBucket = async (bucketName) => {
  try {
    // 1. 列出所有对象
    let isTruncated = true;
    let continuationToken = undefined;
    
    while (isTruncated) {
      const listParams = {
        Bucket: bucketName,
        ContinuationToken: continuationToken
      };
      
      const listResult = await s3.listObjectsV2(listParams).promise();
      
      if (listResult.Contents && listResult.Contents.length > 0) {
        // 2. 批量删除对象
        const deleteParams = {
          Bucket: bucketName,
          Delete: {
            Objects: listResult.Contents.map(obj => ({ Key: obj.Key }))
          }
        };
        
        await s3.deleteObjects(deleteParams).promise();
        console.log(`Deleted ${listResult.Contents.length} objects`);
      }
      
      isTruncated = listResult.IsTruncated;
      continuationToken = listResult.NextContinuationToken;
    }
    
    // 3. 删除版本(如果启用了版本控制)
    await deleteAllVersions(bucketName);
    
    // 4. 删除 Bucket
    await s3.deleteBucket({ Bucket: bucketName }).promise();
    console.log(`Bucket ${bucketName} deleted successfully`);
  } catch (err) {
    console.error(err);
  }
};

// 删除所有版本
const deleteAllVersions = async (bucketName) => {
  let keyMarker = undefined;
  let versionMarker = undefined;
  
  while (true) {
    const params = {
      Bucket: bucketName,
      KeyMarker: keyMarker,
      VersionIdMarker: versionMarker
    };
    
    const result = await s3.listObjectVersions(params).promise();
    
    // 删除所有版本和删除标记
    const objectsToDelete = [
      ...(result.Versions || []).map(v => ({ Key: v.Key, VersionId: v.VersionId })),
      ...(result.DeleteMarkers || []).map(d => ({ Key: d.Key, VersionId: d.VersionId }))
    ];
    
    if (objectsToDelete.length > 0) {
      await s3.deleteObjects({
        Bucket: bucketName,
        Delete: { Objects: objectsToDelete }
      }).promise();
    }
    
    if (!result.IsTruncated) break;
    
    keyMarker = result.NextKeyMarker;
    versionMarker = result.NextVersionIdMarker;
  }
};

AWS CLI

bash
# 删除空 Bucket
aws s3 rb s3://my-bucket-name

# 删除非空 Bucket(先删除所有对象)
aws s3 rb s3://my-bucket-name --force

🏷️ Bucket 标签

标签用于分类和成本分配。

javascript
// 设置标签
const setBucketTags = async (bucketName) => {
  const params = {
    Bucket: bucketName,
    Tagging: {
      TagSet: [
        { Key: 'Environment', Value: 'Production' },
        { Key: 'Project', Value: 'MyApp' },
        { Key: 'CostCenter', Value: 'Engineering' }
      ]
    }
  };
  
  try {
    await s3.putBucketTagging(params).promise();
    console.log('Tags set successfully');
  } catch (err) {
    console.error(err);
  }
};

// 获取标签
const getBucketTags = async (bucketName) => {
  try {
    const result = await s3.getBucketTagging({
      Bucket: bucketName
    }).promise();
    
    console.log('Bucket tags:');
    result.TagSet.forEach(tag => {
      console.log(`${tag.Key}: ${tag.Value}`);
    });
    
    return result.TagSet;
  } catch (err) {
    if (err.code === 'NoSuchTagSet') {
      console.log('No tags found');
      return [];
    }
    console.error(err);
  }
};

// 删除标签
const deleteBucketTags = async (bucketName) => {
  try {
    await s3.deleteBucketTagging({
      Bucket: bucketName
    }).promise();
    console.log('Tags deleted');
  } catch (err) {
    console.error(err);
  }
};

🔐 Bucket 加密

服务端加密(SSE)

javascript
// 启用默认加密(SSE-S3)
const enableEncryption = async (bucketName) => {
  const params = {
    Bucket: bucketName,
    ServerSideEncryptionConfiguration: {
      Rules: [
        {
          ApplyServerSideEncryptionByDefault: {
            SSEAlgorithm: 'AES256'  // S3 管理的密钥
          },
          BucketKeyEnabled: true  // 降低加密成本
        }
      ]
    }
  };
  
  try {
    await s3.putBucketEncryption(params).promise();
    console.log('Encryption enabled');
  } catch (err) {
    console.error(err);
  }
};

// 使用 KMS 加密
const enableKMSEncryption = async (bucketName, kmsKeyId) => {
  const params = {
    Bucket: bucketName,
    ServerSideEncryptionConfiguration: {
      Rules: [
        {
          ApplyServerSideEncryptionByDefault: {
            SSEAlgorithm: 'aws:kms',
            KMSMasterKeyID: kmsKeyId
          },
          BucketKeyEnabled: true
        }
      ]
    }
  };
  
  await s3.putBucketEncryption(params).promise();
};

// 获取加密配置
const getEncryption = async (bucketName) => {
  try {
    const result = await s3.getBucketEncryption({
      Bucket: bucketName
    }).promise();
    
    console.log('Encryption:', result.ServerSideEncryptionConfiguration);
    return result;
  } catch (err) {
    if (err.code === 'ServerSideEncryptionConfigurationNotFoundError') {
      console.log('No encryption configured');
    } else {
      console.error(err);
    }
  }
};

🌐 跨域资源共享(CORS)

javascript
const setCORS = async (bucketName) => {
  const params = {
    Bucket: bucketName,
    CORSConfiguration: {
      CORSRules: [
        {
          AllowedHeaders: ['*'],
          AllowedMethods: ['GET', 'PUT', 'POST', 'DELETE'],
          AllowedOrigins: ['https://example.com', 'https://*.example.com'],
          ExposeHeaders: ['ETag', 'x-amz-meta-custom-header'],
          MaxAgeSeconds: 3600
        }
      ]
    }
  };
  
  try {
    await s3.putBucketCors(params).promise();
    console.log('CORS configured');
  } catch (err) {
    console.error(err);
  }
};

// 获取 CORS 配置
const getCORS = async (bucketName) => {
  try {
    const result = await s3.getBucketCors({
      Bucket: bucketName
    }).promise();
    console.log('CORS rules:', result.CORSRules);
    return result;
  } catch (err) {
    console.error(err);
  }
};

📊 Bucket 指标和监控

javascript
// 启用请求指标
const enableMetrics = async (bucketName) => {
  const params = {
    Bucket: bucketName,
    Id: 'EntireBucket',
    MetricsConfiguration: {
      Id: 'EntireBucket'
    }
  };
  
  await s3.putBucketMetricsConfiguration(params).promise();
  console.log('Metrics enabled');
};

// 查看 CloudWatch 指标
// 可以在 AWS 控制台的 CloudWatch 中查看:
// - NumberOfObjects: 对象数量
// - BucketSizeBytes: 存储大小
// - AllRequests: 总请求数
// - GetRequests: GET 请求数
// - PutRequests: PUT 请求数

💡 最佳实践

1. 命名约定

javascript
// ✅ 好的命名
'company-app-images-prod'
'project-logs-2024'
'user-uploads-staging'

// ❌ 避免
'MyBucket'  // 大写
'bucket_name'  // 下划线
'test'  // 太通用

2. 区域选择

javascript
// 选择最近的区域以降低延迟
const regionByLocation = {
  'US-East': 'us-east-1',
  'US-West': 'us-west-2',
  'EU': 'eu-west-1',
  'Asia': 'ap-northeast-1'
};

// 考虑数据主权和合规性
// 例如:GDPR 要求数据存储在欧盟

3. 成本优化

javascript
// 使用生命周期策略自动转换存储类别
// 定期清理不需要的数据
// 启用 Bucket 分析以了解访问模式

4. 安全性

javascript
// 始终加密敏感数据
// 使用 Bucket Policy 和 IAM 策略控制访问
// 启用版本控制以防止意外删除
// 定期审查权限

📖 相关资源


下一步:学习 对象操作 📝