Part 16: Node Drain과 Cluster Upgrade - 유지보수
Part 16: Node Drain과 Cluster Upgrade - 유지보수
Part 16: 클러스터 유지보수
OS Upgrades와 Node Maintenance
Node Drain
개념:
Node Drain은 노드에서 모든 Pod를 안전하게 제거하고 새로운 Pod의 스케줄링을 방지한다. OS 업그레이드, 하드웨어 유지보수 등을 수행하기 전에 필수적이다.
동작 과정:
- 노드를 Unschedulable로 표시 (Cordon)
- 노드의 모든 Pod를 삭제
- Deployment/ReplicaSet의 Pod는 다른 노드에 재생성
- 유지보수 완료 후 Uncordon으로 복귀
기본 사용:
1
2
3
4
5
6
7
8
9
10
11
# 노드 Drain
kubectl drain node01
# 일반적으로 사용하는 플래그들
kubectl drain node01 --ignore-daemonsets --delete-emptydir-data
# Pod 삭제 대기 시간 설정
kubectl drain node01 --ignore-daemonsets --timeout=60s
# 강제 삭제
kubectl drain node01 --ignore-daemonsets --force
주요 플래그 설명:
--ignore-daemonsets: DaemonSet Pod는 제외 (모든 노드에 실행되어야 하므로)--delete-emptydir-data: emptyDir 볼륨을 사용하는 Pod도 삭제 (데이터 손실 가능)--force: ReplicationController 등이 없는 Pod도 강제 삭제--grace-period=<seconds>: Pod 종료 대기 시간 (기본 30초)--timeout=<duration>: Drain 전체 작업 타임아웃
실패 케이스와 해결:
1
2
3
4
5
6
7
8
# 에러: cannot delete Pods with local storage
kubectl drain node01 --delete-emptydir-data
# 에러: cannot delete DaemonSet-managed Pods
kubectl drain node01 --ignore-daemonsets
# 에러: cannot delete Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet
kubectl drain node01 --force
유지보수 후 복구:
1
2
3
4
5
6
7
# 노드를 다시 Schedulable로 설정
kubectl uncordon node01
# 상태 확인
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# node01 Ready <none> 10d v1.28.0
Node Cordon
개념:
Cordon은 노드를 Unschedulable로 표시만 하고 기존 Pod는 유지한다. 일시적으로 새로운 Pod 배치를 막을 때 유용한다.
사용 시나리오:
- 노드에 문제가 있지만 즉시 제거하기 어려운 경우
- 점진적인 노드 교체
- 노드 리소스 조사
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Cordon
kubectl cordon node01
# 상태 확인
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# node01 Ready,SchedulingDisabled <none> 10d v1.28.0
# 기존 Pod는 계속 실행
kubectl get pods -o wide
# NAME READY STATUS NODE
# nginx-75c4b8d8c-abc12 1/1 Running node01 # 여전히 실행 중
# Uncordon
kubectl uncordon node01
PodDisruptionBudget (PDB)
개념:
PDB는 동시에 종료될 수 있는 Pod의 최대/최소 개수를 제한하여 애플리케이션의 가용성을 보장한다.
예제:
1
2
3
4
5
6
7
8
9
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
minAvailable: 2 # 최소 2개는 항상 실행되어야 함
selector:
matchLabels:
app: zookeeper
1
2
3
4
5
6
7
8
9
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
maxUnavailable: 1 # 동시에 최대 1개만 종료 가능
selector:
matchLabels:
app: web
PDB와 Drain:
1
2
3
4
5
# PDB가 있는 노드를 Drain하면
kubectl drain node01 --ignore-daemonsets
# PDB를 위반하면 Drain이 대기
# error when evicting pods/... (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
PDB 확인:
1
2
3
4
5
6
7
8
# PDB 목록
kubectl get pdb
# PDB 상세 정보
kubectl describe pdb web-pdb
# Min available: 2
# Current number available: 3
# Allowed disruptions: 1
Node Maintenance 실습 과제
node01을 Drain하고 Uncordon하기- PodDisruptionBudget를 생성하고 Drain 테스트
- 강제 Drain이 필요한 상황 시뮬레이션
Cluster Upgrade
업그레이드 전략
업그레이드 순서:
- Control Plane 컴포넌트 (한 번에 하나씩)
- etcd
- kube-apiserver
- kube-controller-manager
- kube-scheduler
- Worker Node 컴포넌트
- kubelet
- kube-proxy
버전 skew 정책:
- kube-apiserver: N
- kube-controller-manager, kube-scheduler: N-1
- kubelet, kube-proxy: N-2
- kubectl: N+1, N, N-1
예: kube-apiserver가 1.28이면
- controller-manager/scheduler: 1.27 또는 1.28
- kubelet/kube-proxy: 1.26, 1.27, 1.28
kubeadm을 이용한 업그레이드
1단계: 업그레이드 계획 확인
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
# kubeadm 자체를 먼저 업그레이드
apt update
apt-cache madison kubeadm # 사용 가능한 버전 확인
apt-get install -y kubeadm=1.28.0-00
# 업그레이드 계획 확인
kubeadm upgrade plan
# 출력 예:
# [upgrade/config] Making sure the configuration is correct:
# [upgrade/config] Reading configuration from the cluster...
# [upgrade] Running cluster health checks
# [upgrade] Fetching available versions to upgrade to
# ...
# Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply':
# COMPONENT CURRENT TARGET
# kubelet 4 x v1.27.0 v1.28.0
#
# Upgrade to the latest stable version:
#
# COMPONENT CURRENT TARGET
# kube-apiserver v1.27.0 v1.28.0
# kube-controller-manager v1.27.0 v1.28.0
# kube-scheduler v1.27.0 v1.28.0
# kube-proxy v1.27.0 v1.28.0
# CoreDNS v1.10.1 v1.10.1
# etcd 3.5.7-0 3.5.9-0
2단계: Control Plane 업그레이드 (First Master Node)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Control Plane 업그레이드
kubeadm upgrade apply v1.28.0
# 출력 확인:
# [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.28.0". Enjoy!
# kubelet과 kubectl 업그레이드
apt-get install -y kubelet=1.28.0-00 kubectl=1.28.0-00
# kubelet 재시작
systemctl daemon-reload
systemctl restart kubelet
# 상태 확인
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# controlplane Ready control-plane 20d v1.28.0 # 업그레이드됨
# node01 Ready <none> 20d v1.27.0 # 아직 이전 버전
3단계: 추가 Control Plane 노드 업그레이드 (HA 클러스터)
1
2
3
4
5
6
# 추가 마스터 노드에서
kubeadm upgrade node
apt-get install -y kubelet=1.28.0-00 kubectl=1.28.0-00
systemctl daemon-reload
systemctl restart kubelet
4단계: Worker Node 업그레이드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Control Plane에서 노드 Drain
kubectl drain node01 --ignore-daemonsets --delete-emptydir-data
# node01 노드에서 kubeadm 업그레이드
apt-get update
apt-get install -y kubeadm=1.28.0-00
# 노드 업그레이드
kubeadm upgrade node
# kubelet과 kubectl 업그레이드
apt-get install -y kubelet=1.28.0-00 kubectl=1.28.0-00
systemctl daemon-reload
systemctl restart kubelet
# Control Plane에서 Uncordon
kubectl uncordon node01
# 확인
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# controlplane Ready control-plane 20d v1.28.0
# node01 Ready <none> 20d v1.28.0 # 업그레이드 완료
업그레이드 검증:
1
2
3
4
5
6
7
8
9
10
11
12
# 모든 컴포넌트 버전 확인
kubectl get nodes -o wide
# Control Plane 컴포넌트 버전
kubectl get pods -n kube-system -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
# API 버전 확인
kubectl version
# 클러스터 상태 확인
kubectl get componentstatuses # deprecated in 1.19+
kubectl get --raw='/readyz?verbose'
업그레이드 시 주의사항
- 백업 필수: etcd를 먼저 백업
- 한 번에 한 Minor 버전씩: 1.26 → 1.27 → 1.28 (1.26 → 1.28 불가)
- Control Plane 먼저: Worker Node보다 항상 먼저
- 테스트 환경에서 먼저 수행
- PDB 확인: Drain 시 애플리케이션 가용성 확인
Cluster Upgrade 실습 과제
- 테스트 클러스터를 1.27에서 1.28로 업그레이드
- 업그레이드 중 애플리케이션 다운타임 최소화 전략 수립
- 업그레이드 롤백 시나리오 연습
Backup and Restore
etcd Backup
etcd의 중요성:
etcd는 Kubernetes 클러스터의 모든 상태 정보를 저장하는 핵심 데이터베이스입니다:
- 모든 리소스 정의 (Pods, Services, ConfigMaps, Secrets 등)
- 클러스터 설정
- 네트워크 정책
- RBAC 설정
백업 방법:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# etcd 스냅샷 생성
ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-backup.db \
--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
# 스냅샷 검증
ETCDCTL_API=3 etcdctl snapshot status /tmp/etcd-backup.db \
--write-out=table
# 출력:
# +----------+----------+------------+------------+
# | HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
# +----------+----------+------------+------------+
# | 12ab34cd | 12345 | 1234 | 2.3 MB |
# +----------+----------+------------+------------+
인증서 경로 찾기:
1
2
3
4
5
6
7
8
9
10
# etcd Pod의 인증서 경로 확인
kubectl describe pod -n kube-system etcd-controlplane | grep -A 5 "Command:"
# 또는 etcd manifest 확인
cat /etc/kubernetes/manifests/etcd.yaml | grep file
# 일반적인 경로:
# --cacert=/etc/kubernetes/pki/etcd/ca.crt
# --cert=/etc/kubernetes/pki/etcd/server.crt
# --key=/etc/kubernetes/pki/etcd/server.key
자동화된 백업 스크립트:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# etcd-backup.sh
BACKUP_DIR="/var/backups/etcd"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/etcd-backup-${TIMESTAMP}.db"
mkdir -p ${BACKUP_DIR}
ETCDCTL_API=3 etcdctl snapshot save ${BACKUP_FILE} \
--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
# 검증
ETCDCTL_API=3 etcdctl snapshot status ${BACKUP_FILE} --write-out=table
# 7일 이상 된 백업 삭제
find ${BACKUP_DIR} -name "etcd-backup-*.db" -mtime +7 -delete
echo "Backup completed: ${BACKUP_FILE}"
크론잡으로 정기 백업:
1
2
# 매일 새벽 2시에 백업
0 2 * * * /usr/local/bin/etcd-backup.sh >> /var/log/etcd-backup.log 2>&1
etcd Restore
복원 시나리오:
- 클러스터 설정 손상
- 잘못된 리소스 삭제
- 재해 복구
복원 단계:
1단계: 기존 etcd 정지
1
2
3
4
5
6
7
8
# kube-apiserver 정지 (etcd 접근 차단)
mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/
# etcd 정지
mv /etc/kubernetes/manifests/etcd.yaml /tmp/
# 기존 etcd 데이터 백업 (혹시 모르니)
mv /var/lib/etcd /var/lib/etcd.old
2단계: 스냅샷에서 복원
1
2
3
4
5
6
7
8
# 새로운 데이터 디렉토리로 복원
ETCDCTL_API=3 etcdctl snapshot restore /tmp/etcd-backup.db \
--data-dir=/var/lib/etcd-restore \
--initial-cluster=master=https://127.0.0.1:2380 \
--initial-advertise-peer-urls=https://127.0.0.1:2380
# 권한 설정
chown -R etcd:etcd /var/lib/etcd-restore
3단계: etcd 설정 변경
1
2
3
4
5
6
7
# etcd.yaml에서 데이터 디렉토리 변경
vim /tmp/etcd.yaml
# 변경:
# --data-dir=/var/lib/etcd
# →
# --data-dir=/var/lib/etcd-restore
4단계: 서비스 재시작
1
2
3
4
5
6
7
8
9
10
11
# etcd 재시작
mv /tmp/etcd.yaml /etc/kubernetes/manifests/
# etcd가 시작될 때까지 대기
sleep 20
# kube-apiserver 재시작
mv /tmp/kube-apiserver.yaml /etc/kubernetes/manifests/
# 클러스터 상태 확인
kubectl get pods -A
복원 검증:
1
2
3
4
5
6
7
8
9
10
11
12
# 리소스 확인
kubectl get all -A
# etcd 멤버 확인
ETCDCTL_API=3 etcdctl member list \
--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
# 로그 확인
journalctl -u kubelet -f
클러스터 HA 환경의 etcd
etcd 클러스터 백업:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# HA 환경에서는 모든 etcd 멤버에서 백업 가능
# 하지만 하나의 멤버에서만 백업해도 충분
# etcd 멤버 확인
ETCDCTL_API=3 etcdctl member list \
--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
# 출력:
# 1a2b3c4d5e6f7890, started, master-1, https://192.168.1.11:2380, https://192.168.1.11:2379, false
# 9f8e7d6c5b4a3210, started, master-2, https://192.168.1.12:2380, https://192.168.1.12:2379, false
# 1122334455667788, started, master-3, https://192.168.1.13:2380, https://192.168.1.13:2379, false
etcd 클러스터 복원:
1
2
3
4
5
6
7
8
# 모든 etcd 멤버에서 복원 수행
# 각 노드에서:
ETCDCTL_API=3 etcdctl snapshot restore /tmp/etcd-backup.db \
--data-dir=/var/lib/etcd-restore \
--name=master-1 \ # 각 노드마다 다름
--initial-cluster=master-1=https://192.168.1.11:2380,master-2=https://192.168.1.12:2380,master-3=https://192.168.1.13:2380 \
--initial-advertise-peer-urls=https://192.168.1.11:2380 # 각 노드마다 다름
리소스 레벨 백업
선언적 방식으로 백업:
1
2
3
4
5
6
7
8
# 모든 네임스페이스의 리소스 백업
kubectl get all --all-namespaces -o yaml > cluster-backup.yaml
# 특정 리소스 타입만 백업
kubectl get deployments,services,configmaps,secrets --all-namespaces -o yaml > resources-backup.yaml
# RBAC 설정 백업
kubectl get roles,rolebindings,clusterroles,clusterrolebindings --all-namespaces -o yaml > rbac-backup.yaml
Velero를 이용한 백업 (프로덕션 권장):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Velero 설치
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.8.0 \
--bucket velero-backups \
--backup-location-config region=us-east-1 \
--snapshot-location-config region=us-east-1 \
--secret-file ./credentials-velero
# 전체 클러스터 백업
velero backup create full-backup
# 특정 네임스페이스만 백업
velero backup create app-backup --include-namespaces=production
# 백업 확인
velero backup describe full-backup
# 복원
velero restore create --from-backup full-backup
Certificate 관리
인증서 확인:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 인증서 만료일 확인
kubeadm certs check-expiration
# 출력:
# CERTIFICATE EXPIRES RESIDUAL TIME CERTIFICATE AUTHORITY EXTERNALLY MANAGED
# admin.conf Dec 13, 2024 12:00 UTC 364d ca no
# apiserver Dec 13, 2024 12:00 UTC 364d ca no
# apiserver-etcd-client Dec 13, 2024 12:00 UTC 364d etcd-ca no
# apiserver-kubelet-client Dec 13, 2024 12:00 UTC 364d ca no
# controller-manager.conf Dec 13, 2024 12:00 UTC 364d ca no
# etcd-healthcheck-client Dec 13, 2024 12:00 UTC 364d etcd-ca no
# etcd-peer Dec 13, 2024 12:00 UTC 364d etcd-ca no
# etcd-server Dec 13, 2024 12:00 UTC 364d etcd-ca no
# front-proxy-client Dec 13, 2024 12:00 UTC 364d front-proxy-ca no
# scheduler.conf Dec 13, 2024 12:00 UTC 364d ca no
인증서 갱신:
1
2
3
4
5
6
7
8
9
10
11
12
# 모든 인증서 갱신
kubeadm certs renew all
# 특정 인증서만 갱신
kubeadm certs renew apiserver
kubeadm certs renew apiserver-kubelet-client
# Control Plane 재시작
systemctl restart kubelet
# 확인
kubeadm certs check-expiration
자동 갱신 설정:
1
2
# 크론잡으로 자동 갱신 (만료 30일 전)
0 0 1 * * kubeadm certs renew all && systemctl restart kubelet
Backup and Restore 실습 과제
- etcd 스냅샷 백업 및 복원 수행
- 네임스페이스 하나를 삭제하고 etcd 복원으로 복구
- 인증서 만료일 확인 및 갱신
- 백업 자동화 스크립트 작성
This post is licensed under CC BY 4.0 by the author.