如何使用 CLI 删除 AWS S3 中的版本化存储桶?

How do I delete a versioned bucket in AWS S3 using the CLI?

我都试过了s3cmd:

$ s3cmd -r -f -v del s3://my-versioned-bucket/

以及 AWS CLI:

$ aws s3 rm s3://my-versioned-bucket/ --recursive

但是这两个命令都只是将 DELETE 标记添加到 S3。删除存储桶的命令也不起作用(来自 AWS CLI):

$ aws s3 rb s3://my-versioned-bucket/ --force
Cleaning up. Please wait...
Completed 1 part(s) with ... file(s) remaining
remove_bucket failed: s3://my-versioned-bucket/ A client error (BucketNotEmpty) occurred when calling the DeleteBucket operation: The bucket you tried to delete is not empty. You must delete all versions in the bucket.

好的...怎么样? their documentation for this. S3Cmd says it's a 'fully-featured' S3 command-line tool, but it makes no reference to versions 除了它自己的信息外,没有其他信息。有没有什么方法可以在不使用网络界面的情况下执行此操作,这将花费很长时间并且需要我一直打开笔记本电脑?

一种方法是遍历版本并删除它们。在 CLI 上有点棘手,但正如您提到的 Java,那会更直接:

AmazonS3Client s3 = new AmazonS3Client();
String bucketName = "deleteversions-"+UUID.randomUUID();

//Creates Bucket
s3.createBucket(bucketName);

//Enable Versioning
BucketVersioningConfiguration configuration = new BucketVersioningConfiguration(ENABLED);
s3.setBucketVersioningConfiguration(new SetBucketVersioningConfigurationRequest(bucketName, configuration ));

//Puts versions
s3.putObject(bucketName, "some-key",new ByteArrayInputStream("some-bytes".getBytes()), null);
s3.putObject(bucketName, "some-key",new ByteArrayInputStream("other-bytes".getBytes()), null);

//Removes all versions
for ( S3VersionSummary version : S3Versions.inBucket(s3, bucketName) ) {
    String key = version.getKey();
    String versionId = version.getVersionId();          
    s3.deleteVersion(bucketName, key, versionId);
}

//Removes the bucket
s3.deleteBucket(bucketName);
System.out.println("Done!");

如果需要,您还可以批量删除调用以提高效率。

您可以删除版本化 s3 存储桶中的所有对象。 但是我不知道如何删除特定的对象。

$ aws s3api delete-objects \
      --bucket <value> \
      --delete "$(aws s3api list-object-versions \
      --bucket <value> | \
      jq '{Objects: [.Versions[] | {Key:.Key, VersionId : .VersionId}], Quiet: false}')"

或者没有 jq:

$ aws s3api delete-objects \
    --bucket ${bucket_name} \
    --delete "$(aws s3api list-object-versions \
    --bucket "${bucket_name}" \
    --output=json \
    --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')"

我运行进入AWS CLI的相同限制。我发现最简单的解决方案是使用 Python 和 boto3:

#!/usr/bin/env python

BUCKET = 'your-bucket-here'

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket(BUCKET)
bucket.object_versions.delete()

# if you want to delete the now-empty bucket as well, uncomment this line:
#bucket.delete()

此答案的先前版本使用 boto,但正如 Chuckles 指出的那样,该解决方案存在大量键的性能问题。

  1. 删除指定对象,使用 jq 过滤器。
  2. 您可能需要清理 'DeleteMarkers' 而不仅仅是 'Versions'。
  3. 使用 $() 而不是 ``,您可以为存储桶名称和键值嵌入变量。
aws s3api delete-objects --bucket bucket-name --delete "$(aws s3api list-object-versions --bucket bucket-name | jq -M '{Objects: [.["Versions","DeleteMarkers"][]|select(.Key == "key-value")| {Key:.Key, VersionId : .VersionId}], Quiet: false}')"

这是一个单一的衬垫,您可以将其剪切并粘贴到命令行中以删除所有版本并删除标记(它需要 aws 工具,将 yourbucket-name-backup 替换为您的存储桶名称)

echo '#!/bin/bash' > deleteBucketScript.sh \
&& aws --output text s3api list-object-versions --bucket $BUCKET_TO_PERGE \
| grep -E "^VERSIONS" |\
awk '{print "aws s3api delete-object --bucket $BUCKET_TO_PERGE --key "" --version-id "";"}' >> \
deleteBucketScript.sh && . deleteBucketScript.sh; rm -f deleteBucketScript.sh; echo '#!/bin/bash' > \
deleteBucketScript.sh && aws --output text s3api list-object-versions --bucket $BUCKET_TO_PERGE \
| grep -E "^DELETEMARKERS" | grep -v "null" \
| awk '{print "aws s3api delete-object --bucket $BUCKET_TO_PERGE --key "" --version-id "";"}' >> \
deleteBucketScript.sh && . deleteBucketScript.sh; rm -f deleteBucketScript.sh;

那么你可以使用:

aws s3 rb s3://bucket-name --force

我 运行 遇到了 的问题,因为 list_buckets 生成器用于创建一个名为 all_keys 的庞大列表,我花了一个小时没有完成。这个调整似乎对我更有效,我的存储桶中有将近一百万个对象并且还在增加!

import boto

s3 = boto.connect_s3()
bucket = s3.get_bucket("your-bucket-name-here")

chunk_counter = 0 #this is simply a nice to have
keys = []
for key in bucket.list_versions():
    keys.append(key)
    if len(keys) > 1000:
        bucket.delete_keys(keys)
        chunk_counter += 1
        keys = []
        print("Another 1000 done.... {n} chunks so far".format(n=chunk_counter))

#bucket.delete() #as per usual uncomment if you're sure!

希望这对遇到这个 S3 噩梦的其他人有所帮助!

使用 boto3 比建议的 boto 解决方案更容易删除 S3 存储桶中的所有对象版本:

#!/usr/bin/env python
import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('your-bucket-name')
bucket.object_versions.all().delete()

对于非常大量的对象版本也能正常工作,尽管在那种情况下可能需要一些时间。

我发现其他答案要么不完整,要么需要安装外部依赖项(如 boto),因此这里是受这些启发但更深入的答案。

Working with Delete Markers 中所述,在删除版本化存储桶之前,必须完全删除其所有版本,这是一个两步过程:

  1. "delete" 存储桶中的所有版本对象,将它们标记为 已删除但实际上并未删除它们
  2. 删除所有删除标记对象完成删除

这是对我有用的纯 CLI 解决方案(受其他答案启发):

#!/usr/bin/env bash

bucket_name=...

del_s3_bucket_obj()
{
    local bucket_name=
    local obj_type=
    local query="{Objects: $obj_type[].{Key:Key,VersionId:VersionId}}"
    local s3_objects=$(aws s3api list-object-versions --bucket ${bucket_name} --output=json --query="$query")
    if ! (echo $s3_objects | grep -q '"Objects": null'); then
        aws s3api delete-objects --bucket "${bucket_name}" --delete "$s3_objects"
    fi
}

del_s3_bucket_obj ${bucket_name} 'Versions'
del_s3_bucket_obj ${bucket_name} 'DeleteMarkers'

完成后,以下将起作用:

aws s3 rb "s3://${bucket_name}"

虽然不确定 1000 多个对象的情况如何,但如果有人可以报告那就太棒了。

到目前为止,我发现的最简单的方法是使用此 CLI 工具 s3wipe。它作为 docker 容器提供,因此您可以像这样使用它:

$ docker run -it --rm slmingol/s3wipe --help
usage: s3wipe [-h] --path PATH [--id ID] [--key KEY] [--dryrun] [--quiet]
              [--batchsize BATCHSIZE] [--maxqueue MAXQUEUE]
              [--maxthreads MAXTHREADS] [--delbucket] [--region REGION]

Recursively delete all keys in an S3 path

optional arguments:
  -h, --help               show this help message and exit
  --path PATH              S3 path to delete (e.g. s3://bucket/path)
  --id ID                  Your AWS access key ID
  --key KEY                Your AWS secret access key
  --dryrun                 Don't delete. Print what we would have deleted
  --quiet                  Suprress all non-error output
  --batchsize BATCHSIZE    # of keys to batch delete (default 100)
  --maxqueue MAXQUEUE      Max size of deletion queue (default 10k)
  --maxthreads MAXTHREADS  Max number of threads (default 100)
  --delbucket              If S3 path is a bucket path, delete the bucket also
  --region REGION          Region of target S3 bucket. Default vaue `us-
                           east-1`

例子

这是一个示例,其中我删除了存储桶中的所有版本化对象,然后删除了该存储桶:

$ docker run -it --rm slmingol/s3wipe \
   --id $(aws configure get default.aws_access_key_id) \
   --key $(aws configure get default.aws_secret_access_key) \
   --path s3://bw-tf-backends-aws-example-logs \
   --delbucket
[2019-02-20@03:39:16] INFO: Deleting from bucket: bw-tf-backends-aws-example-logs, path: None
[2019-02-20@03:39:16] INFO: Getting subdirs to feed to list threads
[2019-02-20@03:39:18] INFO: Done deleting keys
[2019-02-20@03:39:18] INFO: Bucket is empty.  Attempting to remove bucket

工作原理

这里有一点要解包,但上面的内容是:

  • docker run -it --rm mikelorant/s3wipe - 以交互方式运行 s3wipe 容器并在每次执行后将其删除
  • --id & --key - 在
  • 中传递我们的访问密钥和访问 ID
  • aws configure get default.aws_access_key_id - 检索我们的密钥 id
  • aws configure get default.aws_secret_access_key - 检索我们的密钥
  • --path s3://bw-tf-backends-aws-example-logs - 我们要删除的存储桶
  • --delbucket - 清空后删除桶

参考资料

https://gist.github.com/wknapik/191619bfa650b8572115cd07197f3baf

#!/usr/bin/env bash

set -eEo pipefail
shopt -s inherit_errexit >/dev/null 2>&1 || true

if [[ ! "$#" -eq 2 || "" != --bucket ]]; then
    echo -e "USAGE: $(basename "[=10=]") --bucket <bucket>"
    exit 2
fi

# $@ := bucket_name
empty_bucket() {
    local -r bucket="${1:?}"
    for object_type in Versions DeleteMarkers; do
        local opt=() next_token=""
        while [[ "$next_token" != null ]]; do
            page="$(aws s3api list-object-versions --bucket "$bucket" --output json --max-items 1000 "${opt[@]}" \
                        --query="[{Objects: ${object_type}[].{Key:Key, VersionId:VersionId}}, NextToken]")"
            objects="$(jq -r '.[0]' <<<"$page")"
            next_token="$(jq -r '.[1]' <<<"$page")"
            case "$(jq -r .Objects <<<"$objects")" in
                '[]'|null) break;;
                *) opt=(--starting-token "$next_token")
                   aws s3api delete-objects --bucket "$bucket" --delete "$objects";;
            esac
        done
    done
}

empty_bucket "${2#s3://}"

例如empty_bucket.sh --bucket foo

这将删除所有对象版本,并以 1000 个为一批删除存储桶中的标记。之后,可以使用 aws s3 rb s3://foo 删除存储桶。

需要 bash、awscli 和 jq。

在此处找到此 bash 脚本:https://gist.github.com/weavenet/f40b09847ac17dd99d16

对我来说工作正常。

我将脚本保存为:delete_all_versions.sh 然后简单地 运行:

./delete_all_versions.sh my_foobar_bucket

这毫无瑕疵。

不需要 python 或 boto 或任何东西。

这对我有用。也许 运行 某些东西的更高版本及以上 > 1000 项。 运行 现在有几百万个文件。然而,半天后仍未完成,无法在 AWS GUI 中验证 =/

# Set bucket name to clearout
BUCKET = 'bucket-to-clear'

import boto3
s3 = boto3.resource('s3')
bucket = s3.Bucket(BUCKET)

max_len         = 1000      # max 1000 items at one req
chunk_counter   = 0         # just to keep track
keys            = []        # collect to delete

# clear files
def clearout():
    global bucket
    global chunk_counter
    global keys
    result = bucket.delete_objects(Delete=dict(Objects=keys))

    if result["ResponseMetadata"]["HTTPStatusCode"] != 200:
        print("Issue with response")
        print(result)

    chunk_counter += 1
    keys = []
    print(". {n} chunks so far".format(n=chunk_counter))
    return

# start
for key in bucket.object_versions.all():
    item = {'Key': key.object_key, 'VersionId': key.id}
    keys.append(item)
    if len(keys) >= max_len:
        clearout()

# make sure last files are cleared as well
if len(keys) > 0:
    clearout()

print("")
print("Done, {n} items deleted".format(n=chunk_counter*max_len))
#bucket.delete() #as per usual uncomment if you're sure!

对于通过 ~/.aws/config

使用多个配置文件的用户
import boto3

PROFILE = "my_profile"
BUCKET = "my_bucket"

session = boto3.Session(profile_name = PROFILE)
s3 = session.resource('s3')
bucket = s3.Bucket(BUCKET)
bucket.object_versions.delete()

您可以使用生命周期规则从 AWS 控制台执行此操作。

打开有问题的桶。单击顶部的“管理”选项卡。 确保选择了生命周期子选项卡。 单击 + 添加生命周期规则

在第 1 步(名称和范围)中输入规则名称(例如 removeall) 单击步骤 2(转换)旁边的下一步 保持原样并单击“下一步”。

您现在处于 3. 过期步骤。 选中当前版本和以前版本的复选框。 单击 "Expire current version of object" 的复选框并为“对象创建后 _____ 天后”输入数字 1 单击 "Permanently delete previous versions" 的复选框并输入数字 1 "After _____ days from becoming a previous version"

单击 "Clean up incomplete multipart uploads" 的复选框 并为 "After ____ days from start of upload" 输入数字 1 点击下一步 回顾一下你刚刚做了什么。
单击保存

过一天回来看看效果如何。

这两 bash 行足以让我启用存储桶删除!

1: 删除对象 aws s3api delete-objects --bucket ${buckettoempty} --delete "$(aws s3api list-object-versions --bucket ${buckettoempty} --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')"

2:删除标记 aws s3api delete-objects --bucket ${buckettoempty} --delete "$(aws s3api list-object-versions --bucket ${buckettoempty} --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')"

要添加此处提供的 python 解决方案:如果您遇到 boto.exception.S3ResponseError: S3ResponseError: 400 Bad Request 错误,请尝试使用以下数据创建 ~/.boto 文件:

[Credentials]
aws_access_key_id = aws_access_key_id
aws_secret_access_key = aws_secret_access_key
[s3]
host=s3.eu-central-1.amazonaws.com
aws_access_key_id = aws_access_key_id
aws_secret_access_key = aws_secret_access_key

帮我删除了法兰克福地区的bucket。

原回答:

尽管从技术上讲它不是 AWS CLI,但我还是建议使用 AWS Tools for Powershell 来完成此任务。然后你可以使用如下简单的命令:

Remove-S3Bucket -BucketName {bucket-name} -DeleteBucketContent -Force -Region {region}

如文档中所述,DeleteBucketContent 标志执行以下操作:

"If set, all remaining objects and/or object versions in the bucket are deleted proir (sic) to the bucket itself being deleted"

参考:https://docs.aws.amazon.com/powershell/latest/reference/

如果您必须 delete/empty 大型 S3 存储桶,删除每个对象和版本会变得非常低效(而且代价高昂)。让 AWS 使所有对象和版本过期通常更方便。

aws s3api put-bucket-lifecycle-configuration \
  --lifecycle-configuration '{"Rules":[{
      "ID":"empty-bucket",
      "Status":"Enabled",
      "Prefix":"",
      "Expiration":{"Days":1},
      "NoncurrentVersionExpiration":{"NoncurrentDays":1}
    }]}' \
  --bucket YOUR-BUCKET

然后您只需要等待 1 天 即可删除存储桶:

aws s3api delete-bucket --bucket YOUR-BUCKET

如果您想要纯 CLI 方法(使用 jq):

aws s3api list-object-versions \
          --bucket $bucket \
          --region $region \
          --query "Versions[].Key"  \
          --output json | jq 'unique' | jq -r '.[]' | while read key; do
   echo "deleting versions of $key"
   aws s3api list-object-versions \
          --bucket $bucket \
          --region $region \
          --prefix $key \
          --query "Versions[].VersionId"  \
          --output json | jq 'unique' | jq -r '.[]' | while read version; do
     echo "deleting $version"
     aws s3api delete-object \
          --bucket $bucket \
          --key $key \
          --version-id $version \
          --region $region
   done
done          

目前看来,AWS S3 控制台中有一个 Empty 按钮。

只需 select 您的存储桶并单击它。它会要求您输入 permanently delete 来确认您的决定 请注意,这不会删除存储桶本身。

您可以使用aws-cli删除s3 bucket

aws s3 rb s3://your-bucket-name

如果 aws cli 未安装在您的计算机中,您可以使用以下命令: 对于 Linux 或 ubuntu:

sudo apt-get install aws-cli

然后通过以下方式检查是否已安装:

aws --version

现在通过提供 aws-access-credentials 进行配置

aws configure

然后提供访问密钥和秘密访问密钥以及您所在的地区

我为 N 个存储桶找到并实施的简单 bash 循环:

for b in $(ListOfBuckets); do \
    echo "Emptying $b"; \
    aws s3api delete-objects --bucket $b --delete "$(aws s3api list-object-versions --bucket $b --output=json --query='{Objects: *[].{Key:Key,VersionId:VersionId}}')"; \
done

我用 Python3 和 argv 改进了

  1. 将以下脚本另存为 s3_rm.py.
#!/usr/bin/env python3
import sys
import boto3

def main():
    args = sys.argv[1:]
    if (len(args) < 1):
        print("Usage: {} s3_bucket_name".format(sys.argv[0]))
        exit()

    s3 = boto3.resource('s3')
    bucket = s3.Bucket(args[0])
    bucket.object_versions.delete()

    # if you want to delete the now-empty bucket as well, uncomment this line:
    #bucket.delete()

if __name__ == "__main__": 
    main()
  1. 添加chmod +x s3_rm.py.
  2. 运行 类似 ./s3_rm.py my_bucket_name.
  3. 的函数