如何使用 CLI 删除 AWS S3 中的版本化存储桶?
Posted
技术标签:
【中文标题】如何使用 CLI 删除 AWS S3 中的版本化存储桶?【英文标题】:How do I delete a versioned bucket in AWS S3 using the CLI? 【发布时间】:2015-06-30 19:00:43 【问题描述】: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 中没有这方面的信息。 S3Cmd 说它是一个“功能齐全”的 S3 命令行工具,但它使no reference to versions 不同于它自己的。有什么方法可以在不使用网络界面的情况下做到这一点,这将花费很长时间并且需要我打开笔记本电脑?
【问题讨论】:
据我所知,您需要遍历对象版本并分批删除 1000 个... 如果某处有这方面的示例 Java 代码,那就太好了。 AWS 文档真的很糟糕…… 【参考方案1】:我遇到了 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 指出的那样,该解决方案存在大量密钥的性能问题。
【讨论】:
最佳解决方案!! 这对我也很有效!只有 snag 在 Arch linux 上成功安装了 boto,这很有效:pip3 install boto3 --user <username>
我不是 Python 开发人员,我主要更喜欢 Node.js 而不是 Python,但这个包看起来是迄今为止最好的解决方案。
效果很好。只是想补充一点,需要在没有任何前缀的情况下指定存储桶。否则,它会引发验证错误。这有效:BUCKET = 'my-bucket-name'
对于需要使用配置文件进行多角色和/或多帐户使用的任何人,在创建 s3 资源之前添加 boto3.setup_default_session(profile_name='YOUR_PROFILE_NAME')
是必要的...【参考方案2】:
使用boto3
比使用建议的boto
解决方案更容易删除S3 存储桶中的所有对象版本:
#!/usr/bin/env python
import boto3
s3 = boto3.resource('s3')
bucket = s3.Bucket('your-bucket-name')
bucket.object_versions.all().delete()
也适用于大量对象版本,但在这种情况下可能需要一些时间。
【讨论】:
如果我想保留当前版本但删除其他所有内容怎么办?【参考方案3】:您可以删除版本化 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')"
【讨论】:
有什么方法可以绕过 1000 多个对象的限制? 不错,但正如其他答案中提到的那样,版本可能还不够,您可能还需要删除 DeleteMarkers。 正确,DeleteMarkers 也需要删除。 (刚刚尝试过) @BruceEdge 您能否更新答案以反映删除标记的删除?谢谢 @DJ_Stuffy_K 我后来通过创建删除超过 1 天的版本的策略来解决这个问题。现在,当我想删除版本控制的存储桶时,我会应用策略,然后禁用版本控制。然后该策略会处理所有旧版本。 (没有一种简单的方法可以在单个命令中删除标记)【参考方案4】:这两条 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')"
【讨论】:
在命令行上执行此操作会产生Argument list too long
异常。如果遇到这种情况,请利用 list-object-versions
调用中的 --max-items
参数(我做了 500 个批次)。
或者你可以使用DeleteMarkers[0:999]
【参考方案5】:
这是一个单行,您可以剪切并粘贴到命令行中以删除所有版本并删除标记(它需要 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 "$4" --version-id "$8";"' >> \
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 "$3" --version-id "$5";"' >> \
deleteBucketScript.sh && . deleteBucketScript.sh; rm -f deleteBucketScript.sh;
那么你可以使用:
aws s3 rb s3://bucket-name --force
【讨论】:
我的同事设置了生命周期规则,这些规则将在接下来的几天内慢慢删除版本控制存储桶。您的回答具有讽刺意味,因为它意味着我们系统中 S3 版本控制的终结。 据我所知,这是唯一一个基于 CLI 的实际答案,可以满足实际工作的任何大小的存储桶。 赞成答案的正确性,但这段代码真的很难阅读和理解。 构建一个脚本,执行它,然后删除脚本非常酷,但是您可以使用 xargs 将参数直接传递给 bash 并立即使用多个线程执行它们。aws --output text s3api list-object-versions --bucket MY_BUCKET | grep -E "^VERSIONS" | xargs -P8 -l bash -c 'aws s3api delete-object --bucket MY_BUCKET --key "$3" --version-id "$7"'
请注意,由于 bash 使用零索引,因此索引会移动 1。【参考方案6】:
一种方法是遍历版本并删除它们。 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 存储桶中的每个“文件夹”(其中有四个),如果需要,将较大文件夹的线程拆分为first/1
, ..., first/9
, 等等...但是我和一个同事最终使用 Web 界面和 Cyberduck 删除了所有版本。感谢您在我需要时提供的帮助!
编写批量删除脚本时要记住的重要事项 * 您可能必须使用特定于区域的端点来删除版本(检查存储桶位置)* 您必须删除所有版本和 DeleteMarkers跨度>
【参考方案7】:
对于那些通过~/.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()
【讨论】:
感谢您的 Pythonic 回答。适用于数百万个对象(尽管您必须长时间打开它)。而且由于 python 是交互式的,所以感觉就像一个 CLI 答案;) 您也可以使用 cli 将配置文件作为选项传递 -aws s3api delete-objects --profile <my_profile> --bucket <my_bucket> --delete "$(aws s3api list-object-versions --bucket <my_bucket> | jq -M 'Objects: [.["Versions","DeleteMarkers"][]|select(.Key == "key-value")| Key:.Key, VersionId : .VersionId], Quiet: false')"
我也可以指定前缀级别吗?
@VishalGori 有没有办法像 aws s3 rm 那样打印正在删除的内容?我正在运行这个 pyscript 但不知道程序是在运行还是卡住了。【参考方案8】:
如果您想要纯 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
【讨论】:
如何只过滤那些有删除标记并删除那些?【参考方案9】:我遇到了Abe's solution 的问题,因为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 噩梦的人!
【讨论】:
感谢您提供的示例,这帮助了我,一件事是在 for 循环之后缺少最终的 bucket.delete_keys(keys) 以根据您的批处理逻辑捕获任何落后者。【参考方案10】:-
要删除指定对象,请使用 jq 过滤器。
您可能需要清理“DeleteMarkers”而不仅仅是“版本”。
使用
$()
代替``
,您可以为bucket-name 和key-value 嵌入变量。
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')"
【讨论】:
这个 oneliner(以及上面的 ***.com/a/31086407/465684 )看起来和工作得很好,但它们不适合要删除的对象超过 1000 个的情况(s3api delete 的硬限制-对象调用)。 @tiger-peng 收到错误“调用 DeleteObjects 操作时发生错误 (MalformedXML):您提供的 XML 格式不正确或未针对我们发布的架构进行验证”。知道发生了什么吗? @MarcellodeSales,如果您可以分享您使用的命令,我可能会尝试检查一下。 我正在将下面的解决方案与 Python 一起使用...我放弃了 aws cli【参考方案11】:我为 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
【讨论】:
最好的答案 ^ 我支持这个【参考方案12】:尽管从技术上讲它不是 AWS CLI,但我还是建议使用 AWS Tools for Powershell 来完成此任务。然后你可以使用如下简单的命令:
Remove-S3Bucket -BucketName bucket-name -DeleteBucketContent -Force -Region region
如文档中所述,DeleteBucketContent 标志执行以下操作:
"如果设置,则桶中所有剩余的对象和/或对象版本 被删除 proir (sic) 到被删除的存储桶本身"
参考:https://docs.aws.amazon.com/powershell/latest/reference/
【讨论】:
这个解决方案实际上比其他解决方案好得多。也就是说,因为我们现在有可以在跨平台 Powershell 上运行的 Powershell 工具,所以这是删除我的存储桶的最快解决方案。一旦我今晚晚些时候可以奖励它,这将收到我的赏金。 @ThomasWard 谢谢你的赏金。我很感激。 嗯,您的答案是唯一一个不仅包括删除存储桶的机制,而且还包括一种直接集成到命令中的方式来清除所有内容和版本。其他解决方案都不起作用 - 即使是 aws s3api 调用也不起作用,它们在“必须删除所有版本”上硬爆,清空存储桶也没有帮助,所以这是唯一真正适合我的解决方案。【参考方案13】:如果您必须删除/清空大型 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
【讨论】:
这是一个聪明的主意:D【参考方案14】:目前看来,AWS S3 控制台中有一个 Empty
按钮。
只需选择您的存储桶并单击它。它会要求您输入permanently delete
来确认您的决定
请注意,这不会删除存储桶本身。
【讨论】:
我相信这不适用于过期的存储桶。在执行此操作之前,请在一个小桶上进行测试。否则你会花几个小时在这上面而没有意识到问题。【参考方案15】:这个 bash 脚本在这里找到:https://gist.github.com/weavenet/f40b09847ac17dd99d16
按原样为我工作。
我将脚本保存为:delete_all_versions.sh 然后简单地运行:
./delete_all_versions.sh my_foobar_bucket
而且没有任何缺陷。
不需要 python 或 boto 什么的。
【讨论】:
【参考方案16】:您可以使用生命周期规则从 AWS 控制台执行此操作。
打开有问题的存储桶。单击顶部的管理选项卡。 确保选择了生命周期子选项卡。 点击 + 添加生命周期规则
在第 1 步(名称和范围)输入规则名称(例如 removeall) 单击第 2 步(转换)旁边的下一步 保持原样,然后单击下一步。
您现在处于 3. 到期步骤。 选中当前版本和以前版本的复选框。 单击“使对象的当前版本过期”复选框,并在“对象创建后 _____ 天后”输入数字 1 单击“永久删除以前的版本”复选框并输入数字 1 “在成为旧版本后 _____ 天”
点击“清理不完整的分段上传”复选框 并为“上传开始后____天后”输入数字 1 点击下一步 回顾一下你刚刚做了什么。 点击保存
过一天回来看看它的效果如何。
【讨论】:
【参考方案17】:我发现其他答案要么不完整,要么需要安装外部依赖项(如 boto),所以这里有一个受这些启发但更深入的答案。
如Working with Delete Markers 中所述,在删除版本化存储桶之前,必须完全删除其所有版本,这是一个两步过程:
-
“删除”存储桶中的所有版本对象,将它们标记为
删除但实际上并没有删除它们
通过删除所有删除标记对象完成删除
这是对我有用的纯 CLI 解决方案(受其他答案的启发):
#!/usr/bin/env bash
bucket_name=...
del_s3_bucket_obj()
local bucket_name=$1
local obj_type=$2
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 多个对象,如果有人可以报告那将是很棒的。
【讨论】:
【参考方案18】:到目前为止,我发现的最简单的方法是使用这个 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://github.com/slmingol/s3wipe Is there a way to export an AWS CLI Profile to Environment Variables? https://cloud.docker.com/u/slmingol/repository/docker/slmingol/s3wipe【讨论】:
这个想法看起来很有希望,但我收到以下错误:ERROR: S3ResponseError: 400 Bad Request
出于某种原因。此外,aws configure get default.aws_access_key_id
不起作用,因此我必须手动传递凭据。【参考方案19】:
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 || "$1" != --bucket ]]; then
echo -e "USAGE: $(basename "$0") --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。
【讨论】:
【参考方案20】:这对我有用。也许运行更高版本的东西及以上> 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!
【讨论】:
【参考方案21】:要添加到此处提供的 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
帮我删除了法兰克福地区的存储桶。
原答案:https://***.com/a/41200567/2586441
【讨论】:
【参考方案22】:您可以使用 aws-cli 删除 s3 存储桶
aws s3 rb s3://your-bucket-name
如果您的计算机中没有安装 aws cli,您可以使用以下命令: 对于 Linux 或 ubuntu:
sudo apt-get install aws-cli
然后检查是否安装:
aws --version
现在通过提供 aws-access-credentials 对其进行配置
aws 配置
然后给出访问密钥和秘密访问密钥以及您所在的地区
【讨论】:
【参考方案23】:我使用 Python3 和 argv 改进了 the boto3 answer。
-
将以下脚本另存为
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()
-
添加
chmod +x s3_rm.py
。
像./s3_rm.py my_bucket_name
一样运行函数。
【讨论】:
以上是关于如何使用 CLI 删除 AWS S3 中的版本化存储桶?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 AWS CLI 找到我的 AWS S3 存储桶的确切字节数?