3.5. 오토스케일링
어떨 때 보는가
- 부하가 몰리는 시간에 서비스가 느려질 때
- 한가한 시간에 자원이 낭비될 때
- 노드 점검 중에 서비스가 끊기지 않게 하고 싶을 때
자동 조절이 필요한 이유
부하가 늘 때 파드 수를 손으로 늘리면 대응이 늦습니다. 반대로 한가한 시간에 많은 파드를 그대로 두면 자원이 낭비됩니다.
COP 는 두 가지 자동 조절 방식을 제공합니다.
| 방식 | 판단 기준 | 반응 |
|---|---|---|
| HPA | 현재 CPU·메모리 사용률 | 부하가 오른 뒤 늘립니다 |
| CronHPA | 정해진 시각 | 부하가 오르기 전에 늘립니다 |
HPA
HPA(HorizontalPodAutoscaler)는 사용률을 보고 파드 수를 늘리거나 줄입니다.
워크로드 > 수평 자동 확장(HPA) 으로 들어갑니다.

| 열 | 설명 |
|---|---|
| 이름 | HPA 이름 |
| 대상 | 조절할 Deployment 등 |
| 최소 · 최대 | 파드 수의 하한과 상한 |
| 복제본 | 현재 파드 수 |
| 지표 | 현재 사용률 / 목표 사용률 |
동작 방식은 이렇습니다.
- 대상 파드들의 평균 사용률을 잽니다.
- 목표 사용률과 비교합니다.
필요한 파드 수 = 현재 파드 수 × (현재 사용률 ÷ 목표 사용률)로 계산합니다.- 최소·최대 범위 안에서 조절합니다.
예를 들어 파드 2개가 평균 80% 를 쓰고 목표가 50% 면, 2 × (80 ÷ 50) = 3.2 → 4개로 늘립니다.
줄일 때는 늘릴 때보다 천천히 움직입니다. 부하가 잠깐 내려갔다고 바로 줄이면 다시 늘려야 하므로, 일정 시간 낮은 상태가 이어져야 줄입니다.
HPA 를 쓰려면 자원 요청량이 있어야 합니다
HPA 를 걸기 전에 대상 파드에 자원 요청량이 설정되어 있어야 합니다. 없으면 HPA 는 아무 일도 하지 않습니다. 이것이 HPA 가 동작하지 않는 가장 흔한 원인입니다.
왜 필요한가
앞의 계산식에 나오는 "사용률" 은 요청량 대비 비율 입니다. 노드 전체 용량이나 상한이 아닙니다.
사용 률 = 실제 사용량 ÷ 요청량 × 100
요청량이 분모입니다. 요청량이 없으면 분모가 없어 사용률 자체를 구할 수 없고, HPA 목록의
지표 열에 <unknown> 이 뜬 채로 멈춥니다.
요청량·상한이 무엇이고 어떻게 정하는지는 3.1 장에 있습니다. 여기서는 HPA 가 그 값을 어떻게 쓰는지만 봅니다.
계산 예 — COP 샘플 애플리케이션
COP 가 넣어 주는 전자정부 샘플 애플리케이션의 실제 설정으로 따라가 보겠습니다.
| 항목 | 값 |
|---|---|
| CPU 상한 | 2 (2 코어) |
| CPU 요청량 | 별도로 정하지 않음 → 상한과 같은 2 가 자동으로 채워집니다(3.1 장) |
| HPA 최소 파드 수 | 2 |
| HPA 최대 파드 수 | 4 |
| HPA 목표 사용률 | 75% |
여기서 목표 75% 는 "파드 하나가 평균 1.5 코어를 쓰는 상태" 를 뜻합니다.
2 코어(요청량) × 75% = 1.5 코어
파드 2개가 각각 1.8 코어를 쓰고 있다고 하면 이렇게 됩니다.
| 단계 | 계산 |
|---|---|
| 현재 사용률 | 1.8 ÷ 2 × 100 = 90% |
| 필요한 파드 수 | 2 × (90 ÷ 75) = 2.4 → 올림 → 3개 |
| 최대 범위 확인 | 3 은 최대 4 이내이므로 그대로 3개 |
늘어난 뒤에는 같은 부하가 3개로 나뉘므로 파드당 1.2 코어, 사용률 60% 가 되어 목표 아래로 내려갑니다. 부하가 계속 오르면 4개까지 늘고, 4개로도 90% 를 넘으면 더는 늘지 않습니다. 그때는 최대값을 올리거나 다른 병목을 찾아야 합니다.
요청량을 잘못 잡으면 생기는 일
요청량은 배치에 쓰이는 값이면서 동시에 HPA 의 분모입니다. 한 값이 두 가지를 결정하므로 잘못 잡으면 양쪽이 함께 어긋납니다.
| 요청량 | 배치에 미치는 영향 | HPA 에 미치는 영향 |
|---|---|---|
| 실제보다 크게 | 노드에 파드가 몇 개 못 들어갑니다 | 사용률이 낮게 나와 필요한데도 늘지 않습니다 |
| 실제보다 작게 | 붐빌 때 밀려납니다 | 사용률이 높게 나와 필요 없는데도 늘어납니다 |
| 없음 | 자리를 잡지 않습니다 | HPA 가 동작하지 않습니다 |
예를 들어 요청량을 2 코어로 잡았는데 실제로는 0.2 코어밖에 쓰지 않는 애플리케이션이라면, 부하가 다섯 배로 뛰어 1 코어를 써도 사용률은 50% 라 목표 75% 에 못 미쳐 파드가 늘지 않습니다. 화면상 "HPA 는 정상인데 서비스는 느린" 상태가 됩니다.
실제 사용량을 먼저 재고 요청량을 정한 뒤 HPA 를 거십시오. 순서를 바꾸면 목표 사용률을 아무리 조절해도 맞지 않습니다.
메모리 기준으로 조절할 때
메모리 사용률로도 조절할 수 있지만 CPU 만큼 잘 맞지 않습니다. 자바처럼 힙을 미리 잡아 두는 런타임은 실제로 놀고 있어도 메모리 사용량이 줄지 않아, 파드를 늘려도 사용률이 내려가지 않습니다. 그러면 최대치까지 계속 늘어납니다.
메모리는 상한을 제대로 잡는 쪽이 맞고, 자동 조절은 CPU 를 기준으로 하는 편이 안전합니다.
만들기 — YAML
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
namespace: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 75 # 요청량 대비 75%
| 항목 | 설명 |
|---|---|
scaleTargetRef | 조절할 대상. 이름이 틀리면 지표가 <unknown> 으로 남습니다 |
minReplicas | 바닥. 2 이상을 권장합니다 — 1 이면 조절 중에 서비스가 끊길 수 있습니다 |
maxReplicas | 천장. 클러스터가 감당할 수 있는 값으로 둡니다 |
averageUtilization | 목표 사용률. 요청량 기준 입니다(위 절) |
오르내림이 잦으면 반응 속도를 조절합니다.
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 5분 동안 낮아야 줄입니다
scaleUp:
stabilizationWindowSeconds: 0 # 늘릴 때는 바로
줄이는 쪽만 늦추는 것이 요령입니다. 부하가 잠깐 내려갔다고 줄이면 곧 다시 늘려야 해 파드가 계속 오르내립니다.
HPA 가 동작하지 않을 때
지표 열에 <unknown> 이 보이면 사용량을 읽지 못하는 상태입니다.
| 원인 | 확인할 것 |
|---|---|
| 대상 파드에 자원 요청량이 없음 | 가장 흔한 원인입니다. 파드 상세의 요청·제한을 봅니다(위 절) |
| 지표 수집기가 동작하지 않음 | 운영 담당자에게 문의 |
| 대상 이름이 틀림 | 상세 화면의 대상이 실제 Deployment 이름과 같은지 |
| 파드가 방금 떴음 | 첫 측정값이 모이기까지 1분 안팎 걸립니다. 잠시 뒤 다시 봅니다 |
<unknown> 이 아니라 숫자는 나오는데 파드가 늘지 않는 경우 는 원인이 다릅니다.
| 증상 | 원인 |
|---|---|
| 사용률이 목표보다 낮게만 나온다 | 요청량이 실제보다 크게 잡혀 있습니다(위 절) |
| 최대값에 머물 러 있다 | 최대 파드 수가 부족하거나 다른 곳이 병목입니다 |
늘었는데 Pending 에 머문다 | 클러스터에 자리가 없습니다. 노드 자원을 확인합니다(2.1 장) |
최대까지 늘었는데도 느리면 파드 수 문제가 아닙니다. 데이터베이스나 외부 연동이 병목일 수 있으니 모니터링 화면에서 확인하십시오(9.2 장).
CronHPA
CronHPA 는 시각 기준으로 파드 수를 바꿉니다. 부하가 오르기 전에 미리 준비할 때 씁니다.
워크로드 > Cron 자동 확장(CHPA) 에서 봅니다.
일정 표기가 CronJob 과 다릅니다. CronJob 은 다섯 자리인데 CronHPA 는 초를 포함한 여섯 자리 입니다. 3.3 장의 표기를 그대로 쓰면 자리가 하나 밀립니다.
| 특수문자 | 뜻 | 예 |
|---|---|---|
* | 모든 값 | 0 0 * * * * = 매시 정각 |
/ | 간격 | 0 */10 * * * * = 10분마다 |
, | 목록 | 0 0 9,18 * * * = 09:00 과 18:00 |
- | 범위 | 0 0 9-18 * * * = 09:00 부터 18:00 까지 매시 |
이 밖에 정해진 일정 대신 쓸 수 있는 표기가 있습니다.
| 표기 | 뜻 |
|---|---|
@hourly · @daily · @weekly · @monthly · @yearly | 매시 정각 · 매일 자정 · 매주 일요일 자정 · 매월 1일 자정 · 매년 1월 1일 자정 |
@every 1h30m | 1시간 30분마다 |
@date 2026-12-25 09:00:00 | 그 날짜·시각에 한 번 |
@date 는 되풀이하지 않는 일정입니다. 행사나 이벤트처럼 날짜가 정해진 일에 씁니다.
어떨 때 쓰는가
| 상황 | 왜 CronHPA 인가 |
|---|---|
| 업무 시간에만 부하가 몰린다 | 출근 전에 미리 늘려 둡니다. HPA 는 부하가 온 뒤에야 움직입니다 |
| 기동이 오래 걸린다 | 자바 애플리케이션처럼 뜨는 데 수 분이 걸리면 HPA 로는 이미 늦습니다 |
| 정산·마감처럼 시각이 정해져 있다 | 매월 말일, 매일 새벽 배치 시간에 맞춰 늘립니다 |
| 야간·주말에 자원을 줄이고 싶다 | 개발·검증 환경에서 밤에 0 또는 1로 줄여 자원을 아낍니다 |
| 행사 일정이 정해져 있다 | @date 로 시작·종료 시각을 지정합니다 |
| 지표로는 부하를 못 읽는다 | 큐 대기열처럼 CPU·메모리에 드러나지 않는 부하 |
HPA 가 잘 맞지 않는 자리를 메우는 것이 CronHPA 입니다. HPA 는 부하가 오른 뒤 반응하므로 급격히 몰리는 순간에는 이미 느려진 뒤에 늘어납니다.
기본 사용 — 업무 시간에 맞춰 조절
가장 흔한 형태입니다. 평일 업무 시간에 늘리고 그 뒤 줄입니다.
apiVersion: autoscaling.openmaru.io/v1
kind: CronHPA
metadata:
name: app-cronhpa
namespace: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
jobs:
- name: scale-up-morning
schedule: "0 50 8 * * 1-5" # 평일 08:50:00
targetSize: 10
- name: scale-down-evening
schedule: "0 0 20 * * 1-5" # 평일 20:00:00
targetSize: 3
- name: weekend-minimum
schedule: "0 0 0 * * 6" # 토요일 00:00:00
targetSize: 2
| 항목 | 설명 |
|---|---|
scaleTargetRef | 조절할 대상. apiVersion·kind·name 세 가지를 모두 적습니다 |
jobs | 일정 목록. 하나 이상이어야 합니다 |
jobs[].name | 이 CronHPA 안에서 겹치지 않는 이름. 상태 화면에 이 이름으로 나옵니다 |
jobs[].schedule | 언제 실행할지 |
jobs[].targetSize | 그때 맞출 파드 수. 0 도 넣을 수 있습니다 |
targetSize 는 "얼마나 늘릴지" 가 아니라 "몇 개로 맞출지" 입니다. 현재 파드 수와 무관하게
그 값으로 맞춥니다.
대상은 scale 조절이 가능한 자원이면 됩니다. Deployment, StatefulSet, ReplicaSet 을
쓸 수 있습니다.
HPA 와 함께 쓰기
CronHPA 를 Deployment 가 아니라 HPA 에 걸면 둘을 함께 쓸 수 있습니다. 이때 CronHPA 는 파드 수를 직접 바꾸는 대신 HPA 의 최소·최대 파드 수를 조절합니다.
apiVersion: autoscaling.openmaru.io/v1
kind: CronHPA
metadata:
name: app-cronhpa-with-hpa
namespace: my-app
spec:
scaleTargetRef:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler # Deployment 가 아니라 HPA 를 가리킵니다
name: my-app-hpa
jobs:
- name: peak-hours
schedule: "0 50 8 * * 1-5" # 평일 08:50 — 바닥을 5로 올림
targetSize: 5
- name: off-hours
schedule: "0 0 20 * * 1-5" # 평일 20:00 — 바닥을 2로 내림
targetSize: 2
동작은 이렇습니다.
| 시각 | CronHPA 가 하는 일 | 그 뒤 HPA 가 하는 일 |
|---|---|---|
| 08:50 | HPA 최소 파드 수를 5로 올립니다 | 부하가 더 오르면 최대까지 스스로 늘립니다 |
| 20:00 | HPA 최소 파드 수를 2로 내립니다 | 부하가 낮으면 2까지 줄입니다 |
시각 기준으로 바닥을 정하고, 그 위는 HPA 가 실제 부하를 보고 조절합니다. 예측 가능한 부분은 CronHPA 가, 예측할 수 없는 부분은 HPA 가 맡는 구성입니다.
targetSize 가 현재 최대 파드 수보다 크면 최대값도 함께 올라갑니다. 최대를 넘어서는 값을
넣어도 실패하지 않습니다.
한 번만 실행
runOnce: true 를 넣으면 그 일정은 한 번 실행되고 목록에서 사라집니다.
jobs:
- name: one-time-scale-up
schedule: "0 0 9 * * *"
targetSize: 10
runOnce: true
@date 와 함께 쓰면 특정 날짜의 행사에 맞출 수 있습니다.
jobs:
- name: event-start
schedule: "@date 2026-10-03 00:00:00"
targetSize: 20
- name: event-end
schedule: "@date 2026-10-09 00:00:00"
targetSize: 3
특정 날짜에 건너뛰기
excludeDates 에 적은 날에는 모든 일정이 실행되지 않습니다. 공휴일이나 주말에 조절을
멈출 때 씁니다.
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
excludeDates:
- "* * * * * 6" # 매주 토요일
- "* * * * * 0" # 매주 일요일
- "* * * 1 1 *" # 1월 1일
- "* * * 25 12 *" # 12월 25일
jobs:
- name: scale-up
schedule: "0 50 8 * * *"
targetSize: 5
- name: scale-down
schedule: "0 10 18 * * *"
targetSize: 1
excludeDates 도 크론 표기로 씁니다. 2026-01-01 같은 날짜 형식이 아닙니다. 여섯 자리
표기에서 날짜에 해당하는 자리만 지정하고 나머지는 * 로 둡니다.
제외일에는 늘리기도 줄이기도 하지 않습니다. 위 예에서 금요일 18:10 에 1개로 줄인 뒤
토요일·일요일에는 아무 일도 일어나지 않으므로, 월요일 08:50 까지 1개로 유지됩니다. 주말에도
최소 대수가 필요하면 excludeDates 대신 주말용 일정을 따로 넣으십시오.