这个问题其实比较有意思,同事早上用k9s修改Deployment的时候误删了一个deployment,这下麻烦了。那其实自己也有过类似操作,迁移的时候误删过influxdb,最后考古才弄回来,也误删过一个ns的secret,都是大麻烦!

其实系统是有velero备份的,但是从那里面去弄出单独一个ns的deploy进行恢复,怎么也来不及,那幸好有每日资源备份,直接拿过来重建即可。分享一下脚本,那注意一下,因为主节点的etcd也是非常要命的东西,也必须备一下,防止主节点脑裂,到时候可以用备份进行恢复。

#!/bin/bash

export KUBECONFIG=/root/.kube/config
export PATH=/usr/local/bin:$PATH

# K8s 资源备份脚本
# 目标:遍历所有命名空间,将 Deployment, Secret, Ingress, 和 Service 导出为 YAML 文件。

# 设置输出目录
OUTPUT_DIR="/root/k8s_deployments_backup/$(date +%Y%m%d)"
# 要备份的资源类型及其对应的 kubectl 别名
# 注意:Secret 资源会备份所有类型,包括自动生成的 Service Account Tokens。
RESOURCE_TYPES=("deployments" "secrets" "ingresses" "services")

# 确保脚本在遇到错误时立即退出
set -e

echo "--- 正在创建输出目录: $OUTPUT_DIR ---"
mkdir -p "$OUTPUT_DIR"

# ----------------------------------------------------
# 核心函数:备份指定类型的资源
# 参数: $1 = 资源类型 (如 deployment), $2 = 命名空间, $3 = 输出目录
# ----------------------------------------------------
backup_resource() {
    local TYPE=$1
    local NAMESPACE=$2
    local DIR=$3

    # 获取当前命名空间中所有该类型资源的名称
    # 使用 2>/dev/null 隐藏找不到资源时的错误信息
    local RESOURCES=$(kubectl get "$TYPE" -n "$NAMESPACE" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null)

    if [ -z "$RESOURCES" ]; then
        echo "  [信息] 命名空间 $NAMESPACE 中未找到 $TYPE。"
        return
    fi

    echo "  -> 找到 ${#RESOURCES[@]}$TYPE,正在导出..."

    # 遍历每个资源并保存 YAML
    for RESOURCE in $RESOURCES; do
        # 文件名格式: namespace-resource_type-resourcename.yaml
        local FILE_NAME="${NAMESPACE}-${TYPE}-${RESOURCE}.yaml"
        local FILE_PATH="$DIR/$FILE_NAME"

        # 使用 kubectl get 获取 YAML,并通过管道和 sed 清理元数据字段
        kubectl get "$TYPE" "$RESOURCE" -n "$NAMESPACE" -o yaml --ignore-not-found |
          # 清理元数据字段,使 YAML 更干净,便于重新应用
          sed '/^  creationTimestamp:/d' |
          sed '/^  resourceVersion:/d' |
          sed '/^  uid:/d' |
          sed '/^  selfLink:/d' |
          sed '/^  status:/d' \
          > "$FILE_PATH"

        # 检查 Secret 是否为 Service Account Token,如果是,则发出警告
        if [ "$TYPE" == "secrets" ] && grep -q 'kubernetes.io/service-account.name' "$FILE_PATH"; then
             echo "    [警告] Secret $RESOURCE 是 Service Account Token,通常不需要备份。"
        fi
    done
}

# 1. 获取所有命名空间 (Namespace)
NAMESPACES=$(kubectl get ns -o jsonpath='{.items[*].metadata.name}')

if [ -z "$NAMESPACES" ]; then
    echo "错误:未找到任何命名空间。请检查 kubectl 配置和集群连接。"
    exit 1
fi

echo "找到以下命名空间: $NAMESPACES"
echo "----------------------------------------------------"

# 2. 遍历每个命名空间和资源类型
for NAMESPACE in $NAMESPACES; do
    echo "--- 处理命名空间: $NAMESPACE ---"
    
    for TYPE in "${RESOURCE_TYPES[@]}"; do
        backup_resource "$TYPE" "$NAMESPACE" "$OUTPUT_DIR"
    done
    
    echo "--- 命名空间 $NAMESPACE 处理完成 ---"
done

ETCDCTL_API=3 etcdctl \
--endpoints=https://10.10.240.3:2379 \
--cacert=/etc/ssl/etcd/ca.pem \
--cert=/etc/ssl/etcd/etcd-client.pem \
--key=/etc/ssl/etcd/etcd-client-key.pem \
snapshot save $OUTPUT_DIR/etcd-`date +%Y%m%d`-snapshot.db

echo "===================================================="
echo "✅ 所有指定资源已成功备份到目录: $OUTPUT_DIR"
echo "===================================================="

exit 0