Do not index
Do not index
안녕하세요? 오토피디아 리서치팀에서 데이터 엔지니어링과 머신러닝 프로젝트에 참여하고 있는 데이터 배관공 Kevin입니다. 이전 스타트업 데이터 배관공 시리즈 글을 이어나가기 전에 스타트업 온프레미스 K8S 구축기 시리즈를 새로 시작하게 되었습니다.
들어가며
스타트업과 대기업을 가리지 않고 많은 회사들에서 쿠버네티스 기술을 적극적으로 도입하거나 도입을 검토하고 있습니다. 기업에서 운영해야 되는 컨테이너 기반의 어플리케이션이 많아지고 복잡해짐에 따라 여러 컴퓨팅 리소스에 워크로드를 잘 분산시키고, 리소스 장애가 발생하더라도 미리 선언해놓은 ‘정상’ 상태를 맞출 때까지 복구시키는 등의 오케스트레이션이 점점 어려워지는데 쿠버네티스는 이에 특화되어 있기 때문입니다.
또 저장소, 워크로드, 네트워크 리소스들의 추상화가 잘 되어 있기 때문에 GCP, AWS, Azure와 같은 클라우드 벤더사들에서 제공하는 매니지드 서비스를 사용하더라도 벤더 의존성을 크게 줄이고 멀티 클라우드(multi-cloud) 혹은 클라우드와 온프레미스가 공존하는 하이브리드 클라우드(hybrid-cloud)를 구축할 때도 용이하다고 소개되어 있습니다.
이러한 장점들은 리서치팀 내에서 운영하고 있는 몇몇 워크로드가 가진 특성과 아주 잘 부합한다고 생각이 들었고 2021년 9월부터 현재까지 3대의 CPU 노드와 2대의 GPU 노드, 1대의 Synology NAS로 이루어진 RKE2 기반의 소규모 온프레미스 쿠버네티스 클러스터를 운영하는데까지 이르렀습니다.
본 스타트업 온프레미스 K8S 구축기 시리즈에서는 오토피디아 데이터 웨어하우스 구축기에서 다룬 오토피디아의 데이터 웨어하우스를 지탱하고 있는 온프레미스 쿠버네티스를 더 자세하게 살펴보는 글입니다. 어떤 상황에서 클라우드에 비해 온프레미스 쿠버네티스를 운영하는 것이 유리할 수 있었는지, 최소한의 고가용성을 갖는 온프레미스 쿠버네티스를 구축하기 위해 어떤 노력들을 가했는지, 온프레미스 쿠버네티스에서 GPU 리소스를 활용하는 것에 관심이 있는 분들께 이 글을 바칩니다.
목차
1편 ← (보고 계신 글)
들어가며1. 온프레미스 쿠버네티스 도입을 마렵게 한 요인들ML API에 필요한 데이터셋 어노테이션을 위한 Label Studio 와 같은 사내 서비스 (Docker Compose 기반)Docker-compose + Celery 스케쥴러 기반의 AirflowGPU가 필요한 몇몇 ML API2. 프로젝트 요구사항 정립하기가용한 장비 현황목표인 것Docker Compose 위주의 단일 서버 환경 ⇒ 고가용성이 확보된 온프레미스 쿠버네티스 클러스터 환경 구축하기훗날 클라우드의 매니지드 쿠버네티스로 전환이 최대한 용이하도록 운영하기쿠버네티스 상에서 GPU 리소스를 활용할 수 있도록 하고, 최소 서로 다른 노드 2대에 배포되도록 하기서울 오피스의 장애 대비책 마련하기목표가 아닌 것3. 고가용성(HA) 온프레미스 클러스터 구축하기온프레미스 쿠버네티스 솔루션 선택하기 — RKE2컨트롤 플레인, 워커 역할 분배하기SSD 장애에 대응 가능한 스토리지 레이어 만들기외부 도메인과 안정적인 네트워크 연결하기4. 최종 아키텍쳐 모습5. 한계와 개선할 점6. 프로젝트 후기마치며Reference
1. 온프레미스 쿠버네티스 도입을 마렵게 한 요인들
온프레미스 쿠버네티스 클러스터 구축 이전에는 주변에 굴러다니던 게임용 데스크탑을 Ubuntu 서버로 개조(???: 이젠 죽여줘… / Kevin: 어림도 없다!!)하여 단일 서버 환경에서 아래와 같은 워크로드를 운영하고 있었습니다. 시간이 지남에 따라 각 워크로드 별로 아래와 같은 문제점들을 느꼈는데요.
ML API에 필요한 데이터셋 어노테이션을 위한 Label Studio 와 같은 사내 서비스 (Docker Compose 기반)
- Docker Compose 기반으로 운영했을 때 종종 좀비 프로세스로 돌변하며 유지보수에 리소스가 들어감
- Label Studio 특성 상 어노테이션 데이터는 S3에 올라가지만 진행 상태 정보와 같은 메타데이터는 로컬 SSD의 DB에 저장했기 때문에 SSD 장애 발생 시 메타 데이터가 모두 유실될 위험이 존재
- 사내 서비스 특성 상 트래픽은 작으나 비정기적이고 간헐적으로 사용될 수 있기 때문에 항상 배포는 되어 있어야 함
- 허용 다운타임 : 1~2일 미만
Docker-compose + Celery 스케쥴러 기반의 Airflow
- 마찬가지로 Docker Compose 기반이라 Airflow 스케쥴러나 Task 프로세스가 죽었을 때 정상적으로 복구 되지 않는 경우가 많았고 심지어 종료조차 되지 않는 좀비 프로세스가 심심찮게 생성됨 (Airflow 클러스터 자체가 불안정한 경우가 많음)
- Task가 많아지고 다양해지면서 각 Task에서 요구되는 라이브러리도 함께 다양해졌음. Airflow 도커 이미지가 점점 의존성 지옥에 빠지기 시작함. KubernetesPodOperator가 쓰고 싶었졌음
- Batch Job이고 각 DAG 별로 실행 시각과 실행 주기가 다르기 때문에 리소스 사용량이 일정하며 피크가 거의 발생하지 않음
- 허용 다운타임 : 10분 미만
GPU가 필요한 몇몇 ML API
- 타이어 사진으로부터 마모 상태를 예측하는 닥터트레드 AI가 대표적인 예
- 내부 서비스, 외부 파트너사들에게 제공되는 ML API인 만큼 고가용성을 위해서 최소 2개 이상의 GPU 노드에 배포가 필요함
- 멀티 노드 배포이기 때문에 로드 밸런싱이 되어야 함
- 클라우드 GPU 인스턴스를 사용하기에는 장기적으로 가성비가 무척 좋지 않음
- 허용 다운타임 : 1분 미만
쿠버네티스를 도입한다면 위의 문제점을 대부분 해결할 수 있을 것으로 기대했습니다. 그러나 여기까지 읽었을 때는 그냥 ”클라우드 매니지드 쿠버네티스 쓰면 되는거 아닌가? 왜 하필 온프레미스..?” 라고 생각하실 수 있을텐데요. 굳이 “온프레미스” 쿠버네티스를 쓰게 된 이유는… CPU 서버와 GPU 서버를 운 좋게 지원 받아서 가용한 장비가 많아졌기 때문입니다.
만약 장비를 지원 받지 못 했더라면 초기 투입 비용이 작은 매니지드 쿠버네티스 서비스로 시작했을 가능성이 높다고 생각합니다. 그러나 메이저 클라우드 벤더사의 On-demand GPU 인스턴스들은 대체로 6개월 이상 운영하면 동급 장비를 구매할 수 있을 정도로 장기 운영 시 가성비가 좋지 않습니다. (???: GPU Spot Instance 있잖아요. / Kevin: 읍읍.. 일단 한번 들어보시죠)
2. 프로젝트 요구사항 정립하기
가용한 장비 현황
요구사항을 정립하기 전에 우선 가용한 장비들을 나열해보면 위 그림과 같습니다. CPU 노드와 NAS 노드는 서울 사무실 내 서버랙에 호스팅이 되어 있고 GPU 노드들은 외부 IDC 센터에 놓여져 있습니다. 각 노드들은 모두 공인 IP를 한개씩 가지고 있습니다.
이 장비들을 가지고 어디까지 어떻게 잘 활용할까 고민하며 아래와 같은 스코프를 정의했습니다. 바쁘신 분들을 위해 각 목표를 달성하기 위한 접근법들을 함께 정리했습니다.
목표인 것
Docker Compose 위주의 단일 서버 환경 ⇒ 고가용성이 확보된 온프레미스 쿠버네티스 클러스터 환경 구축하기
- 컨트롤 플레인 : 최소 2개 이상의 Zone에 있는 3개의 노드로 구성된 컨트롤 플레인 구성하기
- 스토리지 리소스 : RAID 1 구성의 NAS 상에 PV 만들기
- 네트워크 : Route53 상에서 컨트롤 플레인 노드들의 IP를 A 레코드로 추가 후 라우팅 정책 설정하기
- 그럼에도 불구하고 장애가 났을 때 : etcd 스냅샷 남겨서 빠르게 복구하기
훗날 클라우드의 매니지드 쿠버네티스로 전환이 최대한 용이하도록 운영하기
- 배포 용이성 : Helm 기반으로 배포하기
- Stateful한 리소스 : DB는 가능하다면 처음부터 클라우드 인스턴스를 활용하기
- 네트워크 엔드포인트 : 워크로드 별로 서브도메인을 할당하고 프로젝트나 환경 구분은 Ingress 상에서 URL Path로 지정하기
쿠버네티스 상에서 GPU 리소스를 활용할 수 있도록 하고, 최소 서로 다른 노드 2대에 배포되도록 하기
- 컨테이너 런타임을
containerd
로 변경하고 Nvidia GPU Operator 활용하기
topologySpreadConstraints
옵션 활용하기
서울 오피스의 장애 대비책 마련하기
- 평상 시에는 GPU 리소스가 필요한 워크로드들만 GPU 노드에 배포되고 그 외의 리소스들은 CPU 노드에 배포. 단, 서울 오피스의 경우 IDC 시설이 아니기에 훗날 사무실 이사나 정전, 네트워크 단절과 같은 CPU 노드의 다운타임이 발생할 경우에 GPU 노드 상에 긴급 배포가 가능할 것
AntiNodeAffinity
옵션 활용하기
- 노드 Drain 명령어 활용하기
목표가 아닌 것
- 오토스케일링 : 앞서 서술한 온프레미스 쿠버네티스에서 운영할 워크로드의 특성 상 트래픽이 급증하는 특성이 없으므로 클러스터의 Scale-out을 고려하지 않았습니다.
- 하이브리드 클라우드 환경 : 클라우드 벤더사에서는 On-premise 장비를 클라우드 상에 편입시켜 관리할 수 있는 서비스(GCP Anthos, AWS EKS Anywhere)를 하나둘씩 내놓고 있습니다. 하지만 당장은 클라우드 환경 내에서 모든 리소스를 관리해야 할 필요성이 없으며 Rancher가 제공하는 GUI 환경을 통해서 충분히 쉽게 클러스터를 관리할 수 있다고 판단했습니다.
1편 글에서는 첫번째 목표인 고가용성 온프레미스 클러스터 구축을 위한 아키텍쳐를 중심으로 다루며 2편에서는 2번과 3번 목표를 달성하기 위한 Step-by-Step 튜토리얼, 3편에서는 구축된 클러스터에 장애를 일으켜보며 고가용성이 달성되는지 테스트하는 내용을 다룰 예정입니다.
자, 이제 할 일이 정해졌고 머리가 명료해졌으니 차근차근 살펴볼까요?
3. 고가용성(HA) 온프레미스 클러스터 구축하기
고가용성은 가장 간단하게는 고장이 잘 나지 않는 특성이라고 볼 수 있는데요. 일반적으로 클러스터를 구성하는 요소들을 다중화시키는 구조로 한 쪽이 실패하더라도 정상 상태인 요소가 복구 과정 동안 버텨주는 형태로 고가용성을 챙길 수 있겠습니다. 쿠버네티스 클러스터의 경우 단순히 노드 수가 많다고 고가용성이 확보되는 것은 아니며 클러스터를 구성하는 하드웨어/소프트웨어 컴포넌트가 단일 장애 지점(Single Points of Failure)이 아닐 때 전체 클러스터가 고가용성을 충족한다고 이야기 할 수 있겠습니다. 하지만 모든 개별 요소들에 대해서 다중화를 하는 것은 적지 않은 비용이 들며 프로젝트의 요구사항과 예산 범위 내에서 적절히 타협을 할 수 밖에 없는 것 같습니다.
본 프로젝트에서는 크게 온프레미스 쿠버네티스 솔루션을 결정한 뒤에 컨트롤 플레인, 스토리지, 네트워크, GPU 컴포넌트 관점에서 가용성을 높이기 위한 노력들을 가했습니다.
온프레미스 쿠버네티스 솔루션 선택하기 — RKE2
고가용성 온프레미스 쿠버네티스 클러스터를 구축하는데에는 대표적으로 Kubeadam, Kubespray, RKE2와 같은 선택지가 있습니다. 실은 RKE2는 다른 두 선택지와 비교했을 때 아직 입지가 작다고 느꼈지만 조사 결과 클러스터 구축에 필요한 세팅이 가장 간편하고, GPU 리소스를 활용하는 레퍼런스가 있었으며, 클러스터 장애 시 etcd 스냅샷으로부터 바로 복구할 수 있는 기능을 지원하며, Rancher를 만든 회사에서 관리하는 쿠버네티스 배포판이라 조금 더 신뢰가 갔습니다.
컨트롤 플레인, 워커 역할 분배하기
쿠버네티스 클러스터 구축 시에는 etcd, 스케쥴러(kube-scheduler), 컨트롤러 매니저(kube-controller-manager), DNS 서버, API 서버(kube-apiserver) 등과 같이 클러스터 전반을 관장하는 컴포넌트들로 구성된 컨트롤 플레인(Control Plane) 역할을 해줄 노드가 최소 1대 이상 필요합니다. 일종의 조장 같은 역할이라고 볼 수 있죠. 워커(Worker)는 사용자가 배포한 워크로드를 실행하는 일꾼 같은 역할을 담당합니다.
RKE2 공식 가이드에 따르면 고가용성(High-Availabilty)을 위해서는 컨트롤 플레인 역할을 할 노드 수를 정족수로 유지하라고 되어 있습니다. NAS 노드를 제외하면 총 5개의 노드가 있는데요. 모든 노드는 워커 역할을 기본적으로 부여받으며 위 그림과 같이 서울 오피스의 CPU 노드 2개, IDC의 GPU 노드 1개에만 컨트롤 플레인 역할을 추가로 부여했습니다. 일반적으로 한 노드에는 컨트롤 플레인과 워커, 둘 중 하나의 역할만 할당하는 것을 권장하지만 리소스가 녹록치 않은 경우에는 조장에게 일꾼 역할도 같이 부여할 수 있습니다. (우리가 미안해..)
더불어서 IDC 센터에 있어 상대적으로 안정된 환경에 있는 GPU 노드 2개를 컨트롤 플레인에 편입시키지 않았는데요. 이유는 일반적으로 서울 오피스에 다운 타임이 발생할 가능성이 크고 이 경우에 만약 GPU 노드 2대만 운영 중일 경우 정족수가 유지되지 않아 클러스터의 리더 노드 선출 과정에서 경합(Race)이 발생할 가능성이 있다고 판단했습니다.
SSD 장애에 대응 가능한 스토리지 레이어 만들기
리서치팀에서 운영하는 워크로드에는 메타데이터 저장 용도의 DB가 적잖이 포함되어 있습니다. 이때 DB 파일 저장소로 활용할 수 있는 옵션으로는 (1) 워크로드가 실행되는 노드의 로컬 파일 시스템. (2) NFS 기반으로 마운팅된 NAS 상의 볼륨. (3) 안정적인 클라우드의 매니지드 DB 인스턴스가 있습니다. 각 옵션 별로 장단점이 다르기에 운영 정책에 대해서 고민을 많이 했습니다.
우선 노드의 로컬 파일 시스템의 경우 해당 노드에 장애가 발생할 경우 워크로드는 다른 노드에 다시 복구되더라도 기존 로컬 파일 정보까지 함께 복구되지는 않으므로 Stateless한 쿠버네티스의 신념 상 적절하지 않습니다.
NAS 볼륨의 경우 가용한 NAS 장비가 1대 밖에 없었기에 실질적으로 단일 실패 지점으로 볼 수 있으며 서울 오피스가 다운되는 경우에는 다른 워커 노드들이 저장소에 엑세스가 불가능해지는 상황이 발생합니다.
결과적으로 허용되는 다운 타임이 서울 오피스의 예상 복구 시간인 수시간~1일 정도보다 긴 경우에는 NAS를 사용하고 그 이하인 경우에는 클라우드 매니지드 DB를 활용하기로 결정했습니다. Label Studio와 같은 사내 툴들은 허용 다운타임이 긴 만큼 NAS 상에 PV(Persistence Volume)를 만들고 NFS(Network File System)로 마운팅하여 사용했으며 Airflow의 경우 허용 다운타임이 분 단위이기 때문에 GCP의 가장 작은 Cloud SQL 인스턴스를 선택했습니다.
더불어서 SSD의 경우 하루 아침에 소리소문 없이 운명을 달리하는 경우가 있고 (실제로 당해봄) HDD와 달리 데이터 복구가 무척 어렵습니다. 이에 NAS 상에서 프로덕션용으로 SSD를 활용한다면 안정성이 높은 NAS용 SSD를 2대 이상 구매하며 RAID 구성을 하는 것을 추천드립니다. RAID 구성은 일반적으로 동일한 자료를 2대의 물리 스토리지에 복사하여 저장하기 때문에 하나의 SSD에 장애가 일어나더라도 데이터 유실을 방지할 수 있습니다. 본 프로젝트에서는 동일 용량의 NAS용 SSD를 2대 구매하여 Synology Hybrid RAID(SHR)로 구성하였습니다. 기존 RAID 방식은 추후 다른 용량의 스토리지를 구매하여 엮을 때 사용하지 못하고 버려지는 용량이 생기는데 SHR은 유휴 공간을 최소화하여 활용할 수 있다는 장점이 있어 선택했습니다.
외부 도메인과 안정적인 네트워크 연결하기
마지막 단계로 쿠버네티스 클러스터 내부 뿐만 아니라 외부 API 요청이 오가는 네트워크도 이중화가 필요합니다. 가장 단순하게는 컨트롤 플레인 노드의 IP로 바로 요청을 보내는 방법이 있지만 해당 노드가 다운되어 있을 때 외부에서 클러스터로의 모든 접근이 불가능해지는 불상사가 발생합니다. 또한 노드의 IP가 변경되었을 때 고객사를 포함한 모든 클라이언트 측에서 호출 IP를 변경해줘야 하기 때문에 그리 권장되는 방식이 아닙니다.
RKE2 공식 가이드 상에서도 이러한 문제를 예방하기 위해 [ 도메인 주소 → 로드 밸런서 → 컨트롤 플레인 노드 ]의 구성으로 네트워크 설정을 권장하고 있습니다. 예를 들자면 “onprem.example.com” 서브도메인을 Route53에 등록한 뒤에 로드 밸런서를 붙이고 로드 밸런서의 IP 풀에 컨트롤 플레인 노드들의 퍼블릭 IP를 할당하는 것입니다. 하지만 안타깝게도 현재 AWS 상의 로드 밸런서 중 ALB만 외부 IP에 대한 라우팅을 지원하고 있으나 이마저도 VPN 혹은 AWS Direct Connect로 연결된 IP에 대해서만 지원하고 있습니다. 아쉽게도 이 부분은 아직 관련 지식이 부족하여 로드 밸런서를 활용하지는 못하고 Route53의 라우팅 정책을 활용하기로 했습니다. (관련된 조언/훈수는 언제나 환영입니다!)
(권장되지는 않지만) Route53을 로드밸런서처럼 쓰기
Route53에서 A 레코드를 생성하게 되면 주어진 도메인/서브도메인에 대해 쿼리 요청이 왔을 때 지정된 IP 주소를 반환하게 됩니다. 이러한 A 레코드는 일반적으로 하나의 IP 주소로 맵핑되지만 라우팅 정책 설정 값에 따라서 여러 개의 IP 주소를 등록해놓고 round robbin과 같은 방식으로 반환하거나, primary IP가 실패하는 경우에 secondary IP로 쿼리 값을 바꿔주는 등의 활용이 가능합니다.
본 프로젝트에서는 라우팅 정책을
가중치 기반(Weighted)
로 설정하고 컨트롤 플레인들의 IP를 동일한 가중치로 등록해놨습니다. 특정 노드에 장애가 발생하여 비가용한 상태가 되면 해당 노드의 A 레코드 가중치 값을 0으로 변경함으로써 “onprem.example.com” 으로 오는 요청이 더 이상 장애가 난 컨트롤 플레인 노드로 전달되지 않도록 합니다. 더불어서 레코드 생성 시에 TTL(Time to Live) 값을 충분히 작게 설정하지 않으면 아무리 빠르게 장애 노드의 레코드 가중치를 0으로 변경하더라도, DNS 쿼리 값이 캐싱되어 있기 때문에 TTL 시간 동안 계속해서 장애 노드로 네트워크 요청이 전달될 수 있습니다. 이러한 상황을 방지하기 위해서 본 프로젝트에서는 10초로 설정하였습니다. 단 TTL 값이 작게 설정되면 DNS 쿼리 비용이 증가할 수 있다는 점을 감안해야 합니다.위와 같이 가중치 기반의 라우팅 정책으로 3개 노드의 IP 주소를 등록한 후 터미널에서
nslookup -type=a onprem.example.com
으로 A 레코드가 반환하는 IP 값을 확인해보면 실제로 클라이언트마다 반환 값이 3개 노드 중 하나임을 확인할 수 있습니다.마지막으로 컨트롤 플레인 노드의 Health 체크 결과에 따라 어떻게 자동으로, 재빠르게 가중치 값을 조정할 수 있을까요? Route53에서는 CloudWatch 커스텀 지표를 레코드의 상태 확인(Health Check)으로 지정할 수 있어 컨트롤 플레인 노드들의 상태를 CloudWatch 커스텀 지표로 수집할 수 있다면 자동화된 레코드 값 관리가 가능합니다. 자세한 설정은 추후 기회가 된다면 다른 글에서 다뤄보겠습니다.
결과적으로 위 도식도와 같이 정상 상태일 때는 각 노드의 IP가 동일한 확률로 DNS 쿼리 값을 반환되다가 특정 노드에 장애가 생기면 A 레코드의 가중치가 0으로 변경되고 해당 레코드를 제외한 나머지 정상 상태의 노드 IP로 요청이 라우팅 되는 구조입니다.
4. 최종 아키텍쳐 모습
최종적으로 구성된 RKE2 기반의 쿠버네티스 클러스터 구조는 위 도식도와 같습니다. 위 도식도에서는 회색 영역은 해당 리소스가 존재하는 서비스 혹은 리전을 나타냅니다. 온프레미스 쿠버네티스를 구성하는 요소들이 AWS, GCP, 서울 오피스, IDC 센터에 걸쳐져 있습니다.
위에서도 다루었듯이 외부에서 컨트롤 플레인으로의 API 요청은 CloudWatch와 Route53에 의해 관장됩니다. 하나의 컨트롤 플레인 노드가 죽어도 정상 상태의 노드로 요청이 전달됩니다. 컨트롤 플레인은 2개 리전에 나누어서 총 3대의 노드로 구성하였습니다.
5대의 노드들은 모두 노란색으로 표기된 것처럼 워커 노드 역할도 함께 수행합니다. 마지막으로 스토리지 레이어에서 NAS 노드의 경우 물리적으로 2대의 SSD가 RAID 구성이 되어 한 개의 SSD 장애까지는 데이터 유실 없이 대응 가능합니다. 다운타임이 중요한 워크로드 DB는 GCP 내의 Cloud SQL에서 관리됩니다. Cloud SQL도 저장소 이중화 옵션을 활성화시켰습니다.
가장 장애 확률이 높은 서울 오피스에 문제가 생기더라도 NAS 저장소를 활용하는 워크로드를 제외한 나머지 워크로드는 IDC 센터 내에 있는 2대의 GPU 노드로 이전되어 지속 운영이 가능합니다. GPU 노드가 CPU 노드의 2배 정도의 스펙을 가지고 있으므로 거의 4대의 CPU 노드와 맞먹습니다.
5. 한계와 개선할 점
아쉽지만, 완벽한 고가용성은 상상 속의 동물과도 같은 것 같습니다. 이번에 구축한 시스템의 한계와 개선할 점에 대해서 기록하고 기회가 될 때 하나씩 보완해나가려고 합니다. 피드백 해주신 동료 분들과 외부 개발자 분들께 감사의 말씀을 드립니다.
- 로드 밸런서의 부재 : Route53의 가중치 기반 라우팅 정책도 그럭저럭 쓸만하지만, 로드밸런서 처럼 요청 실패 시에 다른 노드로 재요청 해주는 기능이 없기 때문에 개선이 필요합니다.
- NAS 장비의 이중화가 필요함 : NAS 장비가 1대이므로 맛이 갈 경우 PV에 액세스가 불가능해집니다. NAS 장비도 이중화가 필요할 듯 한데 아직 다수의 NAS 장비를 클러스터처럼 엮는 방법을 잘 모르겠습니다. Gluster 키워드를 중심으로 조사해 봐야겠습니다.
- GPU 노드의 컨트롤 플레인에 장애가 일어났을 때 CPU 컨트롤 플레인 노드 간의 경합 : 아직 테스트를 못해봐서 추가적인 실험이 필요할 듯 합니다.
- 노드 간의 VPN 구성 등을 통한 보안성 강화
- Ansible을 활용한 노드 프로비저닝 자동화
- Prometheus를 통한 노드, 컨테이너 모니터링 및 알럿 시스템 구축
- Vault(?) 등을 통한 크레덴셜 관리 강화
- 쿠버네티스의 자체 설정
- 하이브리드 쿠버네티스 : 언젠가 기회가 된다면 온프레미스 리소스의 부하가 올라갔을 때 자동으로 클라우드의 스팟 인스턴스 노드가 프로비저닝 되어 Horizontal Scale-Out 할 수 있는 하이브리드 형태의 쿠버네티스 클러스터도 구축해보고 싶습니다.
6. 프로젝트 후기
단순히 가용한 하드웨어들의 스펙 뿐만 아니라 호스팅 장소의 특성, 운영해야 되는 워크로드 별 특성, 운영 비용, 먼 훗날 발생할지도 모르는 장애나 마이그레이션 상황을 함께 고려하며 최선의 아키텍쳐를 만들어나가야 했던 다소 도전적인 프로젝트였습니다.
특히 프로젝트 착수 시기에는 쿠버네티스가 가지는 보편적인 장점들에 대해서만 알고 있었던터라 클러스터 세팅과 쿠버네티스 전반에 관한 학습을 병행했습니다. 더불어서 온프레미스 클러스터 환경에서의 자료가 흔치 않아 간단한 Nginx 데모 앱을 원하는대로 작동시키기까지 YAML 파일과 새벽까지 여러 차례 영혼의 맞짱(?)을 떴던 것이 기억에 남습니다.
또 어느날은 잘 운영 중이던 클러스터가 갑자기 운명을 달리하며 도저히 복구가 불가능한 상황에 빠져 클러스터 세팅을 처음부터 다시 했던 경우도 있었습니다. 이 때의 경험은 올해 초 저를 가장 힘들게 했던 이벤트였으며 인프라 세팅 후 프로덕션에 올리기 전, 장애 시나리오 별 대응 메뉴얼을 만들어 놓은 뒤 의도적으로 장애를 만들어 절차대로 따랐을 때 정상 상태로 되돌아 올 수 있는지 훈련하는 것이 얼마나 중요한지 몸소 깨닫게 했습니다.
많은 우여곡절이 있었고 안정화에 예상보다 다소 시간이 더 소요되었지만 소기의 목표들이 하나씩 달성됨에 따라 리서치팀을 괴롭히던 문제점들이 하나 둘 해결되고 유지보수를 크게 할 필요가 없는 수준으로 올라오면서 마음이 무척 개운해졌습니다. 더불어 오토피디아의 데이터 플랫폼을 지탱하는 중추가 훨씬 더 단단해져 뿌듯했습니다. 끝으로 어렵게 구한 GPU 리소스들을 더 쉽고 다양한 방식으로 활용할 수 있게 되어 내부적으로 진행 중인 여러 ML 프로젝트들을 배포할 생각에 가슴이 두근거립니다!
마치며
시간 내어 긴 글 읽어주셔서 감사하며 이어지는 2편 — 온프레미스 쿠버네티스에서 NAS, GPU 사용하기 (with RKE2, NFS, gpu-operator)에서는 위 글에서 서술한 고가용성 클러스터를 실제로 구축하고, NAS도 붙이고, GPU 리소스를 인식시키기 위한 Step-by-Step 튜토리얼 글이 이어집니다.
더불어 오토피디아에서는 국내 1등 차량 정비 플랫폼을 함께 만들어 나갈 분들을 모시고 있습니다. 데이터와 기술을 바탕으로 정비 시장의 정보 격차를 줄이고 운전자 분들의 차량 문제 해결을 돕는 것에 관심 있는 분들께서는 오토피디아 채용 페이지에서 더 자세한 내용을 확인하실 수 있습니다.
다음 글에서 만나요!