1. ๊ฐœ์š”

Kubernetes ํด๋Ÿฌ์Šคํ„ฐ์—์„œ etcd๋Š” ๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ ์ƒํƒœ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ํ•ต์‹ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‹ค. etcd ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚ ์•„๊ฐ€๋ฉด ํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด๋ฅผ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋Š” ์น˜๋ช…์ ์ธ ์ƒํ™ฉ์ด ์˜จ๋‹ค.

์˜ˆ์ „์— ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด์„œ etcd๋ฅผ ๋ฐฑ์—…ํ•˜์ง€ ์•Š์€ ์ฑ„ ๋…ธ๋“œ join์„ ํ•˜๋‹ค๊ฐ€ etcd ํด๋Ÿฌ์Šคํ„ฐ ์žฅ์• ๋ฅผ ๋‚ธ ์ ์ด ์žˆ๋‹ค. ๊ฒฐ๊ตญ ํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด๋ฅผ ๋‹ค์‹œ ์„ธ์›Œ์•ผ ํ–ˆ๋Š”๋ฐ, ์šด์˜ ์„œ๋ฒ„๊ฐ€ ์•„๋‹ˆ์—ˆ์œผ๋‹ˆ ๋ง์ •์ด์ง€ ์ •๋ง ๋•€๋‚˜๋Š” ๊ฒฝํ—˜์ด์—ˆ๋‹ค. ๊ทธ ๋’ค๋กœ ๋ฐฑ์—…์€ ์Šต๊ด€์ด ๋๋‹ค.

IMPORTANT

etcd ๋ฐฑ์—…์€ ํด๋Ÿฌ์Šคํ„ฐ ์šด์˜์—์„œ ํ•„์ˆ˜๋‹ค. ์ •๊ธฐ ๋ฐฑ์—… ์—†์ด๋Š” ์žฅ์•  ์‹œ ๋ณต๊ตฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

2. ๋ฐฑ์—… ์ „๋žต

์ด๋ฒˆ ์„ค์ •์—์„œ ์“ด ๋ฐฑ์—… ์ „๋žต์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋ฐฑ์—… ์ฃผ๊ธฐ: ๋งค์ผ ์˜คํ›„ 5์‹œ (Asia/Seoul ๊ธฐ์ค€)
  • ๋ณด๊ด€ ์ •์ฑ…: ๋กœ์ปฌ๊ณผ ์˜๊ตฌ ์ €์žฅ์†Œ์— ๊ฐ๊ฐ 5์ผ๊ฐ„ ๋ณด๊ด€
  • ์ด์ค‘ํ™”: ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์™€ PVC๋ฅผ ํ™œ์šฉํ•œ ์ด์ค‘ ๋ฐฑ์—…
  • ์ž๋™ ์ •๋ฆฌ: ์˜ค๋ž˜๋œ ๋ฐฑ์—… ํŒŒ์ผ ์ž๋™ ์‚ญ์ œ

3. CronJob ๊ตฌ์„ฑ

3-1. ๊ธฐ๋ณธ ์„ค์ •

CronJob์€ ๋งค์ผ ์ •ํ•ด์ง„ ์‹œ๊ฐ„์— etcd ์Šค๋ƒ…์ƒท์„ ์ƒ์„ฑํ•˜๊ณ  ๋ฐฑ์—… ํŒŒ์ผ์„ ๊ด€๋ฆฌํ•œ๋‹ค.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: etcd-backup-cron-job
  namespace: kube-system
spec:
  schedule: "0 17 * * *"  # ๋งค์ผ ์˜คํ›„ 5์‹œ
  timeZone: "Asia/Seoul"
  concurrencyPolicy: Allow
  failedJobsHistoryLimit: 1
  successfulJobsHistoryLimit: 3

3-2. Pod ์Šค์ผ€์ค„๋ง

๋ฐฑ์—… ์ž‘์—…์€ ๋ฐ˜๋“œ์‹œ control-plane ๋…ธ๋“œ์—์„œ ์‹คํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค. etcd ์„œ๋ฒ„์— ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ์—์„œ๋งŒ ๋ฐฑ์—…์ด ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

spec:
  template:
    spec:
      nodeSelector:
        node-role.kubernetes.io/control-plane: ""
      tolerations:
      - effect: NoSchedule
        key: node-role.kubernetes.io/control-plane
        operator: Exists
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - kdev-master-a-04  # ํŠน์ • ๋งˆ์Šคํ„ฐ ๋…ธ๋“œ ์„ ํ˜ธ
            weight: 100

3-3. etcd ๋ฐฑ์—… ์ˆ˜ํ–‰

InitContainer์—์„œ ์‹ค์ œ etcd ์Šค๋ƒ…์ƒท ์ƒ์„ฑ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. etcdctl snapshot ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ etcd ์ƒํƒœ๋ฅผ ๋ฐฑ์—… ํŒŒ์ผ๋กœ ์ €์žฅํ•œ๋‹ค.

initContainers:
- name: etcd-backup
  image: bitnami/etcd:latest
  command:
  - /bin/sh
  - -c
  - |
    DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
    BACKUP_DIR="/backup/host"
    SNAPSHOT_FILE="etcd-snapshot-${DATE}.db"
    
    etcdctl \
      --endpoints=https://127.0.0.1:2379 \
      --cacert=/etc/kubernetes/pki/etcd/ca.crt \
      --cert=/etc/kubernetes/pki/etcd/server.crt \
      --key=/etc/kubernetes/pki/etcd/server.key \
      snapshot save "${BACKUP_DIR}/${SNAPSHOT_FILE}"

NOTE

etcd ๋ฐฑ์—… ์‹œ์—๋Š” etcd ์„œ๋ฒ„์˜ TLS ์ธ์ฆ์„œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. Kubernetes์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ /etc/kubernetes/pki/etcd/ ๊ฒฝ๋กœ์— ํ•„์š”ํ•œ ์ธ์ฆ์„œ๋“ค์ด ์œ„์น˜ํ•œ๋‹ค.

3-4. ๋ฐฑ์—… ํŒŒ์ผ ๊ด€๋ฆฌ

๋ฉ”์ธ ์ปจํ…Œ์ด๋„ˆ์—์„œ๋Š” ๋ฐฑ์—… ํŒŒ์ผ์„ ์˜๊ตฌ ์ €์žฅ์†Œ๋กœ ๋ณต์‚ฌํ•˜๊ณ , ์˜ค๋ž˜๋œ ๋ฐฑ์—… ํŒŒ์ผ๋“ค์„ ์ •๋ฆฌํ•œ๋‹ค.

containers:
- name: backup-purge
  image: busybox:latest
  command:
  - /bin/sh
  - -c
  - |
    # ๋กœ์ปฌ ๋ฐฑ์—…์„ ์˜๊ตฌ ์ €์žฅ์†Œ๋กœ ๋ณต์‚ฌ
    cp -u /backup/host/*.db /backup/persist/
    
    # 5์ผ ์ด์ƒ ๋œ ๋ฐฑ์—… ํŒŒ์ผ ์‚ญ์ œ
    find /backup/host -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;
    find /backup/persist -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;

4. ๋ณผ๋ฅจ ๊ตฌ์„ฑ

๋ฐฑ์—… ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€ ๋ณผ๋ฅจ์„ ์‚ฌ์šฉํ•œ๋‹ค:

  • etcd-backup: ๋…ธ๋“œ์˜ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€ (/data/etcd-backup)
  • second-backup: PVC๋ฅผ ํ†ตํ•œ ์˜๊ตฌ ์ €์žฅ์†Œ
  • etcd-certs: etcd TLS ์ธ์ฆ์„œ ๋””๋ ‰ํ† ๋ฆฌ
volumes:
- name: etcd-backup
  hostPath:
    path: /data/etcd-backup
- name: etcd-certs
  hostPath:
    path: /etc/kubernetes/pki/etcd
    type: Directory
- name: second-backup
  persistentVolumeClaim:
    claimName: etcd-backup-pvc

5. ์ „์ฒด ์„ค์ •

์™„์ „ํ•œ CronJob YAML ์„ค์ •
apiVersion: v1
items:
- apiVersion: batch/v1
  kind: CronJob
  metadata:
    name: etcd-backup-cron-job
    namespace: kube-system
  spec:
    concurrencyPolicy: Allow
    failedJobsHistoryLimit: 1
    jobTemplate:
      metadata:
        creationTimestamp: null
      spec:
        template:
          metadata:
            creationTimestamp: null
          spec:
            affinity:
              nodeAffinity:
                preferredDuringSchedulingIgnoredDuringExecution:
                - preference:
                    matchExpressions:
                    - key: kubernetes.io/hostname
                      operator: In
                      values:
                      - kdev-master-a-04
                  weight: 100
            containers:
            - command:
              - /bin/sh
              - -c
              - |
                cp -u /backup/host/*.db /backup/persist/
                find /backup/host -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;
                find /backup/persist -type f -mtime +5 -name '*.db' -exec rm -- '{}' \;
              image: busybox:latest
              imagePullPolicy: IfNotPresent
              name: backup-purge
              resources: {}
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
              volumeMounts:
              - mountPath: /backup/host
                name: etcd-backup
              - mountPath: /backup/persist
                name: second-backup
            dnsPolicy: ClusterFirst
            hostNetwork: true
            initContainers:
            - command:
              - /bin/sh
              - -c
              - |
                DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
                BACKUP_DIR="/backup/host"
                SNAPSHOT_FILE="etcd-snapshot-${DATE}.db"
                ARCHIVE_FILE="${SNAPSHOT_FILE}.gz"
 
                etcdctl \
                  --endpoints=https://127.0.0.1:2379 \
                  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
                  --cert=/etc/kubernetes/pki/etcd/server.crt \
                  --key=/etc/kubernetes/pki/etcd/server.key \
                  snapshot save "${BACKUP_DIR}/${SNAPSHOT_FILE}"
              image: bitnami/etcd:latest
              imagePullPolicy: IfNotPresent
              name: etcd-backup
              resources: {}
              securityContext:
                allowPrivilegeEscalation: false
                runAsGroup: 0
                runAsUser: 0
              terminationMessagePath: /dev/termination-log
              terminationMessagePolicy: File
              volumeMounts:
              - mountPath: /backup/host
                name: etcd-backup
              - mountPath: /etc/kubernetes/pki/etcd
                name: etcd-certs
                readOnly: true
            nodeSelector:
              node-role.kubernetes.io/control-plane: ""
            restartPolicy: OnFailure
            schedulerName: default-scheduler
            securityContext: {}
            terminationGracePeriodSeconds: 30
            tolerations:
            - effect: NoSchedule
              key: node-role.kubernetes.io/control-plane
              operator: Exists
            volumes:
            - hostPath:
                path: /data/etcd-backup
                type: ""
              name: etcd-backup
            - hostPath:
                path: /etc/kubernetes/pki/etcd
                type: Directory
              name: etcd-certs
            - name: second-backup
              persistentVolumeClaim:
                claimName: etcd-backup-pvc
    schedule: 0 17 * * *
    successfulJobsHistoryLimit: 3
    suspend: false
    timeZone: Asia/Seoul

6. ๋ฐฑ์—… ํ™•์ธ ๋ฐ ๋ณต๊ตฌ

๋ฐฑ์—…์ด ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š”์ง€ ์ •๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค:

# ๋ฐฑ์—… ํŒŒ์ผ ํ™•์ธ
ls -la /data/etcd-backup/
 
# ๋ฐฑ์—… ํŒŒ์ผ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ
etcdctl snapshot status /data/etcd-backup/etcd-snapshot-<timestamp>.db
 
# ๋ณต๊ตฌ ํ…Œ์ŠคํŠธ (ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋งŒ)
etcdctl snapshot restore /data/etcd-backup/etcd-snapshot-<timestamp>.db \
  --data-dir=/var/lib/etcd-restore

INFO

๋ฐฑ์—…์€ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ, ์‹ค์ œ๋กœ ๋ณต๊ตฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ์ง€ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด ๋”์šฑ ์ค‘์š”ํ•˜๋‹ค. ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ ์ •๊ธฐ์ ์œผ๋กœ ๋ณต๊ตฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.