본문으로 건너뛰기

3.2. 오토스케일링 (APM HPA)

개요​

APM 의 애플리케이션 지표(TPS)를 기준으로 파드를 자동 확장·축소합니다. CPU/메모리만으로는 잡기 어려운 실제 트래픽에 맞춰 스케일할 수 있습니다.

1. 동작 방식​

APM HPA 는 Kubernetes 의 External Metrics API(external.metrics.k8s.io/v1beta1)를 구현합니다. HPA 가 외부 지표를 요청하면, APM HPA 가 OPENMARU APM 서버에 해당 그룹의 지표를 질의해 값을 돌려줍니다.

APM HPA 동작 방식
  • groupName: OPENMARU APM 의 애플리케이션 그룹 이름.
  • apmAlias: 어느 APM 서버에 물어볼지 고르는 별칭(설치 시 envHpa 에 등록한 name). 등록되지 않은 이름을 적으면 오류로 거부합니다. 다른 서버로 조용히 질의하지 않습니다.

쓸 수 있는 지표​

지표무엇범위target.type
tps초당 처리 건수—AverageValue
activeUser접속 사용자 수—AverageValue
loginUser로그인 사용자 수—AverageValue
avgRT평균 응답시간 (밀리초)—Value
errorRate오류율0~100Value
apdexDeficit100 - apdex. 클수록 응답이 나쁩니다0~100Value

🔴 target.type 을 표대로 쓰십시오. AverageValue 는 받은 값을 파드 수로 나눕니다. tps 처럼 파드마다 쌓이는 값에는 맞지만, 이미 평균이나 비율인 avgRT·errorRate· apdexDeficit 을 나누면 뜻이 달라집니다 — 응답시간 200 밀리초가 파드 4 개에서 50 밀리초로 읽힙니다.

apdex 는 오토스케일링에 쓸 수 없습니다. 값이 클수록 좋은데 HorizontalPodAutoscaler 는 "목표를 넘으면 늘린다" 만 표현할 수 있어, 그대로 걸면 응답이 좋을 때 파드가 늘고 나빠질 때 줄어듭니다. 응답 품질로 조절하려면 apdexDeficit 을 쓰십시오. apdex 자체는 조회만 됩니다.

소수는 밀리 단위로 실려 옵니다 — tps 가 27.667 이면 27667m 으로 나옵니다.

2. 사용법 — HPA 만들기​

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: tomcat-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: tomcat
minReplicas: 1
maxReplicas: 3
metrics:
- type: External
external:
metric:
name: tps # 위 표의 지표 이름
selector:
matchLabels:
apmAlias: APM-SERVER # 어느 APM 서버 (envHpa 의 name 과 일치)
groupName: TOMCAT # APM 애플리케이션 그룹 이름
target:
type: AverageValue
value: 50 # 파드당 평균 TPS 50 을 목표로 스케일

적용은 다음과 같습니다.

kubectl apply -f tomcat-hpa.yaml
kubectl get hpa tomcat-hpa

NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
tomcat-hpa Deployment/tomcat 0/50 1 3 1 8s
  • TARGETS 의 왼쪽 값(현재 TPS)이 정상적으로 표시되면 연동 성공입니다.

3. 동작 확인 (부하 테스트)​

# 부하 생성
ab -n 18000 -c 10 http://tomcat-openmaru-test1.apps.example.local/

# TPS 가 목표를 넘으면 파드가 늘어남
kubectl get hpa tomcat-hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
tomcat-hpa Deployment/tomcat 506/50 1 3 3 24m

직접 외부 지표 API 를 확인할 수도 있습니다.

kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/<namespace>/tps?labelSelector=groupName%3D<그룹이름>%2CapmAlias%3D<별칭>" | jq .

값을 못 가져오면 오류 메시지가 그대로 나옵니다. 무엇이 잘못됐는지 여기에 적혀 있습니다.

Error from server: 메트릭 "tps" 를 가져오지 못했다 (그룹 "wrong-name"): ...
Error from server: labelSelector 에 groupName 이 필요하다 (받은 것: "")
Error from server: apmAlias "APM-TYPO" 에 해당하는 환경변수가 없다

3.1 🔴 애플리케이션 그룹 이름이 재배포 때마다 바뀝니다​

groupName 은 APM 이 인식한 애플리케이션 그룹 이름이고, 그 값은 계측 대상 파드의 OMAPM_APPLICATION_NAME 환경변수에서 정해집니다. 자동 계측이 넣는 기본값에는 ReplicaSet 해시가 들어갑니다.

파드 이름 helloworld-55cb78b54c-7276g
그룹 이름 helloworld-55cb78b54c ← ReplicaSet 해시가 들어 있다

확장·축소는 같은 ReplicaSet 안에서 일어나므로 문제가 없습니다. 그러나 Deployment 를 다시 배포하면 해시가 바뀌어 그룹 이름도 바뀌고, HPA 의 groupName 이 맞지 않게 됩니다.

이때 HPA 는 지표를 못 가져오는데 파드 수를 줄이지 않고 그대로 둡니다. 오류가 겉으로 드러나지 않으므로 한참 뒤에야 알아채게 됩니다.

고정하려면 파드 템플릿에 OMAPM_APPLICATION_NAME 을 직접 지정하십시오. 지정한 값이 있으면 자동 계측이 덮어쓰지 않습니다.

spec:
template:
metadata:
labels:
openmaru.io/was-agent: 'true'
spec:
containers:
- name: tomcat
env:
- name: OMAPM_APPLICATION_NAME
value: "tomcat-prod" # 재배포해도 바뀌지 않는다

그리고 HPA 에서 같은 이름을 씁니다.

matchLabels:
groupName: tomcat-prod

지금 쓰는 그룹 이름을 확인하려면 계측된 파드의 환경변수를 보거나 위 kubectl get --raw 명령으로 값이 나오는지 시험합니다.

kubectl get pod <파드> -o jsonpath='{.spec.containers[0].env[?(@.name=="OMAPM_APPLICATION_NAME")].value}'

4. 여러 APM 서버 사용​

APM 서버가 여러 대면, 설치 시 envHpa 에 서로 다른 name(=apmAlias)으로 등록합니다.

envHpa:
- name: APM-INTERNAL
value: "http://openmaru-apm-server.openmaru-apm.svc.cluster.local:8080"
- name: APM-SERVER
value: "http://192.168.80.190"
- name: APM-INTERNAL_ACCESS_KEY # 별칭마다 액세스 키를 짝지어 둡니다
value: "<APM API access key>"
- name: APM-SERVER_ACCESS_KEY # 해당 APM 서버 API 액세스 키 (<apmAlias>_ACCESS_KEY)
value: "<APM API access key>"

🔴 별칭마다 <apmAlias>_ACCESS_KEY 를 반드시 짝지어 두십시오. 키가 없으면 APM 서버가 HTTP 403 을 돌려주고 지표를 가져오지 못합니다.

그리고 HPA 의 matchLabels.apmAlias 로 골라 씁니다.

matchLabels:
apmAlias: APM-INTERNAL # 내부 APM 서버로 질의
groupName: TOMCAT

apmAlias 가 envHpa 의 어떤 name 과도 맞지 않으면 오류로 거부합니다 (apmAlias "..." 에 해당하는 환경변수가 없다). 다른 서버로 조용히 질의하지 않으므로, 이름을 잘못 적으면 곧바로 드러납니다.

5. 핵심 설정 요약​

HPA 필드값의미
metrics[].typeExternal외부 지표 기반 스케일
metric.nametps사용할 지표. 쓸 수 있는 것은 1절의 표 참고
selector.matchLabels.apmAlias예: APM-SERVER질의할 APM 서버 별칭(envHpa name)
selector.matchLabels.groupName예: TOMCATAPM 애플리케이션 그룹
target.type / target.valueAverageValue / 50파드당 목표 TPS

6. 잘 안 될 때​

증상점검
TARGETS 가 <unknown>kubectl describe hpa <이름> 의 Events 를 보십시오. 왜 못 가져왔는지 메시지로 나옵니다
재배포 뒤로 스케일이 멈춤🔴 그룹 이름이 바뀌었을 가능성이 큽니다. 3.1 참고
HTTP 403별칭에 <apmAlias>_ACCESS_KEY 가 짝지어져 있는지 확인하십시오
apmAlias ... 에 해당하는 환경변수가 없다apmAlias 가 envHpa 의 name 과 정확히 일치하는지(대소문자 포함)
labelSelector 에 groupName 이 필요하다selector.matchLabels.groupName 이 빠졌습니다
항상 0 으로만 나옴해당 그룹에 실제 트래픽이 있는지, APM 서버가 지표를 집계 중인지
apdex 로 걸었더니 반대로 움직임apdex 는 클수록 좋은 값이라 HPA 에 쓸 수 없습니다. apdexDeficit 을 쓰십시오
응답시간·오류율이 파드 수만큼 작게 나옴target.type 을 AverageValue 로 두었습니다. 1절 표대로 Value 를 쓰십시오
스케일이 안 일어남minReplicas/maxReplicas 범위, target.value 가 너무 큰지 확인