본문으로 건너뛰기

마이그레이션 실행 전략

정보

이 문서는 Gateway API 도입 가이드의 심화 가이드입니다. NGINX Ingress에서 Gateway API로의 실전 마이그레이션 전략을 제공합니다.

1. 사전 요구사항: CRD 설치

모든 Gateway API 구현체는 공통적으로 Kubernetes Gateway API CRDs를 필요로 합니다.

1.1 Gateway API 표준 CRDs

# Gateway API v1.4.0 표준 설치
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml

# 실험적(Experimental) 기능 포함 설치 (선택사항)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml

설치되는 CRDs:

  • gatewayclasses.gateway.networking.k8s.io
  • gateways.gateway.networking.k8s.io
  • httproutes.gateway.networking.k8s.io
  • referencegrants.gateway.networking.k8s.io
  • grpcroutes.gateway.networking.k8s.io (Experimental)
  • tcproutes.gateway.networking.k8s.io (Experimental)
  • tlsroutes.gateway.networking.k8s.io (Experimental)
  • udproutes.gateway.networking.k8s.io (Experimental)

1.2 각 컨트롤러별 추가 설치

AWS Native (ALB + NLB Gateway)

# AWS Load Balancer Controller v3.0+ 설치 (Gateway API 지원)
helm repo add eks https://aws.github.io/eks-charts
helm repo update

# IRSA (IAM Role for Service Account) 생성
eksctl create iamserviceaccount \
--cluster=<클러스터명> \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--role-name AmazonEKSLoadBalancerControllerRole \
--attach-policy-arn=arn:aws:iam::aws:policy/AWSLoadBalancerControllerIAMPolicy \
--approve

# Helm 설치
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<클러스터명> \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
--set enableGatewayAPI=true # Gateway API 활성화 (핵심!)

# 설치 확인
kubectl get deployment -n kube-system aws-load-balancer-controller

NGINX Gateway Fabric

# NGINX Gateway Fabric 설치
kubectl apply -f https://github.com/nginxinc/nginx-gateway-fabric/releases/download/v1.6.0/crds.yaml
kubectl apply -f https://github.com/nginxinc/nginx-gateway-fabric/releases/download/v1.6.0/nginx-gateway.yaml

# 설치 확인
kubectl get pods -n nginx-gateway
kubectl get gatewayclass nginx

Envoy Gateway

# Envoy Gateway 설치
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.3.0 \
--namespace envoy-gateway-system \
--create-namespace

# 설치 확인
kubectl get pods -n envoy-gateway-system
kubectl get gatewayclass envoy-gateway

Cilium Gateway API

Cilium 설치 시 gatewayAPI.enabled=true로 이미 활성화되어 있으므로 별도 설치 불필요.

# GatewayClass 확인
kubectl get gatewayclass cilium

2. 5-Phase 마이그레이션 프로세스


3. Phase별 상세 가이드

Step 1.1: 현재 Ingress 인벤토리 수집

# 모든 Ingress 리소스 목록 추출
kubectl get ingress -A -o json > ingress-inventory.json

# 주요 정보 요약
cat ingress-inventory.json | jq -r '
.items[] |
{
namespace: .metadata.namespace,
name: .metadata.name,
class: .spec.ingressClassName,
hosts: [.spec.rules[].host],
paths: [.spec.rules[].http.paths[].path],
tls: (.spec.tls != null)
}
' > ingress-summary.json

# 통계 요약
echo "=== Ingress Statistics ==="
echo "Total Ingress: $(cat ingress-inventory.json | jq '.items | length')"
echo "With TLS: $(cat ingress-inventory.json | jq '[.items[] | select(.spec.tls != null)] | length')"
echo "Unique Hosts: $(cat ingress-inventory.json | jq -r '[.items[].spec.rules[].host] | unique | length')"

Step 1.2: 기능 매핑 (NGINX Ingress → Gateway API)

🔄 NGINX Ingress → Gateway API 마이그레이션 매핑
기존 Ingress 기능의 Gateway API 대안
host: example.comHTTPRoute.spec.hostnames
직접 매핑직접 매핑
path: /apiHTTPRoute.spec.rules[].matches[].path
직접 매핑직접 매핑
pathType: Prefixpath.type: PathPrefix
동일동일
annotations: rewrite-targetfilters[].type: URLRewrite
표준화됨표준화됨
annotations: rate-limitPolicy Attachment (구현체별 상이)
진행 중표준화 진행 중
annotations: cors-*Policy Attachment
진행 중표준화 진행 중
annotations: auth-*Policy Attachment 또는 외부 인증
외부OAuth2-Proxy 등 권장
annotations: ssl-redirectGateway TLS 리스너 자동 처리
자동화됨자동화됨

Step 1.3: 리스크 평가

# risk-assessment.yaml
risks:
- id: RISK-001
category: 기능 누락
description: "NGINX rate-limit 어노테이션의 직접 대안 없음"
severity: MEDIUM
mitigation: "AWS WAF 또는 Envoy Rate Limit 서비스 사용"

- id: RISK-002
category: 다운타임
description: "Cilium ENI 모드 마이그레이션 시 다운타임 발생"
severity: HIGH
mitigation: "블루-그린 클러스터 전환 또는 유지보수 창 설정"

- id: RISK-003
category: 학습 곡선
description: "팀의 Gateway API 경험 부족"
severity: LOW
mitigation: "Phase 2 PoC에서 충분한 테스트 기간 확보"

4. 검증 스크립트

#!/bin/bash
# validate-httproute.sh

set -e

NAMESPACE=${1:-default}
HTTPROUTE_NAME=${2:-}

if [ -z "$HTTPROUTE_NAME" ]; then
echo "Usage: $0 <namespace> <httproute-name>"
exit 1
fi

echo "=== HTTPRoute Validation ==="
echo "Namespace: $NAMESPACE"
echo "HTTPRoute: $HTTPROUTE_NAME"
echo ""

# 1. HTTPRoute 존재 확인
if ! kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE &>/dev/null; then
echo "❌ HTTPRoute not found"
exit 1
fi
echo "✅ HTTPRoute exists"

# 2. Accepted Condition 확인
ACCEPTED=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.status.parents[0].conditions[?(@.type=="Accepted")].status}')
if [ "$ACCEPTED" != "True" ]; then
REASON=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.status.parents[0].conditions[?(@.type=="Accepted")].reason}')
echo "❌ HTTPRoute not accepted. Reason: $REASON"
exit 1
fi
echo "✅ HTTPRoute accepted by Gateway"

# 3. Programmed Condition 확인
PROGRAMMED=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.status.parents[0].conditions[?(@.type=="Programmed")].status}')
if [ "$PROGRAMMED" != "True" ]; then
REASON=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.status.parents[0].conditions[?(@.type=="Programmed")].reason}')
echo "❌ HTTPRoute not programmed. Reason: $REASON"
exit 1
fi
echo "✅ HTTPRoute programmed in dataplane"

# 4. Backend 서비스 확인
BACKEND_SERVICES=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.spec.rules[*].backendRefs[*].name}')
for svc in $BACKEND_SERVICES; do
if ! kubectl get service $svc -n $NAMESPACE &>/dev/null; then
echo "❌ Backend service not found: $svc"
exit 1
fi

ENDPOINTS=$(kubectl get endpoints $svc -n $NAMESPACE -o jsonpath='{.subsets[*].addresses[*].ip}' | wc -w)
if [ "$ENDPOINTS" -eq 0 ]; then
echo "⚠️ Warning: Service $svc has no endpoints"
else
echo "✅ Backend service $svc has $ENDPOINTS endpoint(s)"
fi
done

# 5. Gateway 주소 확인
PARENT_GATEWAY=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.spec.parentRefs[0].name}')
PARENT_NAMESPACE=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.spec.parentRefs[0].namespace}')
PARENT_NAMESPACE=${PARENT_NAMESPACE:-$NAMESPACE}

GATEWAY_ADDRESS=$(kubectl get gateway $PARENT_GATEWAY -n $PARENT_NAMESPACE -o jsonpath='{.status.addresses[0].value}')
if [ -z "$GATEWAY_ADDRESS" ]; then
echo "❌ Gateway has no address assigned"
exit 1
fi
echo "✅ Gateway address: $GATEWAY_ADDRESS"

# 6. 실제 HTTP 요청 테스트
HOSTNAMES=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.spec.hostnames[*]}')
FIRST_HOST=$(echo $HOSTNAMES | awk '{print $1}')
FIRST_PATH=$(kubectl get httproute $HTTPROUTE_NAME -n $NAMESPACE -o jsonpath='{.spec.rules[0].matches[0].path.value}')

echo ""
echo "=== HTTP Request Test ==="
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: $FIRST_HOST" http://$GATEWAY_ADDRESS$FIRST_PATH --max-time 5)

if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 400 ]; then
echo "✅ HTTP request successful (HTTP $HTTP_CODE)"
else
echo "❌ HTTP request failed (HTTP $HTTP_CODE)"
exit 1
fi

echo ""
echo "=== All Checks Passed ==="

사용 예시:

chmod +x validate-httproute.sh
./validate-httproute.sh production api-route

5. 문제 해결

5.1 일반적인 이슈 및 해결 방법

🔧 Gateway API 트러블슈팅 가이드
일반적인 문제와 해결 방법
HTTPRoute Accepted=False
원인: Gateway가 HTTPRoute를 거부함
해결: 1. ReferenceGrant 확인 2. GatewayClass 올바른지 확인 3. 네임스페이스 정책 확인
HTTPRoute Programmed=False
원인: 데이터플레인 구성 실패
해결: 1. 백엔드 Service 존재 확인 2. 컨트롤러 로그 확인 3. TLS Secret 유효성 확인
503 Service Unavailable
원인: 백엔드 엔드포인트 없음
해결: 1. Service의 Endpoints 확인 2. Pod selector 일치 여부 확인 3. Pod 상태 확인 (Ready)
TLS 인증서 오류
원인: Secret이 올바르지 않음
해결: 1. Secret 타입 kubernetes.io/tls 확인 2. tls.crt, tls.key 존재 확인 3. 인증서 유효기간 확인
404 Not Found
원인: 경로 매칭 실패
해결: 1. PathPrefix vs Exact 타입 확인 2. 대소문자 구분 여부 확인 3. URL 인코딩 확인
Gateway 주소 없음
원인: LoadBalancer 생성 실패
해결: 1. 클라우드 제공자 쿼터 확인 2. 서브넷 IP 고갈 여부 확인 3. 어노테이션 오타 확인

5.2 컨트롤러별 디버깅 명령어

AWS Load Balancer Controller

# 컨트롤러 로그 확인
kubectl logs -n kube-system deployment/aws-load-balancer-controller --tail=100 -f

# Gateway의 실제 NLB 확인
kubectl get gateway <name> -n <namespace> -o jsonpath='{.metadata.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-name}'

# NLB의 Target Group 상태 확인
aws elbv2 describe-target-health --target-group-arn <arn>

# HTTPRoute 이벤트 확인
kubectl describe httproute <name> -n <namespace>

Cilium Gateway API

# Cilium Operator 로그
kubectl logs -n kube-system deployment/cilium-operator --tail=100 -f

# Envoy 구성 덤프
kubectl exec -n kube-system ds/cilium -- cilium envoy config dump > envoy-config.json

# HTTPRoute 라우팅 테이블 확인
kubectl exec -n kube-system ds/cilium -- cilium service list

# 플로우 모니터링 (Gateway 관련)
hubble observe --protocol http --port 443

# Gateway 상태 확인
cilium status --wait

NGINX Gateway Fabric

# NGINX Gateway 로그
kubectl logs -n nginx-gateway deployment/nginx-gateway --tail=100 -f

# NGINX 구성 확인
kubectl exec -n nginx-gateway deployment/nginx-gateway -- nginx -T

# HTTPRoute 매핑 확인
kubectl describe httproute <name> -n <namespace>

# 접근 로그 실시간 확인
kubectl logs -n nginx-gateway deployment/nginx-gateway -f | grep "HTTP/1.1"

Envoy Gateway

# Envoy Gateway 컨트롤러 로그
kubectl logs -n envoy-gateway-system deployment/envoy-gateway --tail=100 -f

# Envoy Proxy 로그 (데이터플레인)
kubectl logs -n envoy-gateway-system deployment/envoy-<gateway-name> --tail=100 -f

# Envoy 관리 인터페이스 포트 포워딩
kubectl port-forward -n envoy-gateway-system deployment/envoy-<gateway-name> 19000:19000

# 브라우저에서 http://localhost:19000 접속하여 stats, config 확인

# xDS 구성 덤프
curl http://localhost:19000/config_dump > envoy-xds-config.json

공통 디버깅

# Gateway 상태 상세 확인
kubectl get gateway <name> -n <namespace> -o yaml

# HTTPRoute 상태 상세 확인
kubectl get httproute <name> -n <namespace> -o yaml

# 백엔드 Service 엔드포인트 확인
kubectl get endpoints <service-name> -n <namespace>

# Pod가 Ready 상태인지 확인
kubectl get pods -n <namespace> -l <selector>

# 네트워크 정책 확인 (트래픽 차단 여부)
kubectl get networkpolicies -n <namespace>

# 이벤트 확인 (최근 10분)
kubectl get events -n <namespace> --sort-by='.lastTimestamp' | tail -20

관련 문서