용량 기반 부하 분산을 위해 멀티 클러스터 게이트웨이 배포

이 문서에서는 서로 다른 리전의 두 GKE 클러스터에 샘플 애플리케이션을 배포하는 방법을 안내하고, 서비스 용량 한도를 초과할 때 멀티 클러스터 게이트웨이가 트래픽을 지능적으로 라우팅하는 방법을 보여줍니다.

용량 기반 부하 분산은 안정성과 복원력이 뛰어난 애플리케이션을 빌드하는 데 도움이 되는 멀티 클러스터 게이트웨이의 기능입니다. 서비스의 용량을 정의하면 서비스가 과부하되지 않도록 보호하고 사용자에게 일관된 환경을 제공할 수 있습니다. 한 클러스터의 서비스가 용량에 도달하면 부하 분산기가 사용 가능한 용량이 있는 다른 클러스터로 트래픽을 자동으로 리디렉션합니다. 트래픽 관리에 대한 자세한 내용은 GKE 트래픽 관리를 참고하세요.

이 튜토리얼에서는 샘플 store 애플리케이션을 사용하여 온라인 쇼핑 서비스가 개별 팀에 의해 소유 및 운영되고 공유되는 GKE 클러스터의 Fleet 간에 배포되는 실제 시나리오를 시뮬레이션합니다.

시작하기 전에

멀티 클러스터 게이트웨이는 배포되기 전 몇 가지 환경적인 준비가 요구됩니다. 계속하기 전에 멀티 클러스터 게이트웨이 환경 준비의 단계를 따르세요.

  1. GKE 클러스터를 배포합니다.

  2. 아직 등록하지 않은 경우 클러스터를 Fleet에 등록합니다.

  3. 멀티 클러스터 서비스 및 멀티 클러스터 게이트웨이 컨트롤러를 사용 설정합니다.

마지막으로 환경에서 컨트롤러를 사용하기 전에 GKE Gateway Controller 제한사항 및 알려진 문제를 검토하세요.

용량 기반 부하 분산 배포

이 섹션의 연습에서는 서로 다른 리전에서 2개의 GKE 클러스터 간에 애플리케이션을 배포하여 전역 부하 분산 및 서비스 용량 개념을 설명합니다. 클러스터 및 리전 간에 트래픽이 부하 분산되는 방식을 보여주기 위해 여러 초당 요청 수(RPS) 수준으로 생성된 트래픽이 전송됩니다.

다음 다이어그램은 배포할 토폴로지와 트래픽이 서비스 용량을 초과할 때 클러스터 및 리전 간에 트래픽이 오버플로되는 방식을 보여줍니다.

한 클러스터에서 다른 클러스터로 오버플로되는 트래픽

개발 환경 준비

  1. 멀티 클러스터 게이트웨이 환경 준비에 따라 환경을 준비합니다.

  2. GatewayClass 리소스가 구성 클러스터에 설치되었는지 확인하세요.

    kubectl get gatewayclasses --context=gke-west-1
    

    출력은 다음과 비슷합니다.

    NAME                                  CONTROLLER                  ACCEPTED   AGE
    gke-l7-global-external-managed        networking.gke.io/gateway   True       16h
    gke-l7-global-external-managed-mc     networking.gke.io/gateway   True       14h
    gke-l7-gxlb                           networking.gke.io/gateway   True       16h
    gke-l7-gxlb-mc                        networking.gke.io/gateway   True       14h
    gke-l7-regional-external-managed      networking.gke.io/gateway   True       16h
    gke-l7-regional-external-managed-mc   networking.gke.io/gateway   True       14h
    gke-l7-rilb                           networking.gke.io/gateway   True       16h
    gke-l7-rilb-mc                        networking.gke.io/gateway   True       14h
    

애플리케이션 배포

두 클러스터 모두에 샘플 웹 애플리케이션 서버를 배포합니다.

kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml

출력은 다음과 비슷합니다.

namespace/store created
deployment.apps/store created

서비스, 게이트웨이, HTTPRoute 배포

  1. 다음 Service 매니페스트를 gke-west-1gke-east-1 클러스터 모두에 적용합니다.

    cat << EOF | kubectl apply --context gke-west-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    
    cat << EOF | kubectl apply --context gke-east-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    

    서비스에 초당 요청 10개로 설정된 max-rate-per-endpoint 주석이 추가됩니다. 복제본이 클러스터당 2개 있는 각 서비스의 용량은 클러스터당 20RPS입니다.

    서비스의 서비스 용량 수준을 선택하는 방법은 서비스 용량 결정을 참조하세요.

  2. 다음 Gateway 매니페스트를 구성 클러스터(이 예시에서는 gke-west-1)에 적용합니다.

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store
      namespace: traffic-test
    spec:
      gatewayClassName: gke-l7-global-external-managed-mc
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    EOF
    

    이 매니페스트는 공개적으로 액세스 가능한 IP 주소를 사용해서 외부 애플리케이션 부하 분산기를 배포하는 외부의 전역 멀티 클러스터 게이트웨이를 기술합니다.

  3. 다음 HTTPRoute 매니페스트를 구성 클러스터(이 예시에서는 gke-west-1)에 적용합니다.

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store
      namespace: traffic-test
      labels:
        gateway: store
    spec:
      parentRefs:
      - kind: Gateway
        namespace: traffic-test
        name: store
      rules:
      - backendRefs:
        - name: store
          group: net.gke.io
          kind: ServiceImport
          port: 8080
    EOF
    

    이 매니페스트는 모든 트래픽을 저장소 ServiceImport로 전달하는 라우팅 규칙을 사용해서 게이트웨이를 구성하는 HTTPRoute를 기술합니다. store ServiceImport는 두 클러스터 간에 store 서비스 포드를 그룹으로 묶고 부하 분산기에서 단일 서비스로 처리되도록 허용합니다.

    몇 분 후 게이트웨이 이벤트를 통해 배포가 완료되었는지 확인할 수 있습니다.

    kubectl describe gateway store -n traffic-test --context gke-west-1
    

    출력은 다음과 비슷합니다.

    ...
    Status:
      Addresses:
        Type:   IPAddress
        Value:  34.102.159.147
      Conditions:
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has deprecated this condition, do not depend on it.
        Observed Generation:   1
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Accepted
        Status:                True
        Type:                  Accepted
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Programmed
        Status:                True
        Type:                  Programmed
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
        Observed Generation:   1
        Reason:                Ready
        Status:                True
        Type:                  Ready
      Listeners:
        Attached Routes:  1
        Conditions:
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:
          Observed Generation:   1
          Reason:                Programmed
          Status:                True
          Type:                  Programmed
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
          Observed Generation:   1
          Reason:                Ready
          Status:                True
          Type:                  Ready
        Name:                    http
        Supported Kinds:
          Group:  gateway.networking.k8s.io
          Kind:   HTTPRoute
    Events:
      Type    Reason  Age                  From                   Message
      ----    ------  ----                 ----                   -------
      Normal  ADD     12m                  mc-gateway-controller  traffic-test/store
      Normal  SYNC    6m43s                mc-gateway-controller  traffic-test/store
      Normal  UPDATE  5m40s (x4 over 12m)  mc-gateway-controller  traffic-test/store
      Normal  SYNC    118s (x6 over 10m)   mc-gateway-controller  SYNC on traffic-test/store was a success
    

    이 출력은 게이트웨이가 성공적으로 배포되었음을 보여줍니다. 게이트웨이가 배포된 후 트래픽 전달이 시작되려면 여전히 몇 분 정도 기다려야 할 수 있습니다. 다음 단계에서 사용되므로, 이 출력에서 IP 주소를 기록해 둡니다.

트래픽 확인

curl 명령어를 사용해서 게이트웨이 IP 주소를 테스트하여 트래픽이 애플리케이션에 전달되는지 확인합니다.

curl GATEWAY_IP_ADDRESS

출력은 다음과 비슷합니다.

{
  "cluster_name": "gke-west-1",
  "host_header": "34.117.182.69",
  "pod_name": "store-54785664b5-mxstv",
  "pod_name_emoji": "👳🏿",
  "project_id": "project",
  "timestamp": "2021-11-01T14:06:38",
  "zone": "us-west1-a"
}

이 출력은 요청이 처리된 리전을 나타내는 포드 메타데이터를 보여줍니다.

부하 테스트를 사용하여 트래픽 확인

부하 분산기가 작동하는지 확인하려면 gke-west-1 클러스터에서 트래픽 생성기를 배포할 수 있습니다. 트래픽 생성기는 부하 분산기의 용량 및 오버플로 성능을 표시하기 위해 여러 부하 수준으로 트래픽을 생성합니다. 다음 단계에서는 세 가지 부하 수준을 보여줍니다.

  • 10 RPS는 gke-west-1의 저장소 서비스 용량 아래에 있습니다.
  • 30 RPS는 gke-west-1 저장소 서비스 용량을 초과하고 트래픽이 gke-east-1로 오버플로되도록 합니다.
  • 60 RPS는 두 클러스터 모두 서비스의 용량을 초과합니다.

대시보드 구성

  1. 게이트웨이에 대해 기본 URLmap 이름을 가져옵니다.

    kubectl get gateway store -n traffic-test --context=gke-west-1 -o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
    

    출력은 다음과 비슷합니다.

    /projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-traffic-test-store-armvfyupay1t
    
  2. Google Cloud 콘솔에서 측정항목 탐색기 페이지로 이동합니다.

    측정항목 탐색기로 이동

  3. 측정항목 선택에서 코드: MQL을 클릭합니다.

  4. 두 클러스터 간에 저장소 서비스의 트래픽 측정항목을 관측하기 위해 다음 쿼리를 입력합니다.

    fetch https_lb_rule
    | metric 'loadbalancing.googleapis.com/https/backend_request_count'
    | filter (resource.url_map_name == 'GATEWAY_URL_MAP')
    | align rate(1m)
    | every 1m
    | group_by [resource.backend_scope],
        [value_backend_request_count_aggregate:
            aggregate(value.backend_request_count)]
    

    GATEWAY_URL_MAP을 이전 단계의 URLmap 이름으로 바꿉니다.

  5. 쿼리 실행을 클릭합니다. 측정항목이 차트에 표시되도록 다음 섹션에서 로드 생성기를 배포한 후 최소 5분 이상 기다립니다.

10 RPS 테스트

  1. 포드를 gke-west-1 클러스터에 배포합니다.

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 10'
    

    GATEWAY_IP_ADDRESS를 이전 단계의 게이트웨이 IP 주소로 바꿉니다.

    출력은 다음과 비슷하며, 트래픽 생성기가 트래픽을 전송하고 있음을 나타냅니다.

    If you don't see a command prompt, try pressing enter.
    

    부하 생성기는 게이트웨이로 계속 10 RPS를 전송합니다. 트래픽이 Google Cloud 리전 내부에서 시작되지만 부하 분산기는 이것을 미국 서부 해안에서 시작되는 클라이언트 트래픽으로 취급합니다. 실제와 같은 클라이언트 다양성을 시뮬레이션하기 위해 부하 분산기는 각 HTTP 요청을 새로운 TCP 연결로 전송합니다. 즉, 트래픽이 백엔드 포드 간에 보다 고르게 분산됩니다.

    생성기가 대시보드에 대해 트래픽을 생성하려면 최대 5분까지 걸립니다.

  2. 측정항목 탐색기 대시보드를 확인합니다. 각 클러스터에 대해 트래픽이 부하 분산된 정도를 나타내는 2개 줄이 표시됩니다.

    클러스터에 부하 분산되는 트래픽을 보여주는 그래프

    us-east1-b가 트래픽을 수신하지 않는 동안 us-west1-a에서 약 10 RPS 트래픽을 수신하는 것이 확인됩니다. 트래픽 생성기가 us-west1에서 실행되므로, 모든 트래픽이 gke-west-1 클러스터의 서비스로 전송됩니다.

  3. Ctrl+C를 사용해서 부하 생성기를 중지하고 포드를 삭제합니다.

    kubectl delete pod loadgen --context gke-west-1
    

30 RPS 테스트

  1. 30 RPS를 전송하도록 구성해서 부하 생성기를 다시 배포합니다.

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 30'
    

    생성기가 대시보드에 대해 트래픽을 생성하려면 최대 5분까지 걸립니다.

  2. Cloud 작업 대시보드를 확인합니다.

    gke-east-1로 오버플로되는 트래픽을 보여주는 그래프

    약 20 RPS가 us-west1-a로 전송되고 10 RPS가 us-east1-b로 전송되는 것으로 확인됩니다. 이것은 gke-west-1의 서비스가 완전히 사용되고 있고 트래픽의 10 RPS를 gke-east-1의 서비스로 오버플로하고 있음을 나타냅니다.

  3. Ctrl+C를 사용해서 부하 생성기를 중지하고 포드를 삭제합니다.

    kubectl delete pod loadgen --context gke-west-1
    

60 RPS 테스트

  1. 60 RPS를 전송하도록 구성된 부하 생성기를 배포합니다.

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 60'
    
  2. 5분 정도 기다리고 Cloud 작업 대시보드를 확인합니다. 이제 두 클러스터 모두 약 30 RPS를 수신하는 것으로 표시됩니다. 모든 서비스가 전반적으로 초과 사용되고 있기 때문에 트래픽 스필오버가 수행되지 않으며, 서비스가 가능한 모든 트래픽을 흡수합니다.

    초과 사용되는 서비스를 보여주는 그래프

  3. Ctrl+C를 사용해서 부하 생성기를 중지하고 포드를 삭제합니다.

    kubectl delete pod loadgen --context gke-west-1
    

삭제

이 문서의 연습을 완료한 후에는 다음 단계에 따라 자신의 계정에 원치 않는 비용이 발생하지 않도록 리소스를 삭제합니다.

  1. 클러스터를 삭제합니다.

  2. 다른 목적으로 등록할 필요가 없으면 Fleet에서 클러스터를 등록 취소합니다.

  3. multiclusterservicediscovery 기능을 사용 중지합니다.

    gcloud container fleet multi-cluster-services disable
    
  4. 멀티 클러스터 인그레스 사용 중지

    gcloud container fleet ingress disable
    
  5. API를 사용 중지합니다.

    gcloud services disable \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        --project=PROJECT_ID
    

문제 해결

정상 업스트림 없음

증상:

게이트웨이를 만들 때 백엔드 서비스에 액세스할 수 없는 경우 다음 문제가 발생할 수 있습니다(503 응답 코드).

no healthy upstream

이유:

이 오류 메시지는 상태 점검 프로버가 정상 백엔드 서비스를 찾을 수 없음을 나타냅니다. 백엔드 서비스가 정상일 수 있지만 상태 점검을 맞춤설정해야 할 수도 있습니다.

해결 방법:

이 문제를 해결하려면 HealthCheckPolicy를 사용하여 애플리케이션 요구사항(예: /health)에 따라 상태 점검을 맞춤설정합니다.

다음 단계