이 문서에서는 VPC 네트워크 내의 트래픽을 두 개의 서로 다른 GKE 클러스터에서 실행되는 애플리케이션으로 라우팅하는 내부 멀티 클러스터 게이트웨이를 배포하는 실제 예를 안내합니다.
멀티 클러스터 게이트웨이는 여러 GKE 클러스터에 배포된 서비스의 트래픽을 관리하는 강력한 방법을 제공합니다. Google의 글로벌 부하 분산 인프라를 사용하면 애플리케이션의 단일 진입점을 만들어 관리를 간소화하고 안정성을 개선할 수 있습니다.이 튜토리얼에서는 샘플 store 애플리케이션을 사용하여 온라인 쇼핑 서비스가 개별 팀에 의해 소유 및 운영되고 공유되는 GKE 클러스터의 Fleet 간에 배포되는 실제 시나리오를 시뮬레이션합니다.
시작하기 전에
멀티 클러스터 게이트웨이는 배포되기 전 몇 가지 환경적인 준비가 요구됩니다. 계속하기 전에 멀티 클러스터 게이트웨이 환경 준비의 단계를 따르세요.
마지막으로 환경에서 컨트롤러를 사용하기 전에 GKE Gateway Controller 제한사항 및 알려진 문제를 검토하세요.
리전 간 내부 멀티 클러스터 게이트웨이 배포
여러 리전의 GKE 클러스터에서 내부 레이어 7 부하 분산을 제공하는 멀티 클러스터 게이트웨이를 배포할 수 있습니다. 이러한 게이트웨이는 gke-l7-cross-regional-internal-managed-mc GatewayClass를 사용합니다. 이 GatewayClass는 Google Cloud 에서 관리하고 VPC 네트워크 내 클라이언트가 액세스할 수 있는 내부 VIP를 사용하는 리전 간 내부 애플리케이션 부하 분산기를 프로비저닝합니다. 이러한 게이트웨이는 해당 리전의 주소를 요청하는 게이트웨이를 사용하여 원하는 지역의 프런트엔드에서 노출할 수 있습니다. 내부 VIP는 단일 IP 주소이거나 게이트웨이에 지정된 리전당 하나의 IP 주소가 있는 여러 리전의 IP 주소일 수 있습니다. 트래픽은 요청을 처리할 수 있는 가장 가까운 정상 백엔드 GKE 클러스터로 전달됩니다.
기본 요건
프로젝트 ID로
gcloud환경을 구성하여 프로젝트와 셸을 설정합니다.export PROJECT_ID="YOUR_PROJECT_ID" gcloud config set project ${PROJECT_ID}서로 다른 리전에 GKE 클러스터를 만듭니다.
이 예시에서는 두 개의 클러스터, 즉
us-west1의gke-west-1과us-east1의gke-east-1을 사용합니다. 게이트웨이 API가 사용 설정(--gateway-api=standard)되고 클러스터가 Fleet에 등록되어 있는지 확인합니다.gcloud container clusters create gke-west-1 \ --location=us-west1-a \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --project=${PROJECT_ID} \ --enable-fleet \ --gateway-api=standard gcloud container clusters create gke-east-1 \ --location=us-east1-c \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --project=${PROJECT_ID} \ --enable-fleet \ --gateway-api=standard쉽게 액세스할 수 있도록 컨텍스트 이름을 바꿉니다.
gcloud container clusters get-credentials gke-west-1 \ --location=us-west1-a \ --project=${PROJECT_ID} gcloud container clusters get-credentials gke-east-1 \ --location=us-east1-c \ --project=${PROJECT_ID} kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west1 kubectl config rename-context gke_${PROJECT_ID}_us-east1-c_gke-east-1 gke-east1멀티 클러스터 서비스(MCS) 및 멀티 클러스터 인그레스(MCI/게이트웨이)를 사용 설정합니다.
gcloud container fleet multi-cluster-services enable --project=${PROJECT_ID} # Set the config membership to one of your clusters (e.g., gke-west-1) # This cluster will be the source of truth for multi-cluster Gateway and Route resources. gcloud container fleet ingress enable \ --config-membership=projects/${PROJECT_ID}/locations/us-west1/memberships/gke-west-1 \ --project=${PROJECT_ID}프록시 전용 서브넷을 구성합니다. GKE 클러스터가 있고 부하 분산기가 작동할 각 리전에 프록시 전용 서브넷이 필요합니다. 리전 간 내부 애플리케이션 부하 분산기를 사용하려면 이 서브넷 용도를
GLOBAL_MANAGED_PROXY로 설정해야 합니다.# Proxy-only subnet for us-west1 gcloud compute networks subnets create us-west1-proxy-only-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=us-west1 \ --network=default \ --range=10.129.0.0/23 # Choose an appropriate unused CIDR range # Proxy-only subnet for us-east1 gcloud compute networks subnets create us-east1-proxy-only-subnet \ --purpose=GLOBAL_MANAGED_PROXY \ --role=ACTIVE \ --region=us-east1 \ --network=default \ --range=10.130.0.0/23 # Choose an appropriate unused CIDR range기본 네트워크를 사용하지 않는 경우
default를 VPC 네트워크 이름으로 바꿉니다. CIDR 범위가 고유하고 겹치지 않는지 확인합니다.store와 같은 데모 애플리케이션을 두 클러스터에 모두 배포합니다.gke-networking-recipes의store.yaml파일 예시에서는store네임스페이스와 배포를 만듭니다.kubectl apply --context gke-west1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml kubectl apply --context gke-east1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml각 클러스터에서 Kubernetes
Service리소스와ServiceExport리소스를 만들어 각 클러스터의 서비스를 내보내면 Fleet 전반에서 서비스를 검색할 수 있게 됩니다. 다음 예시에서는 각 클러스터에서 일반store서비스와 리전별 서비스(store-west-1,store-east-1)를 모두store네임스페이스 내에서 내보냅니다.gke-west1에 적용됩니다.cat << EOF | kubectl apply --context gke-west1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: store --- apiVersion: v1 kind: Service metadata: name: store-west-1 # Specific to this cluster namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-west-1 # Exporting the region-specific service namespace: store EOFgke-east1에 적용됩니다.cat << EOF | kubectl apply --context gke-east1 -f - apiVersion: v1 kind: Service metadata: name: store namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store namespace: store --- apiVersion: v1 kind: Service metadata: name: store-east-1 # Specific to this cluster namespace: store spec: selector: app: store ports: - port: 8080 targetPort: 8080 --- kind: ServiceExport apiVersion: net.gke.io/v1 metadata: name: store-east-1 # Exporting the region-specific service namespace: store EOFServiceImports 확인:
ServiceImport리소스가store네임스페이스 내의 각 클러스터에 생성되었는지 확인합니다. 생성하는 데 몇 분 정도 걸릴 수 있습니다.bash kubectl get serviceimports --context gke-west1 -n store kubectl get serviceimports --context gke-east1 -n storestore,store-west-1,store-east-1이 나열되어야 합니다(또는 전파에 따라 관련 항목이 표시될 수 있음).
내부 멀티 리전 게이트웨이 구성
gke-l7-cross-regional-internal-managed-mc GatewayClass를 참조하는 Gateway 리소스를 정의합니다. 이 매니페스트를 지정된 구성 클러스터(예: gke-west-1)에 적용합니다.
spec.addresses 필드를 사용하면 특정 리전에서 임시 IP 주소를 요청하거나 사전 할당된 고정 IP 주소를 사용할 수 있습니다.
임시 IP 주소를 사용하려면 다음
Gateway매니페스트를cross-regional-gateway.yaml로 저장합니다.# cross-regional-gateway.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-cross-region-gateway namespace: store # Namespace for the Gateway resource spec: gatewayClassName: gke-l7-cross-regional-internal-managed-mc addresses: # Addresses across regions. Address value is allowed to be empty or matching # the region name. - type: networking.gke.io/ephemeral-ipv4-address/us-west1 value: "us-west1" - type: networking.gke.io/ephemeral-ipv4-address/us-east1 value: "us-east1" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute # Only allow HTTPRoute to attach다음 목록에서는 이전 YAML 파일의 일부 필드를 정의합니다.
metadata.namespace: 게이트웨이 리소스가 생성된 네임스페이스(예:store)spec.gatewayClassName: GatewayClass의 이름.gke-l7-cross-regional-internal-managed-mc여야 합니다.spec.listeners.allowedRoutes.kinds: 연결할 수 있는 경로 객체의 종류입니다(예:HTTPRoute).spec.addresses:type: networking.gke.io/ephemeral-ipv4-address/REGION: 임시 IP 주소를 요청합니다.value: 주소의 리전을 지정합니다(예:"us-west1"또는"us-east1").
매니페스트를 구성 클러스터(예:
gke-west1)에 적용합니다.kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
게이트웨이에 HTTPRoute 연결
트래픽 라우팅을 관리하는 HTTPRoute 리소스를 정의하고 이를 구성 클러스터에 적용합니다.
다음
HTTPRoute매니페스트를store-route.yaml로 저장합니다.# store-route.yaml kind: HTTPRoute apiVersion: gateway.networking.k8s.io/v1 metadata: name: store-route namespace: store labels: gateway: cross-regional-internal spec: parentRefs: - name: internal-cross-region-gateway namespace: store # Namespace where the Gateway is deployed hostnames: - "store.example.internal" # Hostname clients will use rules: - matches: # Rule for traffic to /west - path: type: PathPrefix value: /west backendRefs: - group: net.gke.io # Indicates a multi-cluster ServiceImport kind: ServiceImport name: store-west-1 # Targets the ServiceImport for the west cluster port: 8080 - matches: # Rule for traffic to /east - path: type: PathPrefix value: /east backendRefs: - group: net.gke.io kind: ServiceImport name: store-east-1 # Targets the ServiceImport for the east cluster port: 8080 - backendRefs: # Default rule for other paths (e.g., /) - group: net.gke.io kind: ServiceImport name: store # Targets the generic 'store' ServiceImport (any region) port: 8080다음 목록에서는 이전 YAML 파일의 일부 필드를 정의합니다.
spec.parentRefs: 이 경로를store네임스페이스의internal-cross-region-gateway에 연결합니다.spec.hostnames: 클라이언트가 서비스에 액세스하는 데 사용하는 호스트 이름을 나타냅니다.spec.rules: 라우팅 로직을 정의합니다. 이 예시에서는 경로 기반 라우팅을 사용합니다./west트래픽은store-west-1ServiceImport로 이동합니다./east트래픽은store-east-1ServiceImport로 이동합니다./와 같은 다른 모든 트래픽은 일반storeServiceImport로 이동합니다.
backendRefs:group: net.gke.io및kind: ServiceImport는 멀티 클러스터 서비스를 타겟팅합니다.
HTTPRoute매니페스트를 구성 클러스터에 적용합니다.kubectl apply --context gke-west1 -f store-route.yaml
게이트웨이 및 경로 상태 확인
게이트웨이 상태를 확인합니다.
kubectl get gateway internal-cross-region-gateway -n store -o yaml --context gke-west1type:Programmedandstatus: "True". You should see IP addresses assigned in thestatus.addressesfield, corresponding to the regions you specified (e.g., one forus-west1and one forus-east1`) 조건이 있는지 확인합니다.HTTPRoute 상태를 확인합니다.
kubectl get httproute store-route -n store -o yaml --context gke-west1type: Accepted(또는ResolvedRefs) 및status: "True"인status.parents[].conditions의 조건을 찾습니다.
트래픽 확인
게이트웨이에 IP 주소를 할당한 후 VPC 네트워크 내에 있고 리전 중 하나에 있거나 게이트웨이 IP 주소에 연결할 수 있는 리전에 있는 클라이언트 VM에서 트래픽을 테스트할 수 있습니다.
게이트웨이 IP 주소를 가져옵니다.
다음 명령어는 JSON 출력을 파싱하려고 시도합니다. 정확한 구조에 따라
jsonpath를 조정해야 할 수도 있습니다.kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".이 명령어의 출력에는
VIP1_WEST또는VIP2_EAST와 같은 VIP가 포함되어야 합니다.테스트 요청을 보냅니다. VPC의 클라이언트 VM에서 다음을 실행합니다.
# Assuming VIP_WEST is an IP in us-west1 and VIP_EAST is an IP in us-east1 # Traffic to /west should ideally be served by gke-west-1 curl -H "host: store.example.internal" http://VIP_WEST/west curl -H "host: store.example.internal" http://VIP_EAST/west # Still targets store-west-1 due to path # Traffic to /east should ideally be served by gke-east-1 curl -H "host: store.example.internal" http://VIP_WEST/east # Still targets store-east-1 due to path curl -H "host: store.example.internal" http://VIP_EAST/east # Traffic to / (default) could be served by either cluster curl -H "host: store.example.internal" http://VIP_WEST/ curl -H "host: store.example.internal" http://VIP_EAST/응답에는
cluster_name또는zone과 같은 요청을 처리한 백엔드 포드를 나타내는store애플리케이션의 세부정보가 포함되어야 합니다.
고정 IP 주소 사용
임시 IP 주소 대신 사전 할당된 고정 내부 IP 주소를 사용할 수 있습니다.
사용하려는 리전에 고정 IP 주소를 만듭니다.
gcloud compute addresses create cross-region-gw-ip-west --region us-west1 --subnet default --project=${PROJECT_ID} gcloud compute addresses create cross-region-gw-ip-east --region us-east1 --subnet default --project=${PROJECT_ID}기본 서브넷을 사용하지 않는 경우
default를 할당하려는 IP 주소가 있는 서브넷의 이름으로 바꿉니다. 이러한 서브넷은 프록시 전용 서브넷이 아닌 일반 서브넷입니다.cross-regional-gateway.yaml파일에서spec.addresses섹션을 수정하여 게이트웨이 매니페스트를 업데이트합니다.# cross-regional-gateway-static-ip.yaml kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: internal-cross-region-gateway # Or a new name if deploying alongside namespace: store spec: gatewayClassName: gke-l7-cross-regional-internal-managed-mc addresses: - type: networking.gke.io/named-address-with-region # Use for named static IP value: "regions/us-west1/addresses/cross-region-gw-ip-west" - type: networking.gke.io/named-address-with-region value: "regions/us-east1/addresses/cross-region-gw-ip-east" listeners: - name: http protocol: HTTP port: 80 allowedRoutes: kinds: - kind: HTTPRoute업데이트된 게이트웨이 매니페스트를 적용합니다.
kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
기본값이 아닌 서브넷에 대한 특별 고려사항
기본값이 아닌 서브넷을 사용할 때는 다음 사항을 고려하세요.
동일한 VPC 네트워크: 고정 IP 주소, 프록시 전용 서브넷, GKE 클러스터와 같은 모든 사용자 생성 리소스가 동일한 VPC 네트워크 내에 있어야 합니다.
주소 서브넷: 게이트웨이의 고정 IP 주소를 만들면 지정된 리전의 일반 서브넷에서 할당됩니다.
클러스터 서브넷 이름 지정: 각 리전에는 MCG 구성 클러스터가 있는 서브넷과 이름이 동일한 서브넷이 있어야 합니다.
- 예를 들어
gke-west-1구성 클러스터가projects/YOUR_PROJECT/regions/us-west1/subnetworks/my-custom-subnet에 있는 경우 주소를 요청하는 리전에도my-custom-subnet서브넷이 있어야 합니다.us-east1및us-centra1리전의 주소를 요청하는 경우 이름이my-custom-subnet이라는 서브넷도 해당 리전에 있어야 합니다.
- 예를 들어
삭제
이 문서의 연습을 완료한 후에는 다음 단계에 따라 자신의 계정에 원치 않는 비용이 발생하지 않도록 리소스를 삭제합니다.
다른 목적으로 등록할 필요가 없으면 Fleet에서 클러스터를 등록 취소합니다.
multiclusterservicediscovery기능을 사용 중지합니다.gcloud container fleet multi-cluster-services disable멀티 클러스터 인그레스 사용 중지
gcloud container fleet ingress disableAPI를 사용 중지합니다.
gcloud services disable \ multiclusterservicediscovery.googleapis.com \ multiclusteringress.googleapis.com \ trafficdirector.googleapis.com \ --project=PROJECT_ID
문제 해결
내부 게이트웨이의 프록시 전용 서브넷이 없음
내부 게이트웨이에 다음 이벤트가 표시되면 프록시 전용 서브넷이 해당 리전에 없습니다. 이 문제를 해결하려면 프록시 전용 서브넷을 배포합니다.
generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.
정상 업스트림 없음
증상:
게이트웨이를 만들 때 백엔드 서비스에 액세스할 수 없는 경우 다음 문제가 발생할 수 있습니다(503 응답 코드).
no healthy upstream
이유:
이 오류 메시지는 상태 점검 프로버가 정상 백엔드 서비스를 찾을 수 없음을 나타냅니다. 백엔드 서비스가 정상일 수 있지만 상태 점검을 맞춤설정해야 할 수도 있습니다.
해결 방법:
이 문제를 해결하려면 HealthCheckPolicy를 사용하여 애플리케이션 요구사항(예: /health)에 따라 상태 점검을 맞춤설정합니다.
다음 단계
- 게이트웨이 컨트롤러 자세히 알아보기