前言

在 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)。

排查步骤

  1. 检查 Secret 是否存在
1
$ kubectl -n kube-backup get secret cloud-credentials -o yaml
  1. 验证 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... # ❌ 注意:这里少了一个 'y'

发现问题:Secret 中的键名拼写错误,应该是 aws_secret_access_key 而不是 aws_secret_access_ke

  1. 修正 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 -
  1. 关联 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]; valid keys are [region s3Url publicUrl kmsKeyId s3ForcePathStyle signatureVersion profile serverSideEncryption insecureSkipTLSVerify bucket prefix caCert]

问题分析

这是 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
# 将 initContainers 中的镜像版本改为:
# image: velero/velero-plugin-for-aws:v1.10.0

方案二(临时):通过环境变量传递凭证(不使用 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
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
第一次 第二次(错误)

根本原因

  1. s3Url 中已包含 bucket 名称:https://backup-1356016796.cos.ap-guangzhou.myqcloud.com
  2. Velero 插件会根据 spec.objectStorage.bucket 再次拼接 bucket 名称
  3. 最终 URL 变成:backup-1356016796.backup-1356016796.cos...
  4. 证书只覆盖 *.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
# 注意:不要设置 s3ForcePathStyle
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_idaws_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.namecredential.key 否则无法读取凭证

排查技巧

  1. 查看 BSL 状态和错误信息

    1
    kubectl -n kube-backup describe backupstoragelocation default
  2. 查看 Velero 日志

    1
    kubectl -n kube-backup logs deployment/velero --tail=200
  3. 检查 Secret 格式

    1
    kubectl -n kube-backup get secret cloud-credentials -o jsonpath='{.data.cloud}' | base64 -d
  4. 验证 BSL 配置

    1
    kubectl -n kube-backup get backupstoragelocation default -o yaml
  5. 测试网络连通性(从 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
# Velero BSL 状态诊断脚本

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 yaml

echo -e "\n=== 4. Secret 检查 ==="
kubectl -n $NAMESPACE get secret cloud-credentials -o jsonpath='{.data.cloud}' | base64 -d

echo -e "\n=== 5. Velero Pod 状态 ==="
kubectl -n $NAMESPACE get pods -l component=velero

echo -e "\n=== 6. Velero 日志(最近 50 行) ==="
kubectl -n $NAMESPACE logs deployment/velero --tail=50

echo -e "\n=== 7. 插件版本 ==="
kubectl -n $NAMESPACE get deployment velero -o jsonpath='{.spec.template.spec.initContainers[*].image}'
echo ""

后记

这次排查过程涉及多个层面的问题:

  1. 凭证配置:Secret 格式和引用
  2. 插件 Bug:旧版本插件的已知问题
  3. 对象存储协议:S3 兼容性细节(path-style vs virtual-hosted-style)
  4. URL 拼接逻辑:理解 Velero 如何构造最终访问 URL

通过系统性的排查,逐步缩小问题范围,最终定位到根本原因。希望这篇文章能帮助遇到类似问题的朋友快速解决问题。

如果您在使用 Velero 时遇到其他问题,欢迎留言交流!


更新日志:

  • 2025-12-15:初稿发布,记录完整排查过程, 由AI总结,暂未review