api-server <-> etcd leader 찾기 동작 테스트

진웅·2025년 8월 6일

K8S Basics

목록 보기
33/40

네, 완전히 가능합니다! 🎯 etcdctl과 API Server는 동일한 clientv3 라이브러리를 사용하므로 똑같은 동작을 합니다.

🧪 etcdctl로 API Server 동작 테스트

테스트 1: Smart Routing vs Trial and Error 확인

# 1. 현재 리더 확인
etcdctl --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
  endpoint status --write-out=table

# 2. 디버그 로그로 첫 번째 write 요청 (어디로 가는지 확인)
ETCDCTL_API=3 etcdctl --debug \
  --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
  put test-key-1 test-value-1 2>&1 | grep -E "(picked|dialing|leader)"

# 3. 바로 이어서 두 번째 write 요청 (캐싱된 리더 사용하는지 확인)
ETCDCTL_API=3 etcdctl --debug \
  --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
  put test-key-2 test-value-2 2>&1 | grep -E "(picked|dialing|leader)"

테스트 2: Follower로 강제 요청해서 리다이렉션 확인

# 1. 리더가 etcd-3이라고 가정, follower에만 요청
ETCDCTL_API=3 etcdctl --debug \
  --endpoints=etcd-1:2379 \
  put test-follower-key test-value 2>&1

# 예상 로그:
# DEBUG: dialing to target "etcd-1:2379"  
# ERROR: rpc error: code = FailedPrecondition desc = etcdserver: not leader

테스트 3: 연결 풀 동작 확인

# 여러 번 연속 요청으로 패턴 확인
for i in {1..5}; do
  echo "=== Request $i ==="
  ETCDCTL_API=3 etcdctl --debug \
    --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
    put test-key-$i test-value-$i 2>&1 | \
    grep -E "(picked endpoint|dialing|not leader)" || echo "Direct to leader"
  echo
done

🔍 더 상세한 분석

테스트 4: gRPC 연결 추적

# gRPC 상세 로그 활성화
export GRPC_GO_LOG_VERBOSITY_LEVEL=99
export GRPC_GO_LOG_SEVERITY_LEVEL=info

# 요청 실행
ETCDCTL_API=3 etcdctl --debug \
  --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
  put detailed-test detailed-value

테스트 5: 네트워크 레벨에서 확인

# 터미널 1: 네트워크 패킷 캡처
sudo tcpdump -i any -n port 2379 -A

# 터미널 2: etcdctl 요청
ETCDCTL_API=3 etcdctl \
  --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
  put network-test network-value

# 패킷에서 실제 어느 IP로 요청이 갔는지 확인

📊 실제 테스트 결과 예시

Smart Routing 동작시

$ ETCDCTL_API=3 etcdctl --debug \
  --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
  put smart-test value

# 로그:
DEBUG: etcd client: picked endpoint etcd-3:2379 (cached leader)
DEBUG: grpc: dialing to target "etcd-3:2379"
DEBUG: put request successful

Trial and Error 동작시

$ ETCDCTL_API=3 etcdctl --debug \
  --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
  put trial-test value

# 로그:
DEBUG: etcd client: picked endpoint etcd-2:2379 (round-robin)  
DEBUG: grpc: dialing to target "etcd-2:2379"
ERROR: rpc error: code = FailedPrecondition desc = etcdserver: not leader
DEBUG: etcd client: updating leader to etcd-3:2379  
DEBUG: etcd client: retrying put with leader
DEBUG: grpc: dialing to target "etcd-3:2379"
DEBUG: put request successful on retry

🎛️ API Server와 동일한 환경 만들기

테스트 6: API Server 스타일 설정

# API Server와 동일한 엔드포인트 순서
ENDPOINTS="https://etcd-1:2379,https://etcd-2:2379,https://etcd-3:2379"

# TLS 인증서도 동일하게
ETCDCTL_API=3 etcdctl --debug \
  --endpoints=$ENDPOINTS \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  put api-server-style-test test-value

테스트 7: 부하 분산 패턴 확인

#!/bin/bash
# write-pattern-test.sh

echo "Testing write request distribution pattern..."

# 각 노드별 요청 카운터 초기화
etcd1_count=0
etcd2_count=0  
etcd3_count=0

for i in {1..20}; do
  # 각 요청이 어느 노드로 가는지 확인
  result=$(ETCDCTL_API=3 etcdctl --debug \
    --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
    put test-pattern-$i value-$i 2>&1)
  
  if echo "$result" | grep -q "etcd-1:2379"; then
    etcd1_count=$((etcd1_count + 1))
    echo "Request $i -> etcd-1"
  elif echo "$result" | grep -q "etcd-2:2379"; then
    etcd2_count=$((etcd2_count + 1))
    echo "Request $i -> etcd-2"
  elif echo "$result" | grep -q "etcd-3:2379"; then
    etcd3_count=$((etcd3_count + 1))
    echo "Request $i -> etcd-3"
  fi
  
  sleep 0.1
done

echo "=== Final Distribution ==="
echo "etcd-1: $etcd1_count requests"
echo "etcd-2: $etcd2_count requests"  
echo "etcd-3: $etcd3_count requests"

🚀 리더 변경 시뮬레이션

테스트 8: 동적 리더 변경 대응 확인

# 터미널 1: 지속적인 write 요청
while true; do
  ETCDCTL_API=3 etcdctl --debug \
    --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
    put dynamic-test-$(date +%s) test-value 2>&1 | \
    grep -E "(picked|leader|retry)"
  sleep 1
done

# 터미널 2: 리더 변경 (주의: 테스트 환경에서만!)
kubectl exec -n kube-system etcd-leader -- pkill -STOP etcd
sleep 10
kubectl exec -n kube-system etcd-leader -- pkill -CONT etcd

📈 결과 분석 도구

테스트 9: 로그 분석 스크립트

#!/bin/bash
# analyze-write-behavior.sh

LOG_FILE="etcd-write-test.log"

# 로그 수집
echo "Collecting etcdctl write behavior logs..."
for i in {1..10}; do
  ETCDCTL_API=3 etcdctl --debug \
    --endpoints=etcd-1:2379,etcd-2:2379,etcd-3:2379 \
    put analyze-test-$i value-$i 2>&1 >> $LOG_FILE
done

# 분석
echo "=== Analysis Results ==="
echo "Smart Routing (direct to leader):"
grep -c "picked.*leader" $LOG_FILE

echo "Trial and Error (retry after not leader):"  
grep -c "not leader" $LOG_FILE

echo "Total requests:"
grep -c "put.*successful\|put request successful" $LOG_FILE

🎯 핵심 결론

etcdctl 테스트는 API Server 동작과 100% 동일합니다!

이유:
✅ 동일한 clientv3 라이브러리 사용
✅ 동일한 gRPC 연결 방식
✅ 동일한 리더 발견 메커니즘
✅ 동일한 재시도 로직

따라서:
etcdctl 테스트 결과 = API Server 실제 동작

가장 효과적인 테스트:
1. 연속 요청 테스트 → Smart routing 확인
2. Follower만 지정 테스트 → 리다이렉션 확인
3. 디버그 로그 분석 → 실제 연결 패턴 파악

이렇게 하면 API Server가 실제로 어떻게 etcd와 통신하는지 정확히 알 수 있습니다! 🚀

profile
bytebliss

0개의 댓글