How to Migrate AWS S3 Bucket Between Regions with Zero Downtime: A Complete Guide to Cross-Region Replication and Data Synchronization


1 views

When migrating infrastructure between AWS regions (like moving from US to EU), S3 bucket relocation presents unique challenges. Unlike EC2 instances that can be simply stopped and started in another region, S3 requires strategic planning for data transfer while maintaining data consistency during the transition period.

First, create your destination bucket in the EU region. Then configure CRR to automatically copy objects from your US bucket:

{
    "Role": "arn:aws:iam::account-id:role/CRR-role",
    "Rules": [
        {
            "Status": "Enabled",
            "Priority": 1,
            "DeleteMarkerReplication": { "Status": "Disabled" },
            "Filter" : { "Prefix": "" },
            "Destination": {
                "Bucket": "arn:aws:s3:::eu-destination-bucket",
                "StorageClass": "STANDARD"
            }
        }
    ]
}

To synchronize data created during migration, implement versioning in both buckets and use S3 event notifications to track changes:

aws s3api put-bucket-notification-configuration \
    --bucket us-source-bucket \
    --notification-configuration '{
        "LambdaFunctionConfigurations": [
            {
                "LambdaFunctionArn": "arn:aws:lambda:us-east-1:account-id:function:sync-function",
                "Events": ["s3:ObjectCreated:*"]
            }
        ]
    }'

When ready to switch completely to the EU bucket:

  1. Disable write operations to the US bucket
  2. Run a final sync using AWS DataSync or S3 Batch Operations
  3. Update all application references to the new EU bucket endpoint
  4. Monitor CRR completion metrics in CloudWatch

For large-scale migrations, consider creating a manifest file and using S3 Batch Operations:

aws s3control create-job \
    --account-id 123456789012 \
    --operation '{"S3PutObjectCopy": {"TargetResource": "arn:aws:s3:::eu-destination-bucket"}}' \
    --manifest '{"Spec": {"Format": "S3BatchOperations_CSV_20180820", "Fields": ["Bucket", "Key"]}, "Location": {"ObjectArn": "arn:aws:s3:::manifest-bucket/manifest.csv", "ETag": "exampleETag"}}' \
    --report '{"Bucket": "arn:aws:s3:::report-bucket", "Prefix": "reports", "Format": "Report_CSV_20180820", "Enabled": true, "ReportScope": "AllTasks"}' \
    --priority 10 \
    --role-arn arn:aws:iam::123456789012:role/batch-operations-role

To minimize transfer costs:

  • Use S3 Inventory to identify and migrate only changed objects
  • Compress data before transfer using S3 Select
  • Schedule transfers during AWS off-peak hours for potential cost savings

html

Moving terabytes of data between AWS regions presents several technical hurdles:

  • Native S3 replication only works within the same region
  • Direct bucket-to-bucket transfer isn't supported across regions
  • Maintaining data consistency during migration is complex
  • Cost implications of cross-region data transfer

Here's a battle-tested approach we've used in production:


// Step 1: Create destination bucket in EU region
aws s3api create-bucket \
    --bucket new-eu-bucket \
    --region eu-west-1 \
    --create-bucket-configuration LocationConstraint=eu-west-1

// Step 2: Enable versioning on both buckets
aws s3api put-bucket-versioning \
    --bucket original-us-bucket \
    --versioning-configuration Status=Enabled

aws s3api put-bucket-versioning \
    --bucket new-eu-bucket \
    --versioning-configuration Status=Enabled

Choose based on your specific requirements:

Option A: AWS DataSync

For automated, managed transfers:


# Create DataSync task
aws datasync create-task \
    --source-location-arn arn:aws:datasync:us-east-1:123456789012:location/loc-123abc \
    --destination-location-arn arn:aws:datasync:eu-west-1:123456789012:location/loc-456def \
    --options PreserveDeletedFiles=PRESERVE,VerifyMode=POINT_IN_TIME_CONSISTENT

Option B: S3 Batch Operations

For programmatic control:


{
  "Manifest": {
    "Spec": {
      "Format": "S3BatchOperations_CSV_20180820",
      "Fields": ["Bucket", "Key"]
    },
    "Location": {
      "ObjectArn": "arn:aws:s3:::us-bucket/manifest.csv",
      "ETag": "exampleETag"
    }
  },
  "Operation": {
    "S3PutObjectCopy": {
      "TargetResource": "arn:aws:s3:::eu-bucket",
      "MetadataDirective": "COPY",
      "StorageClass": "STANDARD"
    }
  }
}

The most critical part is maintaining consistency:

  1. Implement S3 event notifications to capture changes
  2. Use Lambda functions to replicate new objects
  3. Set up CloudWatch alarms for monitoring

Example Lambda Replicator


import boto3

s3 = boto3.client('s3')

def lambda_handler(event, context):
    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        key = record['s3']['object']['key']
        
        # Copy object to EU bucket
        copy_source = {'Bucket': bucket, 'Key': key}
        s3.copy_object(
            CopySource=copy_source,
            Bucket='new-eu-bucket',
            Key=key,
            MetadataDirective='COPY'
        )

When ready to switch:

  1. Stop write operations to old bucket
  2. Perform final sync of remaining objects
  3. Update application configurations to point to new bucket
  4. Monitor for 24-48 hours before decommissioning old bucket
  • Schedule transfers during off-peak hours
  • Use S3 inventory to identify cold data
  • Consider S3 Transfer Acceleration for critical paths
  • Delete unnecessary versions before migration