防止已取消接管的命名空间在集群离线时被驱逐删除

概述

当 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 "=== 监控完成 ==="

故障排除

常见问题

  1. 无法找到相关的 Binding 对象

    1
    2
    
    # 检查是否存在 ResourceBinding(命名空间级别)
    kubectl get resourcebindings --all-namespaces | grep <namespace-name>
  2. suppressDeletion 设置不生效

    1
    2
    
    # 检查 GracefulEviction FeatureGate 是否启用
    kubectl get configmap karmada-config -n karmada-system -o yaml | grep -i graceful
  3. 成员集群上仍有 Karmada 注解

    1
    2
    
    # 在成员集群上检查命名空间注解
    kubectl get namespace <namespace-name> -o yaml | grep -A 10 annotations

紧急恢复

如果命名空间已经被误删除,可以尝试以下恢复步骤:

  1. 从备份恢复(如果有的话)
  2. 重新创建命名空间并清理 Karmada 相关标记
  3. 检查并修复相关应用

最佳实践

  1. 预防性设置:在取消资源接管时,立即设置 suppressDeletion: true
  2. 定期监控:使用监控脚本定期检查保护状态
  3. 文档记录:记录哪些命名空间已设置保护以及原因
  4. 测试验证:在非生产环境中测试驱逐保护机制
  5. 备份策略:确保有完整的集群备份策略

注意事项

  1. FeatureGate 依赖suppressDeletion 功能需要启用 GracefulEviction FeatureGate
  2. 永久保护:设置 suppressDeletion: true 后,需要手动干预才能移除保护
  3. 资源清理:如果将来需要完全移除资源,需要先将 suppressDeletion 设置为 false
  4. 集群状态:确保 Karmada 控制平面正常运行,否则保护机制可能不生效
  5. 权限要求:操作需要适当的 RBAC 权限来修改 Binding 对象

相关资源

0%