EKS 워커 노드 강제 종료 시 웹 서비스 장애 테스트

정성헌·2026년 3월 30일

실습 개요

EKS 클러스터를 구성하고 Cluster Autoscaler로 워커 노드 2개를 운영하는 환경을 구성합니다.
이후 EC2 콘솔에서 노드 1개를 강제 종료했을 때 로드밸런서에 연결된 웹 서비스에 장애가 발생하는지 직접 확인합니다.


실습 목표

  • EKS 클러스터 생성 및 Cluster Autoscaler 설정

  • 워커 노드 2개 환경에서 웹 서버 배포 및 External IP 접속 확인

  • 노드 1개 강제 종료 후 서비스 장애 여부 확인

  • 파드 Replica 수에 따른 고가용성 차이 비교


핵심 개념

Cluster Autoscaler

Cluster Autoscaler는 클러스터의 리소스 사용량에 따라 워커 노드(EC2 인스턴스)를 자동으로 늘리거나 줄여주는 기능입니다.
minSize, maxSize, desiredCapacity 값을 설정하면 그 범위 안에서 노드 수가 자동으로 조절됩니다.

이번 실습에서는 desiredCapacity: 2로 워커 노드를 2개로 고정하여 시작합니다.

EC2 강제 종료 시 클러스터 내부에서 일어나는 일

EC2 콘솔에서 인스턴스를 강제 종료(terminate)하면 쿠버네티스의 정상적인 노드 제거 절차(drain)를 거치지 않습니다.
이 경우 아래와 같은 순서로 이벤트가 발생합니다.

1. EC2 콘솔에서 인스턴스 terminate
         ↓
2. 쿠버네티스가 해당 노드를 NotReady 상태로 감지 (약 40초 후)
         ↓
3. 해당 노드의 파드를 Terminating 처리
         ↓
4. 남은 노드로 파드 재스케줄링 시작
         ↓
5. ASG(Auto Scaling Group)가 종료된 인스턴스 감지 → 새 인스턴스 자동 생성
         ↓
6. 새 노드가 클러스터에 합류 (약 2~3분 소요)

파드 재스케줄링이 완료되기 전까지의 시간 동안 서비스 순단이 발생할 수 있습니다.


결론 — 장애 여부는 Replica 설정에 달려 있습니다

시나리오 1 : Replica = 1 (파드 1개)

아키텍처 구조는 아래와 같습니다.

[ 로드밸런서 ]
      |
  ┌───┴────────────────────────┐
  │                            │
노드A [파드 ●]           노드B [     ]

노드A를 강제 종료하면 아래와 같이 진행됩니다.

노드A 강제 종료
      ↓
파드 소멸 → 노드B로 재스케줄링 시도
      ↓
재스케줄링 완료까지 약 1~3분 동안
External IP 접속 시 → 502 / 503 에러 발생 ❌

파드가 1개뿐이므로 해당 노드가 종료되는 순간 서비스가 중단됩니다.


시나리오 2 : Replica = 2, 각 노드에 파드 분산 배치

아키텍처 구조는 아래와 같습니다.

[ 로드밸런서 ]
      |
  ┌───┴────────────────────────┐
  │                            │
노드A [파드 ●]           노드B [파드 ●]

노드A를 강제 종료하면 아래와 같이 진행됩니다.

노드A 강제 종료
      ↓
노드B의 파드는 살아있음
로드밸런서 → 노드B로만 트래픽 전달
      ↓
External IP 접속 시 → 정상 200 OK ✅

파드가 서로 다른 노드에 분산되어 있으므로 노드 1개가 종료되어도 서비스가 유지됩니다.


시나리오 3 : Replica = 2, 그러나 같은 노드에 몰려 있는 경우

아키텍처 구조는 아래와 같습니다.

[ 로드밸런서 ]
      |
  ┌───┴────────────────────────┐
  │                            │
노드A [파드 ● 파드 ●]    노드B [     ]

노드A를 강제 종료하면 아래와 같이 진행됩니다.

노드A 강제 종료
      ↓
파드 2개 동시 소멸 → 장애 발생 ❌

Replica를 늘려도 같은 노드에 파드가 몰려 있으면 고가용성 효과가 없습니다.
topologySpreadConstraints 설정을 통해 파드를 서로 다른 노드에 강제로 분산 배치해야 합니다.


시나리오별 결과 비교

설정노드 1개 종료 시 결과이유
Replica 1개❌ 장애 발생 (약 1~3분)파드 재스케줄링 전까지 서비스 다운
Replica 2개 + 분산 배치✅ 정상 유지나머지 노드의 파드가 트래픽 수신
Replica 2개 + 동일 노드 배치❌ 장애 발생두 파드가 같은 노드에 있어 의미 없음

실습 순서

1단계 — 클러스터 생성

eksctl을 사용하여 워커 노드 2개짜리 클러스터를 생성합니다.

# cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: ha-test-cluster
  region: ap-northeast-2

managedNodeGroups:
  - name: worker-ng
    instanceType: t3.medium
    minSize: 1
    maxSize: 4
    desiredCapacity: 2
    availabilityZones:
      - ap-northeast-2a
      - ap-northeast-2b
eksctl create cluster -f cluster.yaml

2단계 — 웹 서버 배포

Replica를 2개로 설정하고, topologySpreadConstraints로 각 노드에 파드가 1개씩 배치되도록 강제합니다.
또한 readinessProbe를 설정하여 로드밸런서가 비정상 파드로 트래픽을 전달하지 않도록 합니다.

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: web-app
      containers:
        - name: web
          image: nginx
          ports:
            - containerPort: 80
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  type: LoadBalancer
  selector:
    app: web-app
  ports:
    - port: 80
      targetPort: 80
kubectl apply -f deployment.yaml

# External IP 확인 (발급까지 1~2분 소요)
kubectl get svc web-svc

3단계 — 웹 서버 접속 확인

EXTERNAL_IP=$(kubectl get svc web-svc -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
curl http://$EXTERNAL_IP

정상적으로 nginx 응답이 오면 배포가 완료된 것입니다.


4단계 — 노드 강제 종료 테스트

터미널 2개를 열어 동시에 진행합니다.

터미널 1 — 지속적으로 HTTP 요청 전송

while true; do
  curl -s -o /dev/null -w "%{http_code}\n" http://$EXTERNAL_IP
  sleep 1
done

터미널 2 — 파드 상태 실시간 모니터링

watch kubectl get pods -o wide

이 상태에서 AWS EC2 콘솔 → 인스턴스 선택 → 인스턴스 종료를 실행합니다.


5단계 — 결과 확인

# 노드 상태 확인
kubectl get nodes

# 파드 재배치 확인
kubectl get pods -o wide -w

# 클러스터 이벤트 로그 확인
kubectl get events --sort-by=.metadata.creationTimestamp

정리 — 노드 장애에 강한 구성을 위한 4가지 조건

이번 실습을 통해 단순히 노드를 2개 운영하는 것만으로는 고가용성이 보장되지 않는다는 점을 확인할 수 있습니다.
서비스 무중단을 달성하기 위해서는 아래 4가지 조건이 갖춰져야 합니다.

1. Replica ≥ 2
파드가 1개이면 해당 노드 종료 시 단일 장애점(SPOF)이 됩니다.

2. 파드 분산 배치 (topologySpreadConstraints)
Replica를 늘리더라도 파드가 같은 노드에 배치되면 의미가 없습니다.
노드 또는 AZ별로 분산 배치되어야 합니다.

3. Readiness Probe
로드밸런서가 준비되지 않은 파드로 트래픽을 전달하지 않도록 헬스체크를 설정해야 합니다.

4. 다중 AZ 구성
단일 AZ만 사용하는 경우 AZ 자체 장애 시 대응이 불가능합니다.

이 조건들이 갖춰졌을 때 비로소 노드 1개가 종료되어도 서비스가 중단 없이 운영될 수 있습니다.

profile
develop myself

0개의 댓글