前言 在 Kubernetes 集群中使用 Velero 进行备份时,遇到了 BackupStorageLocation 一直处于 Unavailable 状态的问题,导致备份任务无法执行。本文详细记录了从问题发现到最终解决的完整排查过程,涉及多个常见的配置陷阱和已知 Bug,希望能为遇到类似问题的朋友提供参考。
环境信息
Kubernetes 版本 : v1.32.0
Velero 版本 : v1.17.1
Velero AWS 插件版本 : v1.1.0(初始)→ v1.10.0(最终)
对象存储 : 腾讯云 COS(兼容 S3 协议)
存储桶 : backup-1356016796
地域 : ap-guangzhou(广州)
问题现象 初始错误 执行备份命令后,BackupStorageLocation 一直显示 Unavailable:
1 2 3 4 5 6 $ velero backup create gitea-backup --include-namespaces app-codehub -n kube-backup Backup request "gitea-backup" submitted successfully. $ velero backup describe gitea-backup -n kube-backup Phase: FailedValidation Validation errors: backup can't be created because BackupStorageLocation default is in Unavailable status.
BSL 状态检查 1 2 3 $ kubectl -n kube-backup get backupstoragelocation default NAME PHASE LAST VALIDATED AGE default Unavailable 35s 72m
排查过程 第一阶段:凭证问题(NoCredentialProviders) 错误信息 1 rpc error: code = Unknown desc = NoCredentialProviders: no valid providers in chain.
问题分析 Velero 无法找到访问对象存储的凭证(AccessKey/SecretKey)。
排查步骤
检查 Secret 是否存在
1 $ kubectl -n kube-backup get secret cloud-credentials -o yaml
验证 Secret 内容格式
1 2 3 4 $ kubectl -n kube-backup get secret cloud-credentials -o jsonpath='{.data.cloud}' | base64 -d [default] aws_access_key_id=AKID... aws_secret_access_ke=tZ1FJ...
发现问题 :Secret 中的键名拼写错误,应该是 aws_secret_access_key 而不是 aws_secret_access_ke。
修正 Secret
创建正确格式的凭证文件:
1 2 3 4 5 6 7 8 9 cat > ./credentials <<EOF [default] aws_access_key_id = <YOUR_ACCESS_KEY> aws_secret_access_key = <YOUR_SECRET_KEY> EOF kubectl -n kube-backup create secret generic cloud-credentials \ --from-file=cloud=./credentials \ -o yaml --dry-run=client | kubectl apply -f -
关联 Secret 到 BSL
1 2 3 4 5 6 7 8 kubectl -n kube-backup patch backupstoragelocation default --type ='merge' -p '{ "spec": { "credential": { "name": "cloud-credentials", "key": "cloud" } } }'
结果 凭证问题解决,但 BSL 仍然 Unavailable,出现新的错误。
第二阶段:配置键冲突(credentialsFile) 错误信息 1 config has invalid keys [credentialsFile]
问题分析 这是 velero-plugin-for-aws v1.1.0 的已知 Bug :
当 BSL 使用 spec.credential 字段指定凭证时,插件内部会错误地将 credentialsFile 当作 config 的一部分进行校验
尽管 BSL 的 spec.config 中实际不包含 credentialsFile,但插件仍报此错误
该 Bug 在 v1.2.0+ 版本中已修复
解决方案选择 方案一(推荐) :升级插件到 v1.10.0
1 2 3 kubectl -n kube-backup edit deployment velero
方案二(临时) :通过环境变量传递凭证(不使用 spec.credential)
由于我们选择了方案一,升级插件后继续排查。
第三阶段:S3 访问风格问题(PathStyleDomainForbidden) 错误信息 1 api error PathStyleDomainForbidden: The bucket you are attempting to access must be addressed using COS virtual-styled domain .
问题分析 腾讯云 COS 不支持 S3 的 path-style 访问方式,必须使用 virtual-hosted-style 。
两种访问风格对比:
访问方式
URL 格式
说明
Path-style
https://cos.ap-guangzhou.myqcloud.com/backup-1356016796/...
bucket 在路径中
Virtual-hosted-style
https://backup-1356016796.cos.ap-guangzhou.myqcloud.com/...
bucket 作为子域名
解决方案 删除 s3ForcePathStyle 配置:
1 2 3 kubectl -n kube-backup patch backupstoragelocation default --type ='json' -p='[ {"op": "remove", "path": "/spec/config/s3ForcePathStyle"} ]'
结果 出现新的错误:404 NoSuchKey 或证书验证失败。
第四阶段:URL 配置错误(重复拼接 bucket 名称) 错误信息 1 2 Get "https://backup-1356016796.backup-1356016796.cos.ap-guangzhou.myqcloud.com/..." : tls: failed to verify certificate: x509: certificate is valid for *. cos.ap-guangzhou .myqcloud .com , not backup-1356016796 .backup-1356016796 .cos .ap-guangzhou .myqcloud .com
问题分析 关键发现 :URL 中 bucket 名称被重复拼接了两次!
1 2 3 backup-1356016796.backup-1356016796.cos.ap-guangzhou.myqcloud. com ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ 第一次 第二次(错误)
根本原因 :
s3Url 中已包含 bucket 名称:https://backup-1356016796.cos.ap-guangzhou.myqcloud.com
Velero 插件会根据 spec.objectStorage.bucket 再次拼接 bucket 名称
最终 URL 变成:backup-1356016796.backup-1356016796.cos...
证书只覆盖 *.cos.ap-guangzhou.myqcloud.com,因此验证失败
正确的配置方式 s3Url 应该指向 COS 的通用 endpoint(不包含 bucket 名称) :
1 2 3 4 5 6 7 8 kubectl -n kube-backup patch backupstoragelocation default --type ='merge' -p '{ "spec": { "config": { "region": "ap-guangzhou", "s3Url": "https://cos.ap-guangzhou.myqcloud.com" } } }'
Velero 会自动将 spec.objectStorage.bucket 拼接到 s3Url 前面,生成正确的虚拟托管域名:
1 backup-1356016796 .cos .ap-guangzhou . myqcloud.com
最终解决方案 完整的 BSL 配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: velero. io/v1 kind: BackupStorageLocation metadata: name: default namespace: kube-backup spec: provider: aws objectStorage: bucket: backup-1356016796 config: region: ap-guangzhou s3Url: https://cos.ap-guangzhou.myqcloud.com credential: name: cloud-credentials key: cloud default: true
正确的 Velero 安装命令 1 2 3 4 5 6 7 8 9 velero install \ --provider aws \ --plugins velero/velero-plugin-for-aws:v1.10.0 \ --bucket backup-1356016796 \ --secret-file /etc/velero/credentials-velero \ --use-node-agent \ --uploader-type kopia \ --backup-location-config region=ap-guangzhou,s3Url=https://cos.ap-guangzhou.myqcloud.com \ --namespace kube-backup
关键参数说明:
--plugins: 使用 v1.10.0 或更高版本(避免 credentialsFile bug)
--use-node-agent: 替代已废弃的 --use-restic
--uploader-type kopia: Velero v1.17+ 推荐使用 kopia(性能更好)
s3Url: 使用 COS 通用 endpoint,不包含 bucket 名称
不要 添加 s3ForcePathStyle=true
Secret 格式 1 2 3 [default] aws_access_key_id = <YOUR_ACCESS_KEY>aws_secret_access_key = <YOUR_SECRET_KEY>
注意事项:
键名必须精确匹配:aws_access_key_id 和 aws_secret_access_key
等号两侧可以有空格
确保没有拼写错误
验证步骤 1. 检查 BSL 状态 1 2 3 $ kubectl -n kube-backup get backupstoragelocation default NAME PHASE LAST VALIDATED AGE default Available 10s 3h
✅ Phase 应该为 Available
2. 查看详细信息 1 2 $ kubectl -n kube-backup describe backupstoragelocation default
3. 测试备份 1 2 3 4 5 $ velero backup create test-backup --include-namespaces default -n kube-backup Backup request "test-backup" submitted successfully. $ velero backup describe test-backup -n kube-backup Phase: Completed
4. 验证备份文件已上传到 COS 登录腾讯云控制台,检查 bucket backup-1356016796 中是否有备份文件。
经验总结 常见错误配置对比
错误配置
正确配置
说明
s3Url: https://backup-xxx.cos.ap-guangzhou. myqcloud.com
s3Url: https://cos.ap-guangzhou.myqcloud.com
s3Url 不应包含 bucket 名称
s3ForcePathStyle: "true"
删除此配置项
腾讯云 COS 不支持 path-style
aws_secret_access_ke=xxx
aws_secret_access_key=xxx
键名必须完整正确
缺少 credential 字段
必须指定 credential.name 和 credential.key
否则无法读取凭证
排查技巧
查看 BSL 状态和错误信息
1 kubectl -n kube-backup describe backupstoragelocation default
查看 Velero 日志
1 kubectl -n kube-backup logs deployment/velero --tail =200
检查 Secret 格式
1 kubectl -n kube-backup get secret cloud-credentials -o jsonpath='{.data.cloud}' | base64 -d
验证 BSL 配置
1 kubectl -n kube-backup get backupstoragelocation default -o yaml
测试网络连通性 (从 Velero Pod 内部)
1 kubectl -n kube-backup exec deployment/velero -- curl -I https://cos.ap-guangzhou.myqcloud.com
版本选择建议
组件
推荐版本
原因
Velero
v1.12+
稳定且功能完善
velero-plugin-for-aws
v1.10.0+
修复了 credentialsFile bug
uploader
kopia
比 restic 性能更好(Velero v1.12+)
参考资源
附录:完整排查脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #!/bin/bash NAMESPACE="kube-backup" BSL_NAME="default" echo "=== 1. BSL 状态 ===" kubectl -n $NAMESPACE get backupstoragelocation $BSL_NAME echo -e "\n=== 2. BSL 详细信息 ===" kubectl -n $NAMESPACE describe backupstoragelocation $BSL_NAME echo -e "\n=== 3. BSL 配置 ===" kubectl -n $NAMESPACE get backupstoragelocation $BSL_NAME -o yamlecho -e "\n=== 4. Secret 检查 ===" kubectl -n $NAMESPACE get secret cloud-credentials -o jsonpath='{.data.cloud}' | base64 -decho -e "\n=== 5. Velero Pod 状态 ===" kubectl -n $NAMESPACE get pods -l component=veleroecho -e "\n=== 6. Velero 日志(最近 50 行) ===" kubectl -n $NAMESPACE logs deployment/velero --tail =50echo -e "\n=== 7. 插件版本 ===" kubectl -n $NAMESPACE get deployment velero -o jsonpath='{.spec.template.spec.initContainers[*].image}' echo ""
后记 这次排查过程涉及多个层面的问题:
凭证配置 :Secret 格式和引用
插件 Bug :旧版本插件的已知问题
对象存储协议 :S3 兼容性细节(path-style vs virtual-hosted-style)
URL 拼接逻辑 :理解 Velero 如何构造最终访问 URL
通过系统性的排查,逐步缩小问题范围,最终定位到根本原因。希望这篇文章能帮助遇到类似问题的朋友快速解决问题。
如果您在使用 Velero 时遇到其他问题,欢迎留言交流!
更新日志:
2025-12-15:初稿发布,记录完整排查过程, 由AI总结,暂未review