콘텐츠로 이동
Study Note온프렘 쿠버네티스

12. 운영 — 루틴 · 업그레이드 · 진단

온프렘 운영의 8할은 디스크 · 인증서 · 버전 셋이다 — 나머지가 화려할 뿐이다

이 장에서 처음 나오는 말6개
버전 스큐Version Skew
컴포넌트 사이에 허용되는 버전 차이의 범위. 쿠버네티스는 kubelet이 API 서버보다 최대 3마이너 낮은 것까지 허용한다 — 이 범위를 벗어나면 동작을 보장하지 않는다.
드레인Drain
노드에서 파드를 안전하게 비워 내는 것(kubectl drain). 업그레이드·점검 전에 한다.
PDBPodDisruptionBudget
"이 앱은 동시에 몇 개까지만 내려도 된다"는 선언. 드레인이 이걸 존중하기 때문에 PDB가 없으면 업그레이드가 서비스를 끊는다.
runbook실행 절차서
특정 알림·증상이 왔을 때 무엇을 순서대로 확인하고 조치하는지 적은 문서. 알림에 링크로 달아 둔다([관측 덱 2장](/observability/02-prometheus/)).
온콜On-call
장애 시 호출을 받는 당번. 도구보다 누가 어떤 순서로 무엇을 보는지가 정해져 있느냐가 품질을 가른다.
용량 계획Capacity Planning
언제 무엇이 부족해질지 미리 계산하는 일. 온프렘에는 오토스케일이 없으므로 이게 운영 업무의 한 항목이 된다.

운영 루틴 — 주기별로 고정한다

섹션 제목: “운영 루틴 — 주기별로 고정한다”

“문제 생기면 본다”로는 온프렘이 안 굴러간다. 주기를 고정해 두면 대부분의 사고가 예방된다.

주기하는 일
매일알림 확인(밤새 온 것), 백업 잡 결과, Argo CD OutOfSync 목록
매주디스크·PVC 사용률 추세, 인증서 만료 30일 이내 목록, 노드 상태, 재시작 반복 파드
매월컴포넌트 버전과 최신 릴리스 대조(CVE 확인), 대시보드·알림 정리, 용량 추세 리뷰
분기복구 리허설(11장), 쿠버네티스·애드온 업그레이드, 접근 권한 감사, runbook 갱신
연 1회사내 CA·클러스터 인증서 만료 점검, DR(Disaster Recovery, 재해 복구) 시나리오 전면 훈련, 용량 증설 예산
터미널 창
# 매주 5분짜리 스크립트로 만들어 두면 좋은 것들
kubectl get nodes -o wide
kubectl get pods -A --field-selector=status.phase!=Running | grep -v Completed
kubectl get certificate -A | grep -v True
kubectl top nodes
kubectl get pvc -A -o custom-columns=\
'NS:.metadata.namespace,NAME:.metadata.name,SIZE:.status.capacity.storage,SC:.spec.storageClassName'
kubectl -n argocd get applications | grep -v 'Synced.*Healthy'

온프렘에서 업그레이드가 무서운 이유는 컴포넌트가 서로 버전을 탄다는 것이다. 쿠버네티스를 올렸더니 CNI가 안 뜨고, CNI를 올렸더니 게이트웨이가 안 뜨는 식.

컴포넌트현재목표대상 k8s 지원출처 확인
Kubernetes—
CNI (Calico/Cilium)
CSI 드라이버
Gateway 구현체
cert-manager
CloudNativePG
Prometheus Operator
Velero
  1. 백업. etcd 스냅샷 + CNPG 백업을 작업 직전에 한 번 더 (11장)

  2. 스테이징 클러스터에서 먼저. 없으면 최소한 워커 노드 1대로 먼저

  3. CNI·CSI가 목표 버전을 지원하는지 확인하고, 필요하면 먼저 올린다

  4. 컨트롤 플레인 — 한 대씩. 각 대 사이에 kubectl get nodes와 API 응답을 확인

  5. 워커 노드 — drain → 업그레이드 → uncordon. 한 번에 한 대씩

  6. 애드온 — cert-manager · Gateway · 오퍼레이터들. CRD 변경이 있는지 릴리스 노트 확인

  7. 검증 — 아래 스모크 테스트

터미널 창
# 노드 하나 처리 (kubeadm 기준)
kubectl drain node-3 --ignore-daemonsets --delete-emptydir-data --timeout=10m
# → PDB 때문에 멈추면 그건 정상이다. 앱 팀과 조율하거나 replica를 늘린다
ssh node-3 'sudo kubeadm upgrade node && sudo apt-get install -y kubelet=<버전> && sudo systemctl restart kubelet'
kubectl uncordon node-3
kubectl get nodes # VERSION 열 확인
터미널 창
# ① 노드·핵심 파드
kubectl get nodes
kubectl -n kube-system get pods | grep -v Running
# ② 입구 (3·4장)
kubectl get gateway,httproute -A
curl -sI https://grafana.example.internal/ | head -1
# ③ 상태 계층 (6·7장)
kubectl cnpg status platform-pg -n database
mc ls store/ >/dev/null && echo "S3 OK"
# ④ 관측 (8장 · 관측 덱)
kubectl -n observability get pods
# Prometheus /targets 에서 DOWN 급증이 없는지
# ⑤ 배포 (9장)
kubectl -n argocd get applications | grep -v 'Synced.*Healthy'
# ⑥ 스토리지 실동작 (2장)
kubectl create -f - <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: smoke }
spec: { accessModes: [ReadWriteOnce], resources: { requests: { storage: 1Gi } } }
EOF
kubectl get pvc smoke && kubectl delete pvc smoke

용량 — 오토스케일이 없다는 것의 의미

섹션 제목: “용량 — 오토스케일이 없다는 것의 의미”

클라우드는 노드가 모자라면 늘어났다. 온프렘은 주문 → 입고 → 랙 → 설치에 몇 주가 걸린다. 그래서 용량은 알림이 아니라 계획의 영역이다.

자원어디서 보나미리 정할 것
노드 CPU·메모리kubectl top nodes, Prometheus 추세요청(request) 합계가 용량의 70% 를 넘으면 증설 검토
PVC 용량kubelet_volume_stats_*확장 가능한 SC로 만들어 뒀는가 (2장)
오브젝트 스토리지스토리지 자체 지표라이프사이클로 상한을 만든다 (6장)
Prometheus TSDB/tsdb-status리텐션 vs 디스크 (관측 덱 2장)
IP 풀IPAddressPool 잔여서비스가 늘면 LB IP도 는다 (3장)

아무 일도 안 하는데 어느 날 전면 장애가 나는 유형이다. 달력에 넣는다.

만료되는 것기본 수명갱신만료되면
kubeadm 클러스터 인증서1년kubeadm certs renew all (컨트롤 플레인 업그레이드 시 자동 갱신)API 서버에 아무도 못 붙는다
kubelet 클라이언트 인증서1년자동 회전(기본)노드가 NotReady
cert-manager 발급 인증서90일 등자동브라우저 경고 → 서비스 접속 불가
사내 루트·중간 CA수년수동발급한 모든 인증서가 동시에
Keycloak 서명 키정책에 따라롤오버 (Keycloak 관리 권한과 서명 키)토큰 검증 실패
서비스 계정 토큰(외부 시스템용)설정에 따라재발급CI(지속적 통합)·연동 실패
터미널 창
# 클러스터 인증서 만료일 (컨트롤 플레인 노드에서)
sudo kubeadm certs check-expiration
# cert-manager 인증서 중 30일 내 만료
kubectl get certificate -A -o json | jq -r '
.items[] | select(.status.notAfter != null) |
"\(.metadata.namespace)/\(.metadata.name)\t\(.status.notAfter)"' | sort -k2

진단 사다리 — 터졌을 때 어느 층부터

섹션 제목: “진단 사다리 — 터졌을 때 어느 층부터”

1장의 층 구조가 그대로 진단 순서가 된다. 위에서 아래로 내려가며 “여기까지는 되나”를 확인한다.

앱이 응답하는지에서 시작해 입구까지 오는지, 노드·CNI가 정상인지, DB·스토리지가 정상인지 순으로 층을 내려가며 원인을 좁히는 진단 사다리
단계질문명령
0뭐가 언제부터?Grafana 개요 대시보드, Alertmanager 목록
⑤앱 파드가 살아 있나kubectl get pods -n <ns>, describe, 로그
②입구까지 오나게이트웨이 액세스 로그, curl --resolve로 직접
②이름·인증서인가dig, openssl s_client, kubectl get certificate
③DB·스토리지인가kubectl cnpg status, mc admin info
①노드·CNI인가kubectl get nodes, kube-system 파드, etcd 지표
④관측 자체가 죽었나Prometheus /targets, Loki 인입
증상자주 있는 원인첫 수
노드가 갑자기 여러 대 NotReady컨트롤 플레인·etcd 문제API 응답 시간, etcd 리더 유무
파드가 ImagePullBackOff레지스트리 · 자격증명 · 사내 CA노드에서 직접 pull 시도 (9장)
파드가 Pending스토리지 · 리소스 부족 · taintdescribe pod Events
전 서비스 HTTPS 오류인증서 만료kubectl get certificate -A
로그가 안 쌓임오브젝트 스토리지 풀 · Alloy 죽음mc admin info, Alloy 파드
DB 쓰기 실패WAL 아카이브 실패로 디스크 참pg_stat_archiver (7장)
새 배포가 반영 안 됨Argo CD OutOfSync · 이미지 태그argocd app diff
특정 앱만 느림앱 자체 · 다운스트림트레이스 (관측 덱 4장)
항목최소 기준
접근클러스터 접근 수단 + 깨진 유리 계정(5장)이 실제로 손에 있는가
문서알림마다 runbook 링크. 없으면 그 알림부터 정리 대상
연락스토리지·네트워크·DBA·앱 팀의 야간 연락 경로
권한야간에 혼자서 롤백·재시작할 수 있는 권한이 있는가
기록사후 회고(postmortem)를 남기고, runbook에 반영한다
  • 루틴을 일·주·월·분기로 고정한다. 분기에는 복구 리허설과 업그레이드가 들어간다
  • 업그레이드는 호환표를 채우는 것이 절반이다. 순서는 백업 → CNI/CSI → 컨트롤 플레인 → 워커 → 애드온
  • PDB가 없으면 드레인이 서비스를 끊는다
  • 온프렘엔 오토스케일이 없다 — 용량은 알림이 아니라 계획이고, predict_linear가 리드타임을 번다
  • 조용히 만료되는 것들(클러스터 인증서 1년, 사내 CA, 서명 키)을 달력에 넣는다
  • 진단은 층 구조를 위에서 아래로. 시작할 때 관측 스택 자체가 살아 있는지 먼저 본다