【问题标题】:AWS S3 copy files and folders between two bucketsAWS S3 在两个存储桶之间复制文件和文件夹
【发布时间】:2020-12-16 03:41:42
【问题描述】:

我一直在寻找一种工具来帮助我将 AWS S3 存储桶的内容复制到第二个 AWS S3 存储桶,而无需先将内容下载到本地文件系统。

我曾尝试使用 AWS S3 控制台复制选项,但这导致一些嵌套文件丢失。

我曾尝试使用 Transmit 应用程序(由 Panic 提供)。复制命令首先将文件下载到本地系统,然后将它们上传回第二个存储桶,效率非常低。

【问题讨论】:

标签: amazon-s3 copy amazon-web-services


【解决方案1】:

在 S3 存储桶之间复制

AWS(就在最近)发布了一个用于在存储桶之间复制的命令行界面。

http://aws.amazon.com/cli/

$ aws s3 sync s3://mybucket-src s3://mybucket-target --exclude *.tmp
..

将复制从一个目标存储桶到另一个存储桶。

在此处查看文档:S3 CLI Documentation

【讨论】:

  • 从 EC2 运行它并在大约 5 秒内复制了 80MB。
  • 正是我需要的,因为 aws-sdk gem 没有一次复制或同步整个存储桶的功能。谢谢!
  • 它会抛出以下错误A client error (PermanentRedirect) occurred when calling the ListObjects operation: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.
  • @GiovanniBitliner 您使用的存储桶名称不正确。您要么使用了错误的前缀,要么使用了引用存储桶的旧方式。在管理控制台中准确检查您的存储桶名称。
  • 请注意,如果这是您第一次使用 cli 工具,您需要运行“aws configure”并输入您的凭据
【解决方案2】:

使用 aws-sdk gem 的简化示例:

AWS.config(:access_key_id => '...', :secret_access_key => '...')
s3 = AWS::S3.new
s3.buckets['bucket-name'].objects['source-key'].copy_to('target-key')

如果要在不同bucket之间进行复制,则指定目标bucket名称:

s3.buckets['bucket-name'].objects['source-key'].copy_to('target-key', :bucket_name => 'target-bucket')

【讨论】:

    【解决方案3】:

    您现在可以从 S3 管理界面执行此操作。只需进入一个存储桶,选择所有文件夹actions->copy。然后进入您的新存储桶actions->paste

    【讨论】:

    • 太棒了!他指的是网络界面。与大多数其他人不同,我可以通过 iPad 完成此操作。
    • 这会随机遗漏子文件夹中的嵌套对象 - 3 年后,AWS 仍然无法修复这样一个基本错误!
    • 是同一地区还是全部?
    • 亚马逊是否在任何地方记录了这些问题? @RunLoop
    【解决方案4】:

    不同区域的桶之间复制

    $ aws s3 cp s3://src_bucket/file  s3://dst_bucket/file --source-region eu-west-1 --region ap-northeast-1
    

    上述命令将文件从欧洲 (eu-west-1) 的存储桶复制到日本 (ap-northeast-1)。您可以使用以下命令获取存储桶所在区域的代号:

    $ aws s3api get-bucket-location --bucket my_bucket
    

    顺便说一句,在 S3 Web 控制台中使用复制和粘贴很容易,但似乎是从源存储桶下载到浏览器中,然后再上传到目标存储桶。使用“aws s3”对我来说要快得多。

    【讨论】:

      【解决方案5】:

      最近的 aws-sdk gem 可以实现,请参阅代码示例:

      require 'aws-sdk'
      
      AWS.config(
        :access_key_id     => '***',
        :secret_access_key => '***',
        :max_retries       => 10
      )
      
      file     = 'test_file.rb'
      bucket_0 = {:name => 'bucket_from', :endpoint => 's3-eu-west-1.amazonaws.com'}
      bucket_1 = {:name => 'bucket_to',   :endpoint => 's3.amazonaws.com'}
      
      s3_interface_from = AWS::S3.new(:s3_endpoint => bucket_0[:endpoint])
      bucket_from       = s3_interface_from.buckets[bucket_0[:name]]
      bucket_from.objects[file].write(open(file))
      
      s3_interface_to   = AWS::S3.new(:s3_endpoint => bucket_1[:endpoint])
      bucket_to         = s3_interface_to.buckets[bucket_1[:name]]
      bucket_to.objects[file].copy_from(file, {:bucket => bucket_from})
      

      更多详情:How to copy file across buckets using aws-s3 gem

      【讨论】:

      • 感谢您展示如何跨服务器复制。我正在尝试从我们的服务器复制到新加坡服务器。
      • @Arcolye 现在 AWS 新加坡的延迟情况如何?一年前进展缓慢且不一致。
      【解决方案6】:

      我创建了Docker executables3s3mirror 工具。 用于从 AWS S3 存储桶复制和镜像到另一个存储桶的实用程序。

      它是线程化的,允许并行复制并且非常节省内存,它在 s3cmd 完全失败的地方成功。

      用法:

      docker run -e AWS_ACCESS_KEY_ID=FOO -e AWS_SECRET_ACCESS_KEY=BAR pmoust/s3s3mirror [OPTIONS] source_bucket[/prefix] dest_bucket[/prefix]
      

      如需完整的选项列表,请尝试:

      docker run pmoust/s3s3mirror 
      

      【讨论】:

        【解决方案7】:

        查看以下文档。我想这就是你要找的。 http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectCOPY.html

        RightAws gem 的 S3Interface 具有执行上述操作的复制功能。

        http://rubydoc.info/gems/right_aws/3.0.0/RightAws/S3Interface#copy-instance_method

        【讨论】:

          【解决方案8】:

          我想您现在可能已经找到了一个很好的解决方案,但是对于遇到这个问题的其他人(就像我最近一样),我制作了一个简单的实用程序,专门用于镜像一个 S3 存储桶以高度并发但 CPU 和内存高效的方式发送给另一个。

          它在 Apache 许可证下的 github 上:https://github.com/cobbzilla/s3s3mirror

          当您有一个非常大的存储桶并正在寻找最佳性能时,可能值得一试。

          如果您决定尝试一下,如果您有任何反馈,请告诉我。

          【讨论】:

          • 我对 s3s3mirror 的体验非常好。我能够在 m1.small EC2 节点上设置它并在大约 2 小时内复制 150 万个对象。由于我不熟悉 Maven 和 Java,设置有点困难,但在 Ubuntu 上只需要几个 apt-get 命令就可以安装所有东西。最后一点:如果(像我一样)您担心在一个大而重要的 s3 存储桶上运行未知脚本,请创建一个对复制源存储桶具有只读访问权限的特殊用户并使用这些凭据。意外删除的可能性为零。
          【解决方案9】:

          如果您在 shell 中并且想要复制多个文件但不是所有文件: s3cmd cp --recursive s3://BUCKET1/OBJECT1 s3://BUCKET2[/OBJECT2]

          【讨论】:

            【解决方案10】:

            我编写了一个备份 S3 存储桶的脚本:https://github.com/roseperrone/aws-backup-rake-task

            #!/usr/bin/env python
            from boto.s3.connection import S3Connection
            import re
            import datetime
            import sys
            import time
            
            def main():
                s3_ID = sys.argv[1]
                s3_key = sys.argv[2]
                src_bucket_name = sys.argv[3]
                num_backup_buckets = sys.argv[4]
                connection = S3Connection(s3_ID, s3_key)
                delete_oldest_backup_buckets(connection, num_backup_buckets)
                backup(connection, src_bucket_name)
            
            def delete_oldest_backup_buckets(connection, num_backup_buckets):
                """Deletes the oldest backup buckets such that only the newest NUM_BACKUP_BUCKETS - 1 buckets remain."""
                buckets = connection.get_all_buckets() # returns a list of bucket objects
                num_buckets = len(buckets)
            
                backup_bucket_names = []
                for bucket in buckets:
                    if (re.search('backup-' + r'\d{4}-\d{2}-\d{2}' , bucket.name)):
                        backup_bucket_names.append(bucket.name)
            
                backup_bucket_names.sort(key=lambda x: datetime.datetime.strptime(x[len('backup-'):17], '%Y-%m-%d').date())
            
                # The buckets are sorted latest to earliest, so we want to keep the last NUM_BACKUP_BUCKETS - 1
                delete = len(backup_bucket_names) - (int(num_backup_buckets) - 1)
                if delete <= 0:
                    return
            
                for i in range(0, delete):
                    print 'Deleting the backup bucket, ' + backup_bucket_names[i]
                    connection.delete_bucket(backup_bucket_names[i])
            
            def backup(connection, src_bucket_name):
                now = datetime.datetime.now()
                # the month and day must be zero-filled
                new_backup_bucket_name = 'backup-' + str('%02d' % now.year) + '-' + str('%02d' % now.month) + '-' + str(now.day);
                print "Creating new bucket " + new_backup_bucket_name
                new_backup_bucket = connection.create_bucket(new_backup_bucket_name)
                copy_bucket(src_bucket_name, new_backup_bucket_name, connection)
            
            
            def copy_bucket(src_bucket_name, dst_bucket_name, connection, maximum_keys = 100):
                src_bucket = connection.get_bucket(src_bucket_name);
                dst_bucket = connection.get_bucket(dst_bucket_name);
            
                result_marker = ''
                while True:
                    keys = src_bucket.get_all_keys(max_keys = maximum_keys, marker = result_marker)
            
                    for k in keys:
                        print 'Copying ' + k.key + ' from ' + src_bucket_name + ' to ' + dst_bucket_name
            
                        t0 = time.clock()
                        dst_bucket.copy_key(k.key, src_bucket_name, k.key)
                        print time.clock() - t0, ' seconds'
            
                    if len(keys) < maximum_keys:
                        print 'Done backing up.'
                        break
            
                    result_marker = keys[maximum_keys - 1].key
            
            if  __name__ =='__main__':main()
            

            我在 rake 任务中使用它(用于 Rails 应用程序):

            desc "Back up a file onto S3"
            task :backup do
                 S3ID = "AKIAJM3NRWC7STXWUWVQ"
                 S3KEY = "0A5kuzV+E1dkaPjZxHQAezz1GlSddJd0iS5sNpry"
                 SRCBUCKET = "primary-mzgd"
                 NUM_BACKUP_BUCKETS = 2
            
                 Dir.chdir("#{Rails.root}/lib/tasks")
                 system "./do_backup.py #{S3ID} #{S3KEY} #{SRCBUCKET} #{NUM_BACKUP_BUCKETS}"
            end
            

            【讨论】:

              【解决方案11】:

              要从一个 S3 存储桶复制到同一个或另一个 S3 存储桶而不下载到本地,非常简单。使用下面的 shell 命令。

              hdfs dfs -cp -f "s3://AccessKey:SecurityKey@ExternalBucket/SourceFoldername/*.*" "s3://AccessKey:SecurityKey@ExternalBucket/TargetFoldername"
              

              这会将源存储桶的SourceFoldername 文件夹中的所有文件复制到目标存储桶的TargetFoldername 文件夹。上述代码中,请将AccessKeySecurityKeyExternalBucket替换为您对应的值。

              【讨论】:

              • 什么是hdfs
              【解决方案12】:

              来自 AWS cli https://aws.amazon.com/cli/ 你可以这样做

              aws s3 ls - 这将列出所有 S3 存储桶

              aws cp --recursive s3://&lt;source bucket&gt; s3://&lt;destination bucket&gt; - 这会将文件从一个存储桶复制到另一个存储桶

              注意* 在创建跨区域复制存储桶时非常有用,通过执行上述操作,您的文件都会被跟踪,并且对源区域文件的更新将传播到复制的存储桶。除文件删除之外的所有内容均已同步。

              对于 CRR,请确保您在存储桶上启用了版本控制。

              【讨论】:

                【解决方案13】:

                我听说如果你喜欢 javascript,有一个节点模块:p

                来自 knox-copy 文档:

                knoxCopy = require 'knox-copy'
                
                client = knoxCopy.createClient
                  key: '<api-key-here>'
                  secret: '<secret-here>'
                  bucket: 'backups'
                
                client.copyBucket
                  fromBucket: 'uploads'
                  fromPrefix: '/nom-nom'
                  toPrefix: "/upload_backups/#{new Date().toISOString()}"
                  (err, count) ->
                     console.log "Copied #{count} files"
                

                【讨论】:

                • 这不是javascript,抱歉...(是的,我知道coffeescript,你可以使用它,但不是javascript)
                【解决方案14】:

                我被告知您也可以在 EMR 集群上使用 s3distcp 来执行此操作。对于包含大文件的数据,它应该更快。它在少量数据上运行良好 - 但考虑到为这么少的数据设置所需的学习曲线(我以前从未使用过 EMR),我更喜欢另一种解决方案。

                这是来自 AWS 文档的链接:http://docs.aws.amazon.com/ElasticMapReduce/latest/DeveloperGuide/UsingEMR_s3distcp.html

                更新:对于相同的数据集,s3s3mirror 比 s3distcp 或 AWS cli 快得多。设置起来也容易得多。

                【讨论】:

                  【解决方案15】:

                  正如 Neel Bhaat 在此 blog 中所解释的,有许多不同的工具可用于此目的。有些是 AWS 提供的,其中大多数是第三方工具。所有这些工具都要求您将 AWS 账户密钥和秘密保存在工具本身中。使用第三方工具时要非常小心,因为您保存的凭据可能会花费您的全部价值并让您丧命。

                  因此,我始终建议为此使用AWS CLI。你可以简单地从this link 安装它。接下来,运行以下命令并将您的密钥、秘密值保存在 AWS CLI 中。

                  aws configure
                  

                  并使用以下命令将您的 AWS S3 存储桶同步到您的本地计算机。 (本地机器应该安装了 AWS CLI)

                  aws s3 sync <source> <destination>
                  

                  示例:

                  1) 用于 AWS S3 到本地存储

                  aws s3 sync <S3Uri> <LocalPath>
                  

                  2) 从本地存储到 AWS S3

                  aws s3 sync <LocalPath> <S3Uri>
                  

                  3) 从 AWS s3 存储桶到另一个存储桶

                  aws s3 sync <S3Uri> <S3Uri> 
                  

                  【讨论】:

                    【解决方案16】:

                    aws s3 sync cli 命令怎么样。 aws s3 同步 s3://bucket1/ s3://bucket2/

                    【讨论】:

                      【解决方案17】:

                      复制 S3 存储桶的最佳方式是使用 AWS CLI

                      它涉及这三个步骤:

                      1. 在您的服务器上安装 AWS CLI。
                      **https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html**
                      
                      1. 如果您在两个 AWS 账户之间复制存储桶,则需要为每个存储桶附加正确的策略。

                      2. 之后使用此命令从一个存储桶复制到另一个存储桶。

                      aws s3 sync s3://sourcebucket s3://destinationbucket
                      

                      step 2step 3的详细信息在此链接中给出:

                      https://aws.amazon.com/premiumsupport/knowledge-center/account-transfer-s3/

                      【讨论】:

                        【解决方案18】:

                        您可以编写一个 Java 应用程序 - 甚至可能是一个使用 AWS Java API 的 GUI SWING 应用程序要复制对象,请参阅 -

                        https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javav2/example_code/s3/src/main/java/com/example/s3/CopyObject.java

                        【讨论】:

                          【解决方案19】:

                          添加Copying objects across AWS accounts using S3 Batch Operations,因为这里还没有提到它。这是我目前正在尝试的方法,因为我有大约 100 万个对象需要移动到新帐户,并且由于某些令牌过期,cp 和 sync 对我不起作用,而且我没有找出它是什么令牌的方法,因为我的通用访问令牌工作得很好。

                          【讨论】:

                            【解决方案20】:

                            从 2020 年起,如果您使用 s3cmd,您可以使用以下命令将文件夹从 bucket1 复制到 bucket2

                            s3cmd cp --recursive s3://bucket1/folder_name/ s3://bucket2/folder_name/
                            

                            --recursive是递归复制文件夹中所有内容的必要条件,还要注意文件夹名称后必须指定“/”,否则会失败。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2015-07-21
                              • 1970-01-01
                              • 2017-09-13
                              • 1970-01-01
                              • 2021-07-03
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多