이 문서에서는 Google Cloud Managed Service for Prometheus에 수평형 포드 자동 확장(HPA)을 사용 설정하는 방법을 설명합니다. 다음 중 하나를 수행하여 HPA를 사용 설정할 수 있습니다.
- Google Cloud에서 개발 및 지원하는 커스텀 측정항목 Stackdriver 어댑터 라이브러리 사용
- 타사 Prometheus 어댑터 라이브러리 사용
두 가지 방법 중 하나를 선택해야 합니다. 문제 해결에 설명된 대로 리소스 정의가 중복되므로 둘 다 사용할 수 없습니다.
커스텀 측정항목 Stackdriver 어댑터 사용
커스텀 측정항목 Stackdriver 어댑터는 어댑터 버전 v0.13.1로 시작하는 Managed Service for Prometheus에서 측정항목을 쿼리하도록 지원합니다.
커스텀 측정항목 Stackdriver 어댑터를 사용하여 HPA 구성 예시를 설정하려면 다음을 수행합니다.
- 클러스터의 관리 컬렉션을 설정합니다.
클러스터에 커스텀 측정항목 Stackdriver 어댑터를 설치합니다.
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml
예시 Prometheus 측정항목 내보내기 및 HPA 리소스를 배포합니다.
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml
이 명령어는 측정항목
foo
및 HPA 리소스를 내보내는 내보내기 도구 애플리케이션을 배포합니다. HPA는 이 애플리케이션을 최대 5개의 복제본으로 확장하여 측정항목foo
의 목표 값을 달성합니다.워크로드 아이덴티티를 사용하는 경우 어댑터가 실행되는 서비스 계정에 Monitoring 뷰어 역할도 부여해야 합니다. Kubernetes 클러스터에 워크로드 아이덴티티가 사용 설정되어 있지 않으면 이 단계를 건너뜁니다.
export PROJECT_NUMBER=$(gcloud projects describe PROJECT_ID --format 'get(projectNumber)') 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/custom-metrics/sa/custom-metrics-stackdriver-adapter
podmonitoring.yaml
이라는 파일에 다음 구성을 배치하여 PodMonitoring 리소스를 정의합니다.apiVersion: monitoring.googleapis.com/v1 kind: PodMonitoring metadata: name: prom-example spec: selector: matchLabels: run: custom-metric-prometheus-sd endpoints: - port: 8080 interval: 30s
새 PodMonitoring 리소스를 배포합니다.
kubectl -n default apply -f podmonitoring.yaml
Prometheus용 관리형 서비스는 몇 분 안에 내보내기에서 스크레이핑한 측정항목을 처리하고 긴 이름을 사용하여 Cloud Monitoring에 저장합니다. Prometheus 측정항목은 다음 규칙에 따라 저장됩니다.
prometheus.googleapis.com
프리픽스- 유형화되지 않은 측정항목에는
unknown
또는unknown:counter
서픽스가 있을 수 있지만 이 서픽스는 일반적으로gauge
,counter
,summary
또는histogram
중 하나입니다. 서픽스를 확인하려면 측정항목 탐색기를 사용하여 Cloud Monitoring에서 측정항목을 조회합니다.
배포된 HPA를 업데이트하여 Cloud Monitoring에서 측정항목을 쿼리합니다.
foo
측정항목은prometheus.googleapis.com/foo/gauge
으로 수집됩니다. 배포된 HorizontalPodAutoscaler 리소스로 측정항목을 쿼리할 수 있게 하려면 배포된 HPA에서 긴 형식의 이름을 사용하지만 모든 슬래시(/
)를 파이프 문자(|
)로 대체하여 수정해야 합니다:prometheus.googleapis.com|foo|gauge
. 자세한 내용은 커스텀 측정항목 Stackdriver 어댑터 저장소의 Stackdriver에서 제공되는 측정항목 섹션을 참조하세요.다음 명령어를 실행하여 배포된 HPA를 업데이트합니다.
kubectl edit hpa custom-metric-prometheus-sd
pods.metric.name
필드 값을foo
에서prometheus.googleapis.com|foo|gauge
로 변경합니다.spec
섹션은 다음과 같이 표시되어야 합니다.spec: maxReplicas: 5 metrics: - pods: metric: name: prometheus.googleapis.com|foo|gauge target: averageValue: "20" type: AverageValue type: Pods minReplicas: 1
이 예시에서 HPA 구성은
prometheus.googleapis.com/foo/gauge
측정항목의 평균 값을20
으로 찾습니다. 이 배포에서 측정항목의 값을40
으로 설정하므로 HPA 컨트롤러는maxReplicas
(5
) 필드 값까지 포드 수를 늘려 모든 포드에서 메트릭의 평균 값을20
으로 줄이려고 시도합니다.HPA 쿼리는 HPA 리소스가 설치된 네임스페이스와 클러스터로 범위가 지정되므로 다른 클러스터 및 네임스페이스의 동일한 측정항목은 자동 확장에 영향을 미치지 않습니다.
워크로드 수직 확장을 보려면 다음 명령어를 실행합니다.
kubectl get hpa custom-metric-prometheus-sd --watch
REPLICAS
필드 값이1
에서5
로 변경됩니다.NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE custom-metric-prometheus-sd Deployment/custom-metric-prometheus-sd 40/20 1 5 5 *
배포를 축소하려면 대상 측정항목 값을 내보낸 측정항목 값보다 높게 업데이트합니다. 이 예시에서 배포는
prometheus.googleapis.com/foo/gauge
측정항목의 값을40
으로 설정합니다. 대상 값을40
보다 큰 숫자로 설정하면 배포가 축소됩니다.예를 들어 HPA 구성의
pods.target.averageValue
필드 값을20
에서100
으로 변경하려면kubectl edit
를 사용합니다.kubectl edit hpa custom-metric-prometheus-sd
다음과 일치하도록 사양 섹션을 수정합니다.
spec: maxReplicas: 5 metrics: - pods: metric: name: prometheus.googleapis.com|foo|gauge target: averageValue: "100" type: AverageValue type: Pods minReplicas: 1
워크로드의 축소를 확인하려면 다음 명령어를 실행합니다.
kubectl get hpa custom-metric-prometheus-sd --watch
REPLICAS
필드 값이5
에서1
로 변경됩니다. 이는 설계상 포드 수를 늘릴 때보다 더 느리게 발생합니다.NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE custom-metric-prometheus-sd Deployment/custom-metric-prometheus-sd 40/100 1 5 1 *
배포된 예시를 삭제하려면 다음 명령어를 실행합니다.
kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/examples/prometheus-to-sd/custom-metrics-prometheus-sd.yaml kubectl delete podmonitoring/prom-example
자세한 내용은 커스텀 측정항목 Stackdriver 어댑터 저장소의 Prometheus 예시를 참조하거나 애플리케이션 확장을 참조하세요.
Prometheus 어댑터 사용
기존 prometheus-adapter 구성은 몇 가지 변경만으로 자동 확장될 수 있습니다. Managed Service for Prometheus를 사용하여 확장하도록 prometheus-adapter를 구성하는 것은 업스트림 Prometheus를 사용한 확장과 비교하여 두 가지 추가 제한사항이 있습니다.
Prometheus API 또는 UI를 사용하여 Managed Service for Prometheus를 쿼리할 때와 마찬가지로 쿼리는 Prometheus 프런트엔드 UI 프록시를 통해 라우팅되어야 합니다. prometheus-adapter의 경우
prometheus-adapter
배포를 수정하여prometheus-url
값을 다음과 같이 변경합니다.--prometheus-url=http://frontend.NAMESPACE_NAME.svc:9090/
여기서 NAMESPACE_NAME은 프런트엔드가 배포된 네임스페이스입니다.
규칙 구성의
.seriesQuery
필드에서 측정항목 이름에 정규식 일치자를 사용할 수 없습니다. 대신 측정항목 이름을 완전히 지정해야 합니다.
업스트림 Prometheus에 비해 Managed Service for Prometheus 내에서 데이터를 사용할 수 있는 데 시간이 조금 더 걸릴 수 있으므로 과도하게 빠른 자동 확장 로직을 구성하면 원치 않는 동작이 발생할 수 있습니다. 데이터 최신 상태에 대한 보장은 없지만 데이터가 Managed Service for Prometheus로 전송된 후 일반적으로 3~7초가 지나면 데이터를 쿼리할 수 있습니다(네트워크 지연 시간 제외).
prometheus-adapter에서 실행하는 모든 쿼리는 전역 범위에 있습니다. 즉, 이름이 같은 측정항목을 내보내는 네임스페이스 두 개에 애플리케이션이 있는 경우 해당 측정항목을 사용하는 HPA 구성은 두 애플리케이션 모두의 데이터로 확장됩니다. 잘못된 데이터로 확장되지 않도록 항상 PromQL에서 namespace
또는 cluster
필터를 사용하는 것이 좋습니다.
prometheus-adapter 및 관리 컬렉션을 사용하여 HPA 구성 예시를 설정하려면 다음 단계를 따르세요.
- 클러스터의 관리 컬렉션을 설정합니다.
- 클러스터에 Prometheus 프런트엔드 UI 프록시를 배포합니다. 워크로드 아이덴티티를 사용하는 경우 서비스 계정도 구성하고 승인해야 합니다.
- prometheus-engine 저장소 내
examples/hpa/
디렉터리에 매니페스트를 배포합니다.example-app.yaml
: 측정항목을 방출하는 배포 및 서비스의 예시입니다.pod-monitoring.yaml
: 예시 측정항목 스크래핑을 구성하는 리소스입니다.hpa.yaml
: 워크로드의 확장을 구성하는 HPA 리소스입니다.
클러스터에
prometheus-adapter
가 설치되어 있는지 확인합니다. 이렇게 하려면 클러스터에 설치 매니페스트 예시를 배포합니다. 이 매니페스트는 다음과 같이 구성됩니다.default
네임스페이스에 배포된 프런트엔드 프록시를 쿼리합니다.- PromQL을 실행하여 배포 예시에서
http_requests_per_second
측정항목을 계산하고 반환합니다.
다음 명령어를 각각 별도의 터미널 세션에서 실행합니다.
prometheus-example-app
서비스에 대해 HTTP 로드를 생성합니다.kubectl run -i --tty load-generator --rm --image=busybox:1.28 --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://prometheus-example-app; done"
- 수평형 포드 자동 확장 처리를 관찰합니다.
kubectl get hpa prometheus-example-app --watch
- 워크로드 확장을 관찰합니다.
kubectl get po -lapp.kubernetes.io/name=prometheus-example-app --watch
Ctrl+C를 사용하여 HTTP 부하 생성을 중지하고 워크로드 축소를 관찰합니다.
문제 해결
커스텀 측정항목 Stackdriver 어댑터는 Prometheus 어댑터(prometheus-adapter)의 이름과 동일한 이름의 리소스 정의를 사용합니다. 이름이 겹치는 경우 동일한 클러스터에서 어댑터를 두 개 이상 실행하면 오류가 발생합니다.
이전에 Stackdriver 어댑터가 설치된 커스텀 측정항목이 있는 클러스터에 Prometheus 어댑터를 설치하면 이름 충돌로 인해 FailedGetObjectMetric
과 같은 오류가 발생할 수 있습니다. 이를 해결하기 위해 이전에 커스텀 측정항목 어댑터에서 등록한 v1beta1.external.metrics.k8s.io
, v1beta1.custom.metrics.k8s.io
, v1beta2.custom.metrics.k8s.io
apiservice를 삭제해야 할 수 있습니다.
문제 해결 팁:
Pub/Sub 측정항목과 같은 일부 Cloud Monitoring 시스템 측정항목은 60초 이상 지연됩니다. Prometheus 어댑터는 현재 타임스탬프를 사용하여 쿼리를 실행하므로 Prometheus 어댑터를 사용하여 이러한 측정항목을 쿼리하면 데이터 없음으로 잘못된 결과가 나올 수 있습니다. 지연된 측정항목을 쿼리하려면 PromQL의
offset
한정자를 사용하여 쿼리의 타임스탬프를 필요한 양만큼 변경합니다.프런트엔드 UI 프록시가 의도한 대로 작동하고 권한 관련 문제가 없는지 확인하려면 터미널에서 다음 명령어를 실행합니다.
kubectl -n NAMESPACE_NAME port-forward svc/frontend 9090
그런 후 다른 터미널을 열고 다음 명령어를 실행합니다.
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up'
프런트엔드 UI 프록시가 올바르게 작동하지 않으면 두 번째 터미널의 응답이 다음과 비슷하게 표시됩니다.
curl --silent 'localhost:9090/api/v1/series?match%5B%5D=up' | jq . { "status": "success", "data": [ ... ] }
403 오류가 수신되면 프런트엔드 UI 프록시가 올바르게 구성되지 않은 것입니다. 403 오류를 해결하는 방법은 서비스 계정 구성 및 승인 가이드를 참조하세요.
커스텀 측정항목 apiserver를 사용할 수 있는지 확인하려면 다음 명령어를 실행합니다.
kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io
apiserver를 사용할 수 있으면 응답이 다음과 비슷합니다.
$ kubectl get apiservices.apiregistration.k8s.io v1beta1.custom.metrics.k8s.io NAME SERVICE AVAILABLE AGE v1beta1.custom.metrics.k8s.io monitoring/prometheus-adapter True 33m
HPA가 의도한 대로 작동하는지 확인하려면 다음 명령어를 실행합니다.
$ kubectl describe hpa prometheus-example-app Name: prometheus-example-app Namespace: default Labels:
Annotations: Reference: Deployment/prometheus-example-app Metrics: ( current / target ) "http_requests_per_second" on pods: 11500m / 10 Min replicas: 1 Max replicas: 10 Deployment pods: 2 current / 2 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ReadyForNewScale recommended size matches current size ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from pods metric http_requests_per_second ScalingLimited False DesiredWithinRange the desired count is within the acceptable range Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 47s horizontal-pod-autoscaler New size: 2; reason: pods metric http_requests_per_second above target 응답에
FailedGetPodsMetric
과 같은 문이 포함되어 있으면 HPA가 실패합니다. 다음은 HPA가 실패할 때describe
호출에 대한 응답을 보여줍니다.$ kubectl describe hpa prometheus-example-app Name: prometheus-example-app Namespace: default Reference: Deployment/prometheus-example-app Metrics: ( current / target ) "http_requests_per_second" on pods:
/ 10 Min replicas: 1 Max replicas: 10 Deployment pods: 1 current / 1 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ReadyForNewScale recommended size matches current size ScalingActive False FailedGetPodsMetric the HPA was unable to compute the replica count: unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods ScalingLimited False DesiredWithinRange the desired count is within the acceptable range Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedGetPodsMetric 104s (x11 over 16m) horizontal-pod-autoscaler unable to get metric http_requests_per_second: unable to fetch metrics from custom metrics API: the server could not find the metric http_requests_per_second for pods HPA가 실패할 때는
load-generator
로 측정항목을 생성해야 합니다. 다음 명령어를 사용하여 커스텀 측정항목 API를 직접 확인할 수 있습니다.kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq .
성공한 출력은 다음과 같이 표시됩니다.
$ kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq . { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [ { "name": "namespaces/http_requests_per_second", "singularName": "", "namespaced": false, "kind": "MetricValueList", "verbs": [ "get" ] }, { "name": "pods/http_requests_per_second", "singularName": "", "namespaced": true, "kind": "MetricValueList", "verbs": [ "get" ] } ] }
측정항목이 없으면 출력에서
"resources"
에 데이터가 표시되지 않습니다. 예를 들면 다음과 같습니다.kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/" | jq . { "kind": "APIResourceList", "apiVersion": "v1", "groupVersion": "custom.metrics.k8s.io/v1beta1", "resources": [] }