KEDA를 사용하여 0으로 확장


이 튜토리얼에서는 KEDA를 사용하여 GKE 워크로드를 0개 포드로 확장하는 방법을 보여줍니다. 배포를 0개 포드로 확장하면 비활성 기간 (예: 주말 및 근무 시간 외) 또는 주기적 작업과 같은 간헐적인 워크로드에 리소스를 절약할 수 있습니다.

목표

이 튜토리얼에서는 다음 사용 사례를 설명합니다.

  • Pub/Sub 워크로드를 0으로 확장: Pub/Sub 주제에 큐에 추가된 메시지 수에 비례하여 포드 수를 확장합니다. 대기열이 비어 있으면 워크로드가 자동으로 0개 Pod로 축소됩니다.
  • LLM 워크로드를 0으로 조정합니다. GPU가 있는 노드에 LLM 모델 서버를 배포합니다. 서비스가 유휴 상태이면 워크로드가 자동으로 0개 포드로 축소됩니다.

비용

이 문서에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요. Google Cloud를 처음 사용하는 사용자는 무료 체험판을 사용할 수 있습니다.

이 문서에 설명된 태스크를 완료했으면 만든 리소스를 삭제하여 청구가 계속되는 것을 방지할 수 있습니다. 자세한 내용은 삭제를 참조하세요.

시작하기 전에

이 튜토리얼에서는 Cloud Shell을 사용하여 명령어를 실행합니다. Cloud Shell은 Google Cloud에서 호스팅되는 리소스를 관리하는 데 사용되는 셸 환경입니다. Google Cloud CLI, kubectl, Helm, Terraform 명령줄 도구가 사전에 설치되어 있습니다. Cloud Shell을 사용하지 않는 경우에는 Google Cloud CLI 및 Helm을 설치해야 합니다.

  1. 이 페이지에서 명령어를 실행하려면 다음 개발 환경 중 하나에서 gcloud CLI를 설정하세요.

    Cloud Shell

    gcloud CLI로 이미 설정된 온라인 터미널을 사용하려면 Cloud Shell을 활성화하세요.

    이 페이지 하단에서 Cloud Shell 세션이 시작되고 명령줄 프롬프트가 표시됩니다. 세션이 초기화되는 데 몇 초 정도 걸릴 수 있습니다.

    로컬 셸

    로컬 개발 환경을 사용하려면 다음 단계를 수행합니다.

    1. gcloud CLI를 설치합니다.
    2. gcloud CLI를 초기화합니다.
    3. Kubernetes 패키지 관리 도구인 Helm을 설치합니다.
  2. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  3. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  4. Make sure that billing is enabled for your Google Cloud project.

  5. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Enable the APIs

  6. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  7. Make sure that billing is enabled for your Google Cloud project.

  8. Enable the Resource Manager, Compute Engine, GKE, Pub/Sub APIs.

    Enable the APIs

환경 설정

Cloud Shell로 환경을 설정하려면 다음 단계를 따르세요.

  1. 환경 변수를 설정합니다.

    export PROJECT_ID=PROJECT_ID
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
    export LOCATION=LOCATION
    

    PROJECT_ID를 Google Cloud 프로젝트 ID로 바꾸고 LOCATION를 GKE 클러스터를 만들어야 하는 리전 또는 영역으로 바꿉니다.

    단일 세션에서 전체 튜토리얼을 따르지 않거나 어떠한 이유로든 환경 변수가 설정되지 않은 경우 이 명령어를 다시 실행하여 변수를 다시 설정해야 합니다.

  2. 클러스터 자동 확장GKE용 워크로드 아이덴티티 제휴가 사용 설정된 표준 GKE 클러스터를 만듭니다.

    gcloud container clusters create scale-to-zero \
        --project=${PROJECT_ID} --location=${LOCATION} \
        --machine-type=n1-standard-2 \
        --enable-autoscaling --min-nodes=1 --max-nodes=5 \
        --workload-pool=${PROJECT_ID}.svc.id.goog
    

KEDA 설치

KEDA는 Kubernetes 수평형 포드 자동 확장 처리를 보완하는 구성요소입니다. KEDA를 사용하면 배포를 0개 포드로 확장하고 0개 포드에서 1개 포드로 확장할 수 있습니다. 배포는 클러스터의 노드 간에 분산된 포드의 여러 복제본을 실행할 수 있는 Kubernetes API 객체입니다. 표준 수평형 포드 자동 확장 처리 알고리즘은 GKE가 하나 이상의 포드를 만든 후에 적용됩니다.

GKE에서 배포를 0개 포드로 확장하면 실행 중인 포드가 없으므로 자동 확장은 CPU 사용률과 같은 포드 측정항목을 사용할 수 없습니다. 따라서 KEDA를 사용하면 Kubernetes External Metrics API의 구현을 통해 클러스터 외부에서 발생한 측정항목을 가져올 수 있습니다. 이 API를 사용하여 Pub/Sub 구독의 대기 중인 메시지 수와 같은 측정항목을 기반으로 자동 확장할 수 있습니다. 지원되는 모든 측정항목 소스의 목록은 KEDA 문서를 참고하세요.

Helm 또는 kubectl를 사용하여 클러스터에 KEDA를 설치합니다.

Helm

다음 명령어를 실행하여 KEDA Helm 저장소를 추가하고, KEDA Helm 차트를 설치하고, KEDA 서비스 계정에 Cloud Monitoring에 대한 읽기 액세스 권한을 부여합니다.

helm repo add kedacore https://kedacore.github.io/charts
helm repo update
helm install keda kedacore/keda --create-namespace --namespace keda

gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
     --role roles/monitoring.viewer \
     --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator

이 명령어는 클러스터를 GKE용 워크로드 아이덴티티 제휴로 설정해야 하는 승인 규칙도 설정합니다.

kubectl

다음 명령어를 실행하여 kubectl apply를 사용하여 KEDA를 설치하고 KEDA 서비스 계정에 Cloud Monitoring에 대한 읽기 액세스 권한을 부여합니다.

kubectl apply --server-side  -f https://github.com/kedacore/keda/releases/download/v2.15.1/keda-2.15.1.yaml

gcloud projects add-iam-policy-binding projects/${PROJECT_ID} \
     --role roles/monitoring.viewer \
     --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda/sa/keda-operator

이 명령어는 클러스터를 GKE용 워크로드 아이덴티티 제휴로 설정해야 하는 승인 규칙도 설정합니다.

모든 KEDA 리소스가 keda 네임스페이스 아래에 표시되는지 확인합니다.

kubectl get all -n keda

KEDA 설계 및 리소스에 관한 자세한 내용은 KEDA 문서를 참고하세요.

Pub/Sub 워크로드를 0으로 확장

이 섹션에서는 Pub/Sub 구독의 메시지를 처리하고 각 메시지를 처리하고 완료를 확인하는 워크로드를 설명합니다. 워크로드가 동적으로 확장됩니다. 확인되지 않은 메시지의 수가 증가하면 자동 확장이 더 많은 포드를 인스턴스화하여 적시에 처리합니다.

0으로 확장하면 일정 시간 동안 메시지가 수신되지 않을 때 포드가 인스턴스화되지 않습니다. 이렇게 하면 Pod가 장시간 유휴 상태로 유지되지 않으므로 리소스가 절약됩니다.

Pub/Sub 워크로드 배포

Pub/Sub 주제에 대기열에 추가된 메시지를 처리하는 샘플 워크로드를 배포합니다. 실제 워크로드를 시뮬레이션하기 위해 이 샘플 프로그램은 메시지를 확인하기 전에 3초 동안 기다립니다. 워크로드는 keda-pubsub-sa 서비스 계정으로 실행되도록 구성됩니다.

다음 명령어를 실행하여 Pub/Sub 주제와 구독을 만들고 권한을 구성한 후 keda-pubub 네임스페이스 아래에서 워크로드를 시작하는 배포를 만듭니다.

gcloud pubsub topics create keda-echo
gcloud pubsub subscriptions create keda-echo-read --topic=keda-echo
gcloud projects add-iam-policy-binding projects/${PROJECT_ID}  \
    --role=roles/pubsub.subscriber \
  --member=principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/keda-pubsub/sa/keda-pubsub-sa

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-with-workload-identity.yaml

Scale-to-zero 구성

Pub/Sub 워크로드를 0으로 확장되도록 구성하려면 KEDA를 사용하여 ScaledObject 리소스를 정의하여 배포 확장 방법을 지정합니다. 그러면 KEDA가 기본 HorizontalPodAutoscaler (HPA) 객체를 자동으로 만들고 관리합니다.

  1. 예상되는 자동 확장 동작을 설명하는 ScaledObject 리소스를 만듭니다.

    curl https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/cloud-pubsub/deployment/keda-pubsub-scaledobject.yaml | envsubst | kubectl apply -f -
    

    그러면 다음 객체가 생성됩니다.

    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: keda-pubsub
      namespace: keda-pubsub
    spec:
      maxReplicaCount: 5
      scaleTargetRef:
        name: keda-pubsub
      triggers:
        - type: gcp-pubsub
          authenticationRef:
            name: keda-auth
          metadata:
            subscriptionName: "projects/${PROJECT_ID}/subscriptions/keda-echo-read"
    
  2. KEDA가 ScaledObject 객체를 기반으로 만드는 HorizontalPodAutoscaler (HPA) 객체를 검사합니다.

    kubectl get hpa keda-hpa-keda-pubsub -n keda-pubsub -o yaml
    

    Kubernetes 문서에서 자동 확장에 대해 자세히 알아보세요.

  3. KEDA가 Pub/Sub 구독이 비어 있음을 확인하고 배포를 0개 복제본으로 확장할 때까지 기다립니다.

    워크로드 자동 확장 처리를 검사합니다.

    kubectl describe hpa keda-hpa-keda-pubsub -n keda-pubsub
    

    명령어 응답에서 ScalingActive 조건이 false임을 확인합니다. 관련 메시지는 수평형 포드 자동 확장 처리가 KEDA가 배포를 0으로 확장했음을 인식했음을 나타냅니다. 이때 배포가 다시 1개 포드로 확장될 때까지 작동을 중지합니다.

    Name:                                                  keda-hpa-keda-pubsub
    Namespace:                                             keda-pubsub
    Metrics:                                               ( current / target )
      "s0-gcp-ps-projects-[...]]" (target average value):  0 / 10
    Min replicas:                                          1
    Max replicas:                                          5
    Deployment pods:                                       5 current / 5 desired
    Conditions:
      Type            Status  Reason               Message
      ----            ------  ------               -------
      AbleToScale     True    ScaleDownStabilized  recent recommendations were higher than current one [...]
      ScalingActive   False   ScalingDisabled      scaling is disabled since the replica count of the target is zero
      ScalingLimited  True    TooManyReplicas      the desired replica count is more than the maximum replica count
    

확장 트리거

배포를 확장하도록 자극하려면 다음 단계를 따르세요.

  1. Pub/Sub 주제에 메시지를 큐에 추가합니다.

    for num in {1..20}
    do
      gcloud pubsub topics publish keda-echo --project=${PROJECT_ID} --message="Test"
    done
    
  2. 배포가 확장되고 있는지 확인합니다.

    kubectl get deployments -n keda-pubsub
    

    출력에서 'Ready'(준비됨) 열에 복제본 1개가 표시됩니다.

    NAME          READY   UP-TO-DATE   AVAILABLE   AGE
    keda-pubsub   1/1     1            1           2d
    

KEDA는 대기열이 비어 있지 않은 것을 관찰한 후 배포를 확장합니다.

LLM 워크로드를 0으로 조정

이 섹션에서는 GPU가 연결된 Ollama 서버를 배포하는 대규모 언어 모델 (LLM) 워크로드를 설명합니다. Ollama를 사용하면 GemmaLamma 2와 같은 인기 있는 LLM을 실행할 수 있으며 주로 HTTP를 통해 기능을 노출합니다.

KEDA-HTTP 부가기능 설치

비활성 상태인 동안 HTTP 서비스를 0개 Pod로 확장하면 요청을 처리할 백엔드가 없으므로 요청 실패가 발생합니다.

이 섹션에서는 KEDA-HTTP 부가기능을 사용하여 이 문제를 해결하는 방법을 보여줍니다. KEDA-HTTP는 사용자 요청을 수신하고 0으로 확장되도록 구성된 서비스로 전달하는 HTTP 프록시를 시작합니다. 서비스에 포드가 없으면 프록시가 서비스를 트리거하여 확장하고 서비스가 하나 이상의 포드로 확장될 때까지 요청을 버퍼링합니다.

Helm을 사용하여 KEDA-HTTP 부가기능을 설치합니다. 자세한 내용은 KEDA-HTTP 문서를 참고하세요.

helm repo add ollama-helm https://otwld.github.io/ollama-helm/
helm repo update

# Set the proxy timeout to 120s, giving Ollama time to start.
helm install http-add-on kedacore/keda-add-ons-http  \
  --create-namespace --namespace keda \
  --set interceptor.responseHeaderTimeout=120s

Ollama LLM 워크로드 배포

Ollama LLM 워크로드를 배포하려면 다음 단계를 따르세요.

  1. GPU가 연결된 g2-standard-4개의 노드가 포함된 노드 풀을 만들고 0~2개의 노드를 제공하도록 클러스터 자동 확장을 구성합니다.

    gcloud container node-pools create gpu --machine-type=g2-standard-4 \
        --location=${LOCATION} --cluster=scale-to-zero \
        --min-nodes 0 --max-nodes 2 --num-nodes=1 --enable-autoscaling 
    
  2. 공식 Ollama Helm 차트 저장소를 추가하고 로컬 Helm 클라이언트의 저장소를 업데이트합니다.

    helm repo add ollama-helm https://otwld.github.io/ollama-helm/
    helm repo update
    
  3. Helm 차트를 사용하여 Ollama 서버를 배포합니다.

    helm install ollama ollama-helm/ollama --create-namespace --namespace ollama \
      -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/helm-values-ollama.yaml
    

    helm-values-ollama.yaml 구성은 로드할 LLM 모델, GPU 요구사항, Ollama 서버의 TCP 포트를 지정합니다.

Scale-to-zero 구성

Ollama 워크로드를 0으로 확장되도록 구성하기 위해 KEDA-HTTP는 HTTPScaledObject를 사용합니다.

  1. 예상되는 자동 확장 동작을 설명하는 HTTPScaledObject 리소스를 만듭니다.

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/kubernetes-engine-samples/refs/heads/main/cost-optimization/gke-keda/ollama/keda-ollama-httpscaledobject.yaml
    

    그러면 다음 필드를 정의하는 HTTPScaledObject 객체가 생성됩니다.

    • scaleTargetRef: KEDA-HTTP가 요청을 전달해야 하는 서비스를 지정합니다. 이 예시에서는 호스트가 ollama.ollama인 모든 요청이 Ollama 서버로 라우팅됩니다.
    • scaledownPeriod: 요청이 수신되지 않을 때 얼마나 빨리 축소할지 초 단위로 지정합니다.
    • replicas: Ollama 배포를 위해 유지할 포드의 최소 및 최대 수를 지정합니다.
    • scalingMetric: 자동 확장을 유도하는 데 사용되는 측정항목(이 예에서는 요청 비율)을 지정합니다. 더 많은 측정항목 옵션은 KEDA-HTTP 문서를 참고하세요.
    kind: HTTPScaledObject
    apiVersion: http.keda.sh/v1alpha1
    metadata:
        namespace: ollama
        name: ollama
    spec:
        hosts:
        - ollama.ollama
        scaleTargetRef:
            name: ollama
            kind: Deployment
            apiVersion: apps/v1
            service: ollama
            port: 11434
        replicas:
            min: 0
            max: 2
        scaledownPeriod: 3600
        scalingMetric:
            requestRate:
                targetValue: 20
    
  2. 다음 명령어를 실행하여 KEDA-HTTP가 이전 단계에서 만든 HTTPScaledObject를 성공적으로 처리했는지 확인합니다.

    kubectl get hpa,scaledobject -n ollama
    

    출력에는 HorizontalPodAutoscaler (KEDA에서 생성) 및 ScaledObject (KEDA-HTTP에서 생성) 리소스가 표시됩니다.

    NAME                                                  REFERENCE           TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
    horizontalpodautoscaler.autoscaling/keda-hpa-ollama   Deployment/ollama   0/100 (avg)   1         2         1          2d
    
    NAME                          SCALETARGETKIND      SCALETARGETNAME   MIN   MAX   TRIGGERS        AUTHENTICATION   READY   ACTIVE   FALLBACK   PAUSED    AGE
    scaledobject.keda.sh/ollama   apps/v1.Deployment   ollama            0     2     external-push                    True    False    False      Unknown   2d
    
  3. 배포가 0개의 포드로 확장되었는지 확인합니다.

    scaledownPeriod 필드에 설정된 시간 동안 기다린 후 다음 명령어를 실행합니다.

    kubectl get deployments -n ollama
    

    출력은 KEDA가 Ollama 배포를 축소했으며 실행 중인 포드가 없음을 보여줍니다.

    NAME     READY   UP-TO-DATE   AVAILABLE   AGE
    ollama   0/0     0            0           2d
    

확장 트리거

배포가 확장되도록 하려면 KEDA-HTTP 부가기능에서 설정한 프록시를 사용하여 Ollama 서비스를 호출합니다. 이로 인해 요청 비율 측정항목의 값이 증가하고 첫 번째 Pod 생성이 트리거됩니다.

프록시가 외부에 노출되지 않으므로 kubectl 포트 전달 기능을 사용하여 프록시에 액세스합니다.

kubectl port-forward svc/keda-add-ons-http-interceptor-proxy -n keda 8080:8080 &

# Set the 'Host' HTTP header so that the proxy routes requests to the Ollama server.
curl -H "Host: ollama.ollama" \
  http://localhost:8080/api/generate \
  -d '{ "model": "gemma:7b", "prompt": "Hello!" }'

curl 명령어는 Gemma 모델에 'Hello!' 프롬프트를 전송합니다. 응답에서 반환되는 답변 토큰을 확인합니다. API 사양은 Ollama 가이드를 참고하세요.

삭제

이 튜토리얼에서 사용된 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 리소스가 포함된 프로젝트를 삭제하거나 프로젝트를 유지하고 개별 리소스를 삭제하세요.

  1. Pub/Sub 구독 및 주제를 삭제합니다.

    gcloud pubsub subscriptions delete keda-echo-read
    gcloud pubsub topics delete keda-echo
    
  2. GKE 클러스터를 삭제합니다.

    gcloud container clusters delete scale-to-zero --location=${LOCATION}
    

다음 단계