概述
当 Karmada 中的 ClusterPropagationPolicy 被删除或修改以取消对命名空间的资源接管后,成员集群上可能仍然存在相关的 Karmada 注解和标签。在成员集群离线时,这些命名空间可能会被 Karmada 的驱逐机制误删除。本文档提供了多种解决方案来防止这种情况发生。
前提条件
- Karmada 集群正常运行
- 具有集群管理员权限
- 了解基本的 kubectl 操作
- 如果使用 SuppressDeletion 机制,需要启用
GracefulEviction FeatureGate
解决方案
方案一:使用 SuppressDeletion 机制(推荐)
这是最安全和可靠的方法,通过设置 suppressDeletion: true 来永久阻止资源被删除。
1. 检查当前的 Binding 对象
1
2
3
4
5
| # 查看 ClusterResourceBinding(针对集群级资源如命名空间)
kubectl get clusterresourcebindings -o yaml | grep -A 20 -B 5 "gracefulEvictionTasks"
# 或查看 ResourceBinding(针对命名空间级资源)
kubectl get resourcebindings -n <namespace> -o yaml | grep -A 20 -B 5 "gracefulEvictionTasks"
|
2. 查找特定命名空间的 Binding
1
2
3
4
5
| # 查找命名空间相关的 ClusterResourceBinding
kubectl get clusterresourcebindings -o custom-columns=NAME:.metadata.name,RESOURCE:.spec.resource.name,KIND:.spec.resource.kind | grep -i namespace
# 查找特定命名空间的 binding
kubectl get clusterresourcebindings -o json | jq -r '.items[] | select(.spec.resource.kind=="Namespace" and .spec.resource.name=="<namespace-name>") | .metadata.name'
|
3. 手动设置 suppressDeletion
如果发现存在 gracefulEvictionTasks,可以手动编辑来设置保护:
1
2
3
4
5
| # 编辑 ClusterResourceBinding
kubectl edit clusterresourcebinding <binding-name>
# 或编辑 ResourceBinding
kubectl edit resourcebinding <binding-name> -n <namespace>
|
在编辑器中找到 gracefulEvictionTasks 部分,为相关任务添加 suppressDeletion: true:
1
2
3
4
5
6
7
| spec:
gracefulEvictionTasks:
- fromCluster: "member-cluster-name"
reason: "TaintUntolerated"
producer: "taint-manager"
suppressDeletion: true # 添加这一行
creationTimestamp: "2024-01-01T00:00:00Z"
|
4. 使用 kubectl patch 批量设置
1
2
3
4
5
6
7
8
9
10
| # 为特定的 ClusterResourceBinding 设置 suppressDeletion
kubectl patch clusterresourcebinding <binding-name> --type='merge' -p='{
"spec": {
"gracefulEvictionTasks": [
{
"suppressDeletion": true
}
]
}
}'
|
方案二:完全清理 Binding 对象
如果确认不再需要 Karmada 管理这些命名空间,可以直接删除相关的 Binding 对象:
1
2
3
4
5
| # 删除特定的 ClusterResourceBinding
kubectl delete clusterresourcebinding <binding-name>
# 批量删除命名空间相关的 binding
kubectl get clusterresourcebindings -o json | jq -r '.items[] | select(.spec.resource.kind=="Namespace") | .metadata.name' | xargs kubectl delete clusterresourcebinding
|
方案三:清理成员集群上的注解和标签
直接在成员集群上清理 Karmada 相关的标记:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 在成员集群上执行
# 清理命名空间上的 Karmada 注解
kubectl annotate namespace <namespace-name> \
clusterpropagationpolicy.karmada.io/name- \
clusterpropagationpolicy.karmada.io/namespace- \
clusterpropagationpolicy.karmada.io/permanent-id- \
resourcebinding.karmada.io/name- \
resourcebinding.karmada.io/namespace- \
resourcetemplate.karmada.io/uid-
# 清理 Karmada 相关标签
kubectl label namespace <namespace-name> \
clusterpropagationpolicy.karmada.io/permanent-id- \
propagationpolicy.karmada.io/permanent-id-
|
方案四:批量处理脚本
创建自动化脚本来批量处理多个命名空间:
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
28
29
30
31
32
33
34
35
36
37
38
| #!/bin/bash
# cleanup-namespace-bindings.sh
# 设置要处理的命名空间列表
NAMESPACES=("namespace1" "namespace2" "namespace3")
echo "开始清理命名空间的 Karmada 绑定..."
for ns in "${NAMESPACES[@]}"; do
echo "处理命名空间: $ns"
# 查找相关的 ClusterResourceBinding
bindings=$(kubectl get clusterresourcebindings -o json | jq -r ".items[] | select(.spec.resource.kind==\"Namespace\" and .spec.resource.name==\"$ns\") | .metadata.name")
for binding in $bindings; do
echo " 找到 ClusterResourceBinding: $binding"
# 检查是否有 gracefulEvictionTasks
has_tasks=$(kubectl get clusterresourcebinding $binding -o jsonpath='{.spec.gracefulEvictionTasks}' 2>/dev/null)
if [[ -n "$has_tasks" && "$has_tasks" != "null" ]]; then
echo " 设置 suppressDeletion 为 true"
# 获取现有的 gracefulEvictionTasks 并添加 suppressDeletion
kubectl patch clusterresourcebinding $binding --type='json' -p='[
{
"op": "replace",
"path": "/spec/gracefulEvictionTasks/0/suppressDeletion",
"value": true
}
]'
else
echo " 删除 ClusterResourceBinding"
kubectl delete clusterresourcebinding $binding
fi
done
done
echo "清理完成"
|
使用脚本:
1
2
3
4
5
| # 给脚本执行权限
chmod +x cleanup-namespace-bindings.sh
# 执行脚本
./cleanup-namespace-bindings.sh
|
验证和监控
验证保护设置
1
2
3
4
5
6
7
8
| # 检查 ClusterResourceBinding 状态
kubectl get clusterresourcebindings -o custom-columns=NAME:.metadata.name,TASKS:.spec.gracefulEvictionTasks[*].suppressDeletion
# 检查特定命名空间的保护状态
kubectl get clusterresourcebindings -o json | jq -r '.items[] | select(.spec.resource.kind=="Namespace") | {name: .metadata.name, namespace: .spec.resource.name, suppressDeletion: .spec.gracefulEvictionTasks[].suppressDeletion}'
# 检查成员集群上的命名空间状态
kubectl get namespaces -o custom-columns=NAME:.metadata.name,ANNOTATIONS:.metadata.annotations
|
监控脚本
创建监控脚本来定期检查保护状态:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| #!/bin/bash
# monitor-namespace-protection.sh
echo "=== Karmada 命名空间保护状态监控 ==="
echo "时间: $(date)"
echo
# 检查有 suppressDeletion 保护的命名空间
echo "受保护的命名空间:"
kubectl get clusterresourcebindings -o json | jq -r '.items[] | select(.spec.resource.kind=="Namespace" and .spec.gracefulEvictionTasks[]?.suppressDeletion==true) | " - " + .spec.resource.name + " (Binding: " + .metadata.name + ")"'
echo
# 检查可能存在风险的命名空间
echo "可能存在驱逐风险的命名空间:"
kubectl get clusterresourcebindings -o json | jq -r '.items[] | select(.spec.resource.kind=="Namespace" and (.spec.gracefulEvictionTasks | length > 0) and (.spec.gracefulEvictionTasks[]?.suppressDeletion!=true)) | " - " + .spec.resource.name + " (Binding: " + .metadata.name + ")"'
echo
echo "=== 监控完成 ==="
|
故障排除
常见问题
无法找到相关的 Binding 对象
1
2
| # 检查是否存在 ResourceBinding(命名空间级别)
kubectl get resourcebindings --all-namespaces | grep <namespace-name>
|
suppressDeletion 设置不生效
1
2
| # 检查 GracefulEviction FeatureGate 是否启用
kubectl get configmap karmada-config -n karmada-system -o yaml | grep -i graceful
|
成员集群上仍有 Karmada 注解
1
2
| # 在成员集群上检查命名空间注解
kubectl get namespace <namespace-name> -o yaml | grep -A 10 annotations
|
紧急恢复
如果命名空间已经被误删除,可以尝试以下恢复步骤:
- 从备份恢复(如果有的话)
- 重新创建命名空间并清理 Karmada 相关标记
- 检查并修复相关应用
最佳实践
- 预防性设置:在取消资源接管时,立即设置
suppressDeletion: true - 定期监控:使用监控脚本定期检查保护状态
- 文档记录:记录哪些命名空间已设置保护以及原因
- 测试验证:在非生产环境中测试驱逐保护机制
- 备份策略:确保有完整的集群备份策略
注意事项
- FeatureGate 依赖:
suppressDeletion 功能需要启用 GracefulEviction FeatureGate - 永久保护:设置
suppressDeletion: true 后,需要手动干预才能移除保护 - 资源清理:如果将来需要完全移除资源,需要先将
suppressDeletion 设置为 false - 集群状态:确保 Karmada 控制平面正常运行,否则保护机制可能不生效
- 权限要求:操作需要适当的 RBAC 权限来修改 Binding 对象
相关资源