k8s 클러스터의 YAML 파일 기반 백업 및 복원

1. 필요한 도구 설치

데이터를 JSON 형식으로 내보낸 후, 불필요한 필드를 삭제하고 yq를 통해 YAML 형식으로 변환합니다. 이 작업은 YAML 파일로 내보낼 때 특정 필드를 필터링하는 방법을 모를 때 유용합니다.

[root@k8s-master test]# yum install jq -y  # JSON 파싱
[root@k8s-master ~]# curl -LO https://github.com/mikefarah/yq/releases/download/v4.34.1/yq_linux_amd64  # 최신 버전 다운로드
[root@k8s-master ~]# chmod +x yq_linux_amd64
[root@k8s-master ~]# mv yq_linux_amd64 /usr/bin/yq
[root@k8s-master ~]# yq --version
yq (https://github.com/mikefarah/yq/) version 4.34.1

2. 스크립트 작성

V1.13 버전

아래는 Kubernetes 리소스를 YAML 파일로 백업하는 Bash 스크립트입니다.

#!/bin/bash

CURRENT_TIME=$(date +%Y%m%d%H%M%S)  # 시간 기반 디렉토리 생성
BACKUP_PATH=/tmp/k8s-backup-restore  # 백업 경로

NAMESPACE_LIST="change-battery-demo nginx-ingress-port tools tsp"  # 백업할 네임스페이스 목록
RESOURCE_TYPES="service deployment ingress"  # 백업할 리소스 타입

for namespace in ${NAMESPACE_LIST}; do
    TARGET_DIR="${BACKUP_PATH}/${namespace}/${CURRENT_TIME}"  # 네임스페이스별 백업 디렉토리
    mkdir -p "${TARGET_DIR}" && cd "${TARGET_DIR}"
    
    for resource in ${RESOURCE_TYPES}; do
        item_count=$(kubectl get "${resource}" -n "${namespace}" 2>/dev/null | wc -l)
        
        if [ "${item_count}" -lt 2 ]; then continue; fi  # 리소스가 없는 경우 건너뜀
        
        ITEMS=$(kubectl get "${resource}" -n "${namespace}" -o custom-columns=NAME:.metadata.name --no-headers)
        
        for item in ${ITEMS}; do
            FILE_NAME="${TARGET_DIR}/${resource}_${item}.yaml"
            
            kubectl get "${resource}" "${item}" -n "${namespace}" -o=json | \
            jq 'del(
                .spec.clusterIP,
                .metadata.uid,
                .metadata.selfLink,
                .metadata.resourceVersion,
                .metadata.creationTimestamp,
                .metadata.generation,
                .metadata.annotations,
                .status
            )' | yq eval -P > "${FILE_NAME}"
        done
    done
done

V1.22 버전

다음은 보다 고급 기능을 포함한 업데이트된 스크립트입니다.

#!/bin/bash

CURRENT_TIME=$(date +%Y-%m-%d-%H-%M-%S)  # 현재 시간 기반 이름 설정
BASE_BACKUP_PATH="/mnt/k8s-backup-restore"  # 기본 백업 경로
CURRENT_BACKUP_PATH="${BASE_BACKUP_PATH}/${CURRENT_TIME}"  # 실제 백업 경로
SCRIPT_DIR="$(cd "$(dirname "$0")"; pwd)"  # 스크립트 위치

# 백업 대상 네임스페이스 목록
NAMESPACE_LIST=$(kubectl get namespaces -o jsonpath='{.items[?(@.status.phase=="Active")].metadata.name}' | \
    grep -vE 'ahas|ahas-sentinel-pilot|arms-pilot|arms-prom|edas-oam-system|kube-public|kube-node-lease|kube-system')

RESOURCE_TYPES="svc deploy ingress cm secret statefulset"  # 백업할 리소스 타입

# 필터링 로직 정의
FILTER_CM='del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp)'
FILTER_SECRET='del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp)'
FILTER_SVC='del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, .status, .spec.clusterIP)'
FILTER_DEPLOY='del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, .status)'
FILTER_STATEFULSET='del(.metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, .status)'

backup_to_yaml() {
    for ns in ${NAMESPACE_LIST}; do
        TARGET_DIR="${CURRENT_BACKUP_PATH}/${ns}"
        mkdir -p "${TARGET_DIR}" && cd "${TARGET_DIR}"

        for resource in ${RESOURCE_TYPES}; do
            item_count=$(kubectl get "${resource}" -n "${ns}" 2>/dev/null | wc -l)

            if [ "${item_count}" -lt 2 ]; then continue; fi

            ITEMS=$(kubectl get "${resource}" -n "${ns}" -o custom-columns=NAME:.metadata.name --no-headers)

            for item in ${ITEMS}; do
                FILE_NAME="${TARGET_DIR}/${resource}_${item}.yaml"

                FILTER_LOGIC=""
                case "${resource}" in
                    "cm") FILTER_LOGIC="${FILTER_CM}";;
                    "secret") FILTER_LOGIC="${FILTER_SECRET}";;
                    "svc") FILTER_LOGIC="${FILTER_SVC}";;
                    "deploy") FILTER_LOGIC="${FILTER_DEPLOY}";;
                    "statefulset") FILTER_LOGIC="${FILTER_STATEFULSET}";;
                esac

                kubectl get "${resource}" "${item}" -n "${ns}" -o=json | jq "${FILTER_LOGIC}" | yq eval -P > "${FILE_NAME}"
            done
        done
    done
}

archive_and_upload() {
    ARCHIVE_FILE="k8s-backup-${CURRENT_TIME}.tar.gz"
    tar -czf "${ARCHIVE_FILE}" -C "${BASE_BACKUP_PATH}" "${CURRENT_TIME}" &>/dev/null

    if [[ -s "${ARCHIVE_FILE}" ]]; then
        python3 "${SCRIPT_DIR}/oss_upload.py" "k8s_backup/${ARCHIVE_FILE}" "${BASE_BACKUP_PATH}/${ARCHIVE_FILE}"
    fi
}

main() {
    backup_to_yaml
    archive_and_upload
}

main

OSS에 업로드하기 위한 Python 스크립트

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import oss2
import sys

OSS_FILE_NAME = sys.argv[1]
LOCAL_FILE_NAME = sys.argv[2]

auth = oss2.Auth('YOUR_ACCESS_KEY_ID', 'YOUR_ACCESS_KEY_SECRET')
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'YOUR_BUCKET_NAME')

bucket.put_object_from_file(OSS_FILE_NAME, LOCAL_FILE_NAME)

생성된 디렉토리 구조는 다음과 같습니다:

root@tsp-prod-ansible:~/script_dir# tree -L 3 /mnt
/mnt/
└── k8s-backup-restore
    ├── 2022-11-10-14-24-01
    │   ├── bmp-prd
    │   ├── change-battery-demo
    │   ├── default
    │   ├── mk1-prod
    │   ├── mk1-website

태그: kubernetes jq yq

6월 28일 18:24에 게시됨