쿠버네티스 노드 구성 및 관리 실습 가이드

📚 실습 개요

쿠버네티스 클러스터에서 워커 노드들을 효과적으로 관리하는 방법을 실습을 통해 학습합니다. 노드 격리, 드레인, 레이블링, 스케줄링 제어 등 실제 운영에서 필요한 핵심 기능들을 다룹니다.

🎯 학습 목표

  • 노드 상태 관리 및 점검 방법 습득
  • 노드 격리(cordon) 및 드레인(drain) 실습
  • 노드 레이블링 및 셀렉터 활용법 이해
  • 어피니티/안티 어피니티를 통한 고급 스케줄링 제어

🛠️ 실습 환경 준비

필수 도구

# 쿠버네티스 클러스터 (minikube 또는 Docker Desktop)
minikube start --nodes 3 --cpus=2 --memory=4096
 
# kubectl 설정 확인
kubectl cluster-info
kubectl get nodes

멀티 노드 환경 구성 (minikube)

# 3개 노드로 클러스터 시작
minikube start --nodes 3 --driver=docker
 
# 노드 상태 확인
kubectl get nodes -o wide

📋 1. 노드 구성 및 기본 관리

1.1 노드 상태 확인

# 전체 노드 목록 조회
kubectl get nodes
 
# 노드 상세 정보 확인
kubectl describe node <node-name>
 
# 노드별 리소스 사용량 확인
kubectl top nodes

실습 결과 예시:

NAME           STATUS   ROLES           AGE   VERSION
minikube       Ready    control-plane   5m    v1.28.3
minikube-m02   Ready    <none>          3m    v1.28.3
minikube-m03   Ready    <none>          2m    v1.28.3

1.2 노드 정보 분석

# JSON 형태로 노드 정보 조회
kubectl get node minikube-m02 -o json | jq '.status.conditions'
 
# 노드의 할당 가능한 리소스 확인
kubectl get node minikube-m02 -o jsonpath='{.status.allocatable}'

🚫 2. 노드 격리(Cordon) 및 드레인(Drain)

2.1 노드 격리 (Cordon) 실습

개념 정리

  • Cordon: 노드에 새로운 파드 스케줄링을 차단
  • 기존 파드는 그대로 유지, 새로운 파드만 차단
# 노드 격리 (새로운 파드 스케줄링 차단)
kubectl cordon minikube-m02
 
# 노드 상태 확인 (SchedulingDisabled 상태)
kubectl get nodes

격리 상태 확인

# 격리된 노드에 파드 배포 시도
kubectl create deployment test-cordon --image=nginx --replicas=3
 
# 파드 배포 위치 확인 (minikube-m02 제외)
kubectl get pods -o wide

2.2 노드 격리 해제 (Uncordon)

# 노드 격리 해제
kubectl uncordon minikube-m02
 
# 상태 확인
kubectl get nodes

2.3 노드 드레인 (Drain) 실습

드레인 준비 작업

# 테스트용 파드 배포
kubectl create deployment drain-test --image=nginx --replicas=6
 
# 파드 배포 상태 확인
kubectl get pods -o wide

노드 드레인 실행

# 노드 드레인 (모든 파드 다른 노드로 이동)
kubectl drain minikube-m02 --ignore-daemonsets --delete-emptydir-data
 
# 드레인 후 파드 위치 확인
kubectl get pods -o wide

드레인 중 발생 가능한 문제 해결

# DaemonSet 파드가 있는 경우
kubectl drain minikube-m02 --ignore-daemonsets
 
# 로컬 스토리지를 사용하는 파드가 있는 경우
kubectl drain minikube-m02 --ignore-daemonsets --delete-emptydir-data
 
# 강제 드레인 (주의: 데이터 손실 가능)
kubectl drain minikube-m02 --ignore-daemonsets --delete-emptydir-data --force

🏷️ 3. 노드 레이블 관리

3.1 기본 노드 레이블 확인

# 모든 노드의 레이블 확인
kubectl get nodes --show-labels
 
# 특정 노드 레이블 상세 조회
kubectl describe node minikube-m02 | grep Labels -A 10

3.2 사용자 정의 레이블 추가

# 노드에 환경 레이블 추가
kubectl label node minikube-m02 environment=production
kubectl label node minikube-m03 environment=development
 
# 하드웨어 타입 레이블 추가
kubectl label node minikube-m02 hardware=ssd
kubectl label node minikube-m03 hardware=hdd
 
# 위치 레이블 추가
kubectl label node minikube-m02 zone=asia-northeast1-a
kubectl label node minikube-m03 zone=asia-northeast1-b

3.3 레이블 기반 노드 검색

# 특정 레이블로 노드 필터링
kubectl get nodes -l environment=production
kubectl get nodes -l hardware=ssd
kubectl get nodes -l zone=asia-northeast1-a
 
# 복합 조건으로 노드 검색
kubectl get nodes -l environment=production,hardware=ssd

3.4 레이블 수정 및 삭제

# 레이블 값 변경
kubectl label node minikube-m02 environment=staging --overwrite
 
# 레이블 삭제
kubectl label node minikube-m02 hardware-
 
# 변경 결과 확인
kubectl get nodes --show-labels

🎯 4. 노드 셀렉터 실습

4.1 기본 노드 셀렉터 사용

노드 셀렉터를 사용한 파드 배포

# nodeSelector-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: production-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: production-app
  template:
    metadata:
      labels:
        app: production-app
    spec:
      nodeSelector:
        environment: production  # production 레이블이 있는 노드에만 배포
      containers:
      - name: app
        image: nginx
        ports:
        - containerPort: 80
# 배포 실행
kubectl apply -f nodeSelector-demo.yaml
 
# 파드 배포 위치 확인
kubectl get pods -l app=production-app -o wide

4.2 다양한 노드 셀렉터 조건

하드웨어 타입별 배포

# ssd-app.yaml
apiVersion: v1
kind: Pod
metadata:
  name: ssd-app
spec:
  nodeSelector:
    hardware: ssd
  containers:
  - name: app
    image: redis
    ports:
    - containerPort: 6379
# SSD 노드에만 배포
kubectl apply -f ssd-app.yaml
 
# 배포 결과 확인
kubectl get pod ssd-app -o wide

⚡ 5. 어피니티 (Affinity) 실습

5.1 노드 어피니티 (Node Affinity)

필수 조건 (requiredDuringSchedulingIgnoredDuringExecution)

# node-affinity-required.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: affinity-required-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: affinity-demo
  template:
    metadata:
      labels:
        app: affinity-demo
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: environment
                operator: In
                values: ["production", "staging"]
              - key: zone
                operator: Exists
      containers:
      - name: app
        image: nginx

선호 조건 (preferredDuringSchedulingIgnoredDuringExecution)

# node-affinity-preferred.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: affinity-preferred-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: preferred-demo
  template:
    metadata:
      labels:
        app: preferred-demo
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            preference:
              matchExpressions:
              - key: hardware
                operator: In
                values: ["ssd"]
          - weight: 50
            preference:
              matchExpressions:
              - key: environment
                operator: In
                values: ["production"]
      containers:
      - name: app
        image: nginx
# 어피니티 규칙 적용
kubectl apply -f node-affinity-required.yaml
kubectl apply -f node-affinity-preferred.yaml
 
# 배포 결과 확인
kubectl get pods -l app=affinity-demo -o wide
kubectl get pods -l app=preferred-demo -o wide

5.2 파드 간 어피니티 (Pod Affinity)

파드 어피니티 - 함께 배치

# pod-affinity-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
        tier: frontend
    spec:
      containers:
      - name: web
        image: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cache-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: cache
  template:
    metadata:
      labels:
        app: cache
        tier: cache
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values: ["web"]
            topologyKey: kubernetes.io/hostname
      containers:
      - name: cache
        image: redis

5.3 안티 어피니티 (Anti-Affinity) 실습

파드 안티 어피니티 - 분산 배치

# pod-anti-affinity-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: distributed-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: distributed-app
  template:
    metadata:
      labels:
        app: distributed-app
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values: ["distributed-app"]
            topologyKey: kubernetes.io/hostname
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            preference:
              matchExpressions:
              - key: environment
                operator: In
                values: ["production"]
      containers:
      - name: app
        image: nginx
# 안티 어피니티 배포
kubectl apply -f pod-anti-affinity-demo.yaml
 
# 분산 배치 결과 확인 (각 노드에 하나씩 배치됨)
kubectl get pods -l app=distributed-app -o wide

🔍 6. 고급 스케줄링 시나리오

6.1 복합 조건 스케줄링

# complex-scheduling.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: complex-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: complex-app
  template:
    metadata:
      labels:
        app: complex-app
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: environment
                operator: NotIn
                values: ["development"]
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            preference:
              matchExpressions:
              - key: hardware
                operator: In
                values: ["ssd"]
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values: ["complex-app"]
              topologyKey: kubernetes.io/hostname
      containers:
      - name: app
        image: nginx

6.2 테인트와 톨러레이션 (Taints & Tolerations)

# 노드에 테인트 추가
kubectl taint node minikube-m03 special=true:NoSchedule
 
# 테인트가 있는 노드 확인
kubectl describe node minikube-m03 | grep Taints

톨러레이션을 가진 파드 배포

# toleration-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: toleration-pod
spec:
  tolerations:
  - key: "special"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"
  containers:
  - name: app
    image: nginx
  nodeSelector:
    kubernetes.io/hostname: minikube-m03
# 톨러레이션 파드 배포
kubectl apply -f toleration-demo.yaml
 
# 배포 결과 확인
kubectl get pod toleration-pod -o wide

🧪 7. 실습 검증 및 문제 해결

7.1 스케줄링 문제 진단

# 파드가 스케줄되지 않는 경우
kubectl describe pod <pending-pod-name>
 
# 이벤트 로그 확인
kubectl get events --sort-by=.metadata.creationTimestamp
 
# 스케줄러 로그 확인 (kube-system 네임스페이스)
kubectl logs -n kube-system -l component=kube-scheduler

7.2 노드 리소스 분석

# 노드별 리소스 사용률 확인
kubectl top nodes
 
# 각 노드의 파드 목록
kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=minikube-m02
 
# 노드의 할당 가능한 리소스 vs 요청된 리소스
kubectl describe node minikube-m02 | grep -A 5 "Allocated resources"

🧹 8. 실습 환경 정리

8.1 생성한 리소스 정리

# 배포된 애플리케이션 삭제
kubectl delete deployment test-cordon drain-test production-app
kubectl delete deployment affinity-required-demo affinity-preferred-demo
kubectl delete deployment web-app cache-app distributed-app complex-app
 
# 테스트 파드 삭제
kubectl delete pod ssd-app toleration-pod
 
# 노드 레이블 정리
kubectl label node minikube-m02 environment- hardware- zone-
kubectl label node minikube-m03 environment- hardware- zone-
 
# 노드 테인트 제거
kubectl taint node minikube-m03 special=true:NoSchedule-
 
# 모든 노드 언코든
kubectl uncordon minikube-m02
kubectl uncordon minikube-m03

8.2 최종 상태 확인

# 노드 상태 확인
kubectl get nodes
 
# 남은 파드 확인
kubectl get pods --all-namespaces

📝 실습 요약

✅ 주요 학습 내용

  1. 노드 관리 기초: 상태 확인, 리소스 모니터링
  2. 노드 격리/드레인: 유지보수 시 필수 작업
  3. 레이블 관리: 노드 분류 및 관리
  4. 노드 셀렉터: 간단한 스케줄링 제어
  5. 어피니티/안티어피니티: 고급 스케줄링 전략
  6. 테인트/톨러레이션: 특수 노드 관리

🎯 실무 적용 포인트

  • Blue-Green 배포 시 노드 드레인 활용
  • 하드웨어 특성에 따른 워크로드 분산
  • 가용성 향상을 위한 안티어피니티 적용
  • 특수 워크로드 격리를 위한 테인트 활용

🔗 연관 학습 자료


📅 작성일: 2025.11.19
🏷️ 태그: kubernetes node-management scheduling affinity 실습
🔗 상위: 00_k8s_실습_시리즈_목차