Kubernetes에서는 외부 요청, 저장소, 오토스케일링을 어떻게 다룰까
Kubernetes에서는 외부 요청, 저장소, 오토스케일링을 어떻게 다룰까
앞선 글에서는 클라우드, Docker, Kubernetes의 차이와 함께 Kubernetes의 기본 구조를 정리했습니다. 클러스터, Pod, Deployment, Service까지 이해하고 나면, 애플리케이션을 어떻게 실행하는지는 어느 정도 보이기 시작합니다.
하지만 실제 운영 관점에서 보면 여기서 끝나지 않습니다.
- 외부 사용자의 요청은 어디서 받아야 하는가
- Pod가 재생성되어도 데이터는 어떻게 유지할 것인가
- 트래픽이 늘어나면 Pod 수는 어떻게 조절할 것인가
Kubernetes는 이런 문제도 각각의 리소스로 나누어 다룹니다. 이번 글에서는 외부 요청을 처리하는 방식, 저장소를 다루는 방식, 오토스케일링 방식을 중심으로 정리해보겠습니다.
Service만으로는 왜 부족할까
Service는 Pod에 대한 고정된 접근점을 제공합니다. Pod는 재생성되면 IP가 바뀔 수 있기 때문에, 클라이언트가 Pod를 직접 바라보는 방식은 안정적이지 않습니다. Service는 이 문제를 해결하기 위해 존재합니다.
하지만 Service만으로는 모든 문제가 해결되지는 않습니다. 기본적으로 Service는 클러스터 내부에서 Pod에 접근하기 위한 리소스이기 때문입니다.
즉, 클러스터 내부에서 Pod를 안정적으로 찾는 문제와, 외부 사용자의 요청을 클러스터 안으로 받아오는 문제는 다릅니다.
이 지점에서 Ingress나 Gateway API 같은 리소스가 필요해집니다.
외부 요청은 어떻게 들어올까
애플리케이션을 실제로 서비스하려면, 외부 사용자의 요청이 클러스터 안으로 들어와야 합니다. 예를 들어 브라우저에서 특정 도메인이나 경로로 요청했을 때, 그 요청이 어떤 Service로 전달될지 정해야 합니다.
이 역할을 위해 사용되는 대표적인 방식이 Ingress와 Gateway API입니다.
Ingress
Ingress는 HTTP(S) 요청을 어떤 Service로 보낼지 정의하는 리소스입니다. 예를 들어 다음과 같은 규칙을 생각할 수 있습니다.
api.example.com으로 들어온 요청은 API Service로 전달/web경로는 Web Service로 전달/admin경로는 Admin Service로 전달
다만 Ingress 리소스만 있다고 해서 실제 트래픽이 자동으로 처리되지는 않습니다. Ingress 규칙을 실제로 동작하게 하려면 Ingress Controller가 필요합니다.
즉, Ingress는 규칙 선언이고, Ingress Controller는 그 규칙을 실제로 처리하는 실행 주체라고 볼 수 있습니다.
Gateway API는 무엇이 다를까
Gateway API는 Ingress의 한계를 보완하기 위해 나온 새로운 표준입니다.
Ingress는 구조가 비교적 단순하고 널리 쓰였지만, 몇 가지 한계가 있습니다.
- 주로 HTTP(S) 중심으로 설계되어 있습니다.
- 세밀한 설정이 컨트롤러별 어노테이션에 의존하는 경우가 많습니다.
- 인프라 관리자와 애플리케이션 개발자의 역할을 명확히 나누기 어렵습니다.
Gateway API는 이런 문제를 개선하기 위해 역할을 분리한 구조를 제공합니다.
대표적으로 다음 세 가지 리소스가 자주 등장합니다.
- GatewayClass
- Gateway
- HTTPRoute
GatewayClass
GatewayClass는 어떤 Gateway Controller를 사용할지를 정의하는 리소스입니다. 즉, 트래픽을 처리하는 구현체를 지정하는 역할입니다.
Gateway
Gateway는 어떤 포트와 프로토콜로 요청을 받을지를 정의합니다. 예를 들어 HTTP 80 포트로 요청을 받도록 설정할 수 있습니다.
HTTPRoute
HTTPRoute는 어떤 도메인과 경로의 요청을 어느 Service로 보낼지를 정의합니다.
즉, Gateway API는 크게 보면 다음처럼 역할이 나뉩니다.
- GatewayClass: 어떤 컨트롤러를 쓸 것인가
- Gateway: 어떤 방식으로 요청을 받을 것인가
- HTTPRoute: 받은 요청을 어디로 보낼 것인가
이 구조 덕분에 인프라 설정과 애플리케이션 라우팅 규칙을 좀 더 분리해서 관리할 수 있습니다.
Pod가 재생성되면 데이터는 어떻게 될까
Kubernetes에서 Pod는 영구적인 인스턴스가 아닙니다. 노드 장애, 재스케줄링, 업데이트 등 여러 이유로 언제든 다시 생성될 수 있습니다.
이 말은 곧 Pod 내부에만 저장한 데이터는 사라질 수 있다는 뜻이기도 합니다.
예를 들어 애플리케이션이 업로드 파일이나 로그, 캐시, 상태 데이터를 Pod 내부 파일 시스템에만 저장하고 있다면, Pod가 교체될 때 그 데이터도 함께 사라질 수 있습니다.
따라서 데이터가 유지되어야 하는 경우에는 Pod 바깥의 저장소를 별도로 사용해야 합니다.
StorageClass, PV, PVC는 어떤 관계일까
Kubernetes에서 저장소를 다룰 때 자주 나오는 개념이 다음 세 가지입니다.
- StorageClass
- PersistentVolume(PV)
- PersistentVolumeClaim(PVC)
이 세 개념은 각각 역할이 다릅니다.
StorageClass
StorageClass는 저장소를 어떤 방식으로 만들 것인지에 대한 정책입니다. 예를 들어 어떤 종류의 디스크를 사용할지, 언제 볼륨을 바인딩할지 같은 기준을 정의합니다.
즉, StorageClass는 "어떤 저장소를 어떤 규칙으로 제공할 것인가"에 가까운 개념입니다.
PersistentVolume(PV)
PV는 실제로 할당된 저장소입니다. 클러스터 입장에서 보면, 사용할 수 있는 실체 저장소라고 볼 수 있습니다.
PersistentVolumeClaim(PVC)
PVC는 애플리케이션이 저장소를 요청하는 방식입니다. 즉, Pod가 "이 정도 크기의 저장소가 필요합니다"라고 요청하면, Kubernetes가 적절한 PV와 연결해주는 구조입니다.
정리하면 다음과 같습니다.
- StorageClass: 저장소 제공 방식에 대한 정책
- PV: 실제 저장소
- PVC: 저장소 요청서
왜 PVC를 통해 저장소를 요청할까
Pod가 저장소를 직접 지정하지 않고 PVC를 통해 요청하는 이유는, 애플리케이션과 실제 저장소 구현을 분리하기 위해서입니다.
애플리케이션 입장에서는 "어떤 디스크 제품을 쓸지"보다 "얼마나 필요한지", "어떤 방식으로 접근할지"가 더 중요합니다. PVC는 이 요청을 선언적으로 표현하게 해줍니다.
예를 들어 Pod는 단지 다음과 같은 요구만 표현하면 됩니다.
- 저장소 크기
- 접근 방식
- 어떤 StorageClass를 사용할지
그 뒤의 실제 바인딩 과정은 Kubernetes가 처리합니다.
accessModes는 무엇을 의미할까
PVC를 정의할 때 자주 보게 되는 값이 accessModes입니다.
이 값은 저장소에 어떤 방식으로 접근할 수 있는지를 나타냅니다.
대표적으로 다음과 같은 모드가 있습니다.
- ReadWriteOnce(RWO): 하나의 노드에서 읽기/쓰기가 가능합니다.
- ReadOnlyMany(ROX): 여러 노드에서 읽기만 가능합니다.
- ReadWriteMany(RWX): 여러 노드에서 읽기/쓰기가 가능합니다.
실습 환경이나 로컬 스토리지에서는 보통 ReadWriteOnce를 많이 사용합니다.
특히 로컬 디스크 기반 저장소는 특정 노드에 종속되기 쉬워서, 여러 노드에서 동시에 읽고 쓰는 구성이 어렵기 때문입니다.
StorageClass의 옵션은 왜 중요할까
StorageClass에는 저장소 동작과 관련된 여러 옵션이 있습니다.
그중 자주 보게 되는 것이 reclaimPolicy와 volumeBindingMode입니다.
reclaimPolicy
reclaimPolicy는 PVC가 삭제되었을 때 PV를 어떻게 처리할지를 의미합니다.
- Delete: PVC 삭제 시 PV도 함께 삭제합니다.
- Retain: PVC 삭제 후에도 PV를 유지합니다.
즉, 저장소를 자동으로 함께 정리할지, 아니면 데이터를 남겨둘지를 결정하는 정책입니다.
volumeBindingMode
volumeBindingMode는 PV를 언제 바인딩할지를 결정합니다.
예를 들어 WaitForFirstConsumer는 해당 PVC를 사용하는 Pod가 실제로 스케줄링될 때 바인딩을 진행합니다.
이 방식은 특정 노드에 종속되는 로컬 저장소 환경에서 특히 유용합니다.
왜냐하면 Pod가 어느 노드에 배치될지도 모르는 상태에서 저장소를 먼저 고정해버리면, 실제 스케줄링과 맞지 않을 수 있기 때문입니다.
HPA는 무엇을 할까
애플리케이션을 운영하다 보면 항상 같은 수의 Pod만으로 충분하지 않을 수 있습니다. 트래픽이 몰릴 때는 Pod를 늘리고, 한가할 때는 줄이는 것이 더 효율적입니다.
Kubernetes에서 이런 역할을 하는 리소스가 HPA(Horizontal Pod Autoscaler) 입니다.
HPA는 Deployment 같은 리소스를 대상으로 하여, Pod 수를 자동으로 늘리거나 줄입니다. 즉, 애플리케이션의 수평 확장을 자동화하는 기능입니다.
예를 들어 다음과 같은 정책을 둘 수 있습니다.
- 최소 Pod 수는 2개
- 최대 Pod 수는 6개
- CPU 사용률이 특정 기준을 넘으면 Pod 수 증가
HPA는 무엇을 기준으로 동작할까
HPA는 메트릭을 기준으로 동작합니다. 대표적으로 CPU 사용률이나 메모리 사용량 같은 리소스 메트릭을 기준으로 삼을 수 있습니다.
예를 들어 CPU 사용률 기반으로 동작한다면, 각 Pod의 사용량을 보고 현재 Pod 수가 충분한지 판단합니다.
이때 중요한 점은, HPA가 단순히 "CPU가 높다"는 사실만 보는 것이 아니라 어떤 기준 대비 얼마나 사용 중인지를 계산한다는 점입니다.
requests가 왜 필요할까
HPA가 CPU 사용률 기준으로 동작할 때는 Pod에 설정된 requests 값이 중요합니다.
예를 들어 CPU request가 100m로 설정된 Pod가 있고, 실제 사용량이 50m라면 사용률은 50%입니다.
즉, HPA의 averageUtilization은 requests 대비 사용률을 기준으로 계산됩니다.
그래서 requests가 없으면, 퍼센트 기준의 사용률 계산이 애매해지거나 기대한 방식으로 동작하지 않을 수 있습니다.
정리하면 다음과 같습니다.
- requests: 스케줄링 기준이 되는 최소 자원 요청량
- HPA averageUtilization: requests 대비 사용률 기준
따라서 HPA를 제대로 사용하려면 Pod 리소스 설정도 함께 고려해야 합니다.
metrics-server는 왜 필요할까
HPA가 동작하려면 현재 Pod의 CPU나 메모리 사용량을 알아야 합니다. 이 정보를 제공하는 대표적인 컴포넌트가 metrics-server입니다.
즉, HPA는 혼자서 메트릭을 측정하지 않고, 클러스터 안의 메트릭 수집 도구를 통해 데이터를 받습니다.
실제로 kubectl top pods 같은 명령이 동작하려면 이 메트릭 계층이 준비되어 있어야 합니다.
따라서 HPA를 설정하기 전에, 먼저 클러스터가 리소스 메트릭을 수집할 수 있는 상태인지 확인해야 합니다.
정리
Kubernetes에서는 애플리케이션 실행뿐 아니라, 외부 요청, 저장소, 확장 전략도 각각 별도의 리소스로 관리합니다.
- 외부 요청은 Ingress 또는 Gateway API로 연결합니다.
- 저장소는 StorageClass, PV, PVC를 통해 다룹니다.
- 오토스케일링은 HPA를 통해 처리합니다.
즉, Kubernetes는 단순히 컨테이너를 띄우는 도구가 아니라, 네트워크, 저장소, 확장 전략까지 분리된 리소스로 관리하는 운영 플랫폼이라고 볼 수 있습니다.