5. 쿠버네티스 설계 - 100-hours-a-week/KTB4-17th-wiki GitHub Wiki
1. 쿠버네티스 사용 이유
도메인별로 독립 운영되는 애플리케이션이 증가하고, 실시간 통신·AI 추론·비동기 처리·정기 배치 등 워크로드의 실행 방식도 다양해졌다.
이에 따라 워크로드별 배포, 확장, 자원 할당, 실행 일정, 장애 복구를 일관된 운영 모델로 관리할 필요성이 커졌다.
1-1. 독립적으로 배포·운영해야 하는 애플리케이션이 증가했다.
| 도메인 | 담당 팀 |
|---|---|
| 인증 | 인증 팀 |
| 채팅 | 채팅 팀 |
| 명리학 | 명리학 팀 |
| 유저 | 유저 팀 |
| 추천 | 추천 팀 |
도메인마다 변경 주기, 트래픽 패턴, 장애 대응 요구가 다르므로 애플리케이션을 독립적으로 배포하고 확장할 수 있어야 한다.
또한 같은 도메인 안에서도 API 서버, 비동기 워커, 배치 작업의 운영 요구가 다르므로 필요에 따라 배포·실행 단위를 분리할 수 있어야 한다.
1-2. 워크로드의 실행 및 확장 모델이 다양해졌다.
서비스가 확장되면서 API, WebSocket, 비동기 Worker, Batch, AI 추론 등 생명주기와 확장 기준이 서로 다른 워크로드가 증가했다.
| 워크로드 유형 | 실행 특성 | 주요 확장·운영 기준 | Kubernetes Resource Model |
|---|---|---|---|
| REST API | 상시 실행, Stateless | RPS, CPU | Deployment + HPA |
| WebSocket | 장기 연결 유지 | 동시 연결 수, Memory, 메시지 처리량 | Deployment + HPA |
| 큐 기반 Worker | 이벤트 발생에 따른 비동기 처리 | 큐 적체량, 작업 대기 시간 | Deployment + KEDA |
| 완료형 비동기 작업 | 작업 수행 후 종료 | 작업량, 처리 시간 | Job / ScaledJob |
| 예약 작업 | 정해진 일정에 실행 | 실행 주기, 작업량 | CronJob → Job |
| 대규모 Batch | 대량 데이터 처리 후 종료 | 처리량, 실행 시간, CPU·Memory | Job |
| AI 추론 | 실시간 또는 비동기 추론 | 동시 요청, 추론 처리량, 자원 요구량 | Deployment / Job + HPA·KEDA |
ECS에서도 이러한 워크로드를 운영할 수 있지만, 워크로드의 실행 방식과 확장 정책이 다양해질수록 각 특성에 맞는 운영 구성을 개별적으로 관리해야 한다.
Kubernetes에서는 이를 Deployment, Job, CronJob 등의 Resource로 추상화하고, HPA·KEDA 등의 Controller를 결합하여 서로 다른 워크로드를 공통된 Resource Model과 운영 방식으로 관리할 수 있다.
따라서 다양해진 워크로드의 실행·확장 정책을 일관된 운영 모델로 관리하는 것을 Kubernetes 도입의 주요 근거로 판단했다.
1-3. 복잡해진 스케줄링 정책을 일관된 모델로 관리할 수 있다
워크로드가 다양해지면서 필요한 자원뿐만 아니라 실행할 노드와 워크로드 간 배치 관계까지 달라졌다.
| 워크로드 특성 | 주요 자원 또는 병목 | 배치·운영 요구 |
|---|---|---|
| 일반 API | CPU / Memory | 자원 요청량에 맞는 범용 노드 배치 |
| WebSocket | Memory / Network | 연결 부하를 고려한 자원 확보 및 여러 노드에 분산 배치 |
| 이미지 처리 | CPU / Memory | 연산량에 맞는 자원 할당, 필요 시 연산용 노드 풀 사용 |
| 자체 LLM 추론 | GPU / VRAM / Memory | 모델 크기와 GPU 종류에 맞는 노드 배치 |
| 자체 Vision 추론 | GPU / VRAM / Memory | 모델 요구사항에 맞는 GPU 노드 배치 |
| 외부 AI API 연동 | CPU / Memory / Network | 호출 동시성, 응답 대기, API 제한을 고려한 워커 운영 |
| 대규모 추천 배치 | CPU / Memory / 데이터 I/O | 충분한 자원 확보 및 실시간 서비스와의 자원 경쟁 완화 |
워크로드별 CPU·Memory 요구량은 Requests / Limits로 명시하고, GPU 등 특정 자원이 필요한 워크로드는 Node Label, Affinity, Taint / Toleration 등의 스케줄링 정책을 통해 적합한 노드에 배치할 수 있다.
또한 실시간 서비스와 배치·AI 워크로드를 서로 다른 Node Group으로 분리하여 자원 경쟁을 줄이고, HPA / KEDA를 통해 API 트래픽이나 Queue 적재량 등 각 워크로드의 특성에 맞게 독립적으로 확장할 수 있다.
이를 통해 서로 다른 자원 및 배치 요구사항을 가진 워크로드를 Kubernetes의 공통된 리소스·스케줄링 모델로 관리한다.
1-4. 벤더 종속을 줄일 수 있다
ECS를 중심으로 애플리케이션 실행·확장·배치 정책을 구성하면 AWS 고유 운영 모델에 대한 의존도가 높아진다.
Kubernetes를 사용하면 Deployment, Job, Service, Controller 등 Kubernetes API를 기준으로 CSP와 애플리케이션 운영 모델 사이에 공통 추상화 계층을 둘 수 있다.
당장 멀티 클라우드의 계획이나 클라우드 이전을 고려하고 있는 것은 아니지만, 인프라 선택권을 유지하기 위해 벤더 종속을 낮추는 것이 이상적이다.
이를 통해 특정 CSP의 가격이나 계약 조건이 변경되었을 때 발생하는 전환 비용을 낮추고, 다른 실행 환경으로 이전할 수 있는 Exit Option을 확보한다.
이러한 선택권은 장기적인 클라우드 비용 및 계약 협상에서도 협상력을 유지하는 기반이 될 수 있다.
1-5. 모니터링 표준화
현재 우리 서비스는 AI 추론서버(EC2)와 api서버(fargate)를 함께 사용한다.
- api서버 : ECS Fargate에서는 서버에 직접 접근할 수 없기 때문에 필요한 경우 각 Task에 모니터링 Sidecar(모니터링 컨테이너)를 추가해야 한다.
- GPU용 서버 ECS on EC2에서는 EC2 서버에 노드 단위 모니터링 에이전트를 설치할 수 있다.
⇒ 쿠버네티스 사용하는 경우 : CPU 노드와 GPU 노드 모두 DaemonSet을 이용해 노드마다 동일한 모니터링 pod를 사용할 수 있다.
2. 클러스터 도구 결정
| 비교 기준 | EKS | EC2 + kubeadm | GKE Standard |
|---|---|---|---|
| 성격 | AWS 관리형 Kubernetes 서비스 | 직접 Kubernetes를 구축하는 도구 | Google Cloud 관리형 Kubernetes 서비스 |
| 컨트롤 플레인 | AWS가 운영 | 팀이 구축·운영 | Google이 운영 |
| 컨트롤 플레인 고가용성 | AWS가 여러 AZ에 걸쳐 관리 | 다중 컨트롤 플레인·etcd·로드밸런서를 직접 구성 | Regional 클러스터에서 여러 존에 걸쳐 제공 |
| 클러스터 유지보수 | 컨트롤 플레인 운영은 AWS 담당. 버전 계획과 호환성 검증은 팀 담당 | 인증서·etcd 백업과 복구·업그레이드를 팀이 담당 | Google이 컨트롤 플레인을 관리. 팀은 호환성과 변경 영향을 검증 |
| 워커 노드 | 생성·교체 절차 지원. 용량 정책과 업데이트 적용은 팀 관리 | EC2·OS·런타임·kubelet·노드 교체를 직접 관리 | 노드 풀 설정은 팀 관리. 자동 업그레이드·자동 복구 기본 제공 |
| Pod 네트워크 | AWS VPC CNI 기본 제공. 설정·업데이트 관리 필요 | CNI를 직접 선택·설치·관리 | 클러스터 네트워킹 제공 |
| 기존 AWS 자원 활용 | 같은 AWS 환경에서 유지·연동 가능 | 같은 AWS 환경에서 유지·연동 가능 | AWS 자원 유지 시 클라우드 간 연동 필요. GCP로 옮기면 이전 범위 증가 |
| 세밀한 제어 | 관리형 서비스에서 허용하는 범위 | 컨트롤 플레인 내부까지 직접 제어 가능 | 관리형 서비스에서 허용하는 범위 |
| 비용 구조 | 클러스터 관리 요금 + 실행 자원 비용 | 도구는 무료. 컨트롤 플레인·워커 인프라와 운영 비용 발생 | 클러스터 관리 요금 + 실행 자원 비용 |
(1) Kubernetes로 이전이 쉬움
- 현재 V2 운영 환경은 ECS Fargate에서 운영되고 있어 Kubernetes의 리소스 구조로 전환하기 용이하다.
| ECS | Kubernetes |
|---|---|
| Task | Pod |
| ECS Service | Deployment, Service |
- 네트워크와 데이터베이스를 새로 구성할 필요 없이 기존 VPC와 RDS를 그대로 사용할 수 있다.
- ECS와 EKS를 동일한 VPC 내에 구성할 수 있어 서비스별 순차적인 이전이 가능하다.
- 예: API Server → EKS
- Chat Server → ECS 유지
- 검증 완료 후 순차 이전
(2) 장애 발생 가능성 감소 및 운영 안정성 확보
kubeadm을 사용하는 경우 API Server, Scheduler, Controller Manager와 etcd를 팀이 직접 운영해야 한다.- Control Plane에 장애가 발생하면 기존 Pod는 계속 실행될 수 있지만, 새로운 Pod의 배포 및 재스케줄링이 중단될 수 있다.
- 이 경우 팀이 애플리케이션 장애와 Kubernetes Control Plane 장애를 함께 분석하고 복구해야 한다.
- EKS는 AWS가 Control Plane을 여러 가용 영역에 구성하고 비정상 인스턴스를 교체하여 Control Plane 운영 및 장애 대응 부담을 줄일 수 있다.
→ Kubernetes Control Plane 자체의 운영보다 애플리케이션과 Worker Node의 안정성에 집중할 수 있다.
3단계 -service,DB, 네트워크
- Kubernetes Architecture Diagram
- 주요 Kubernetes Resource 설계
3-1 DB를 Kubernetes 외부에서 관리
(1) pod로 DB를 띄우지 않는 이유
우리 서비스에는 장애가 발생해도 유지되어야 하는 데이터가 있다.
ex )회원 정보와 프로필,채팅 메시지,추천 결과와 이력,알림 처리 상태
애플리케이션 Pod는 언제든 교체할 수 있지만 사용자 데이터는 RDS에 유지된다. EKS Cluster나 Worker Node에 장애가 발생해도 데이터베이스의 수명주기가 함께 영향을 받지 않는다.
(2) PV로 DB를 띠우지 않는 이유
- EKS는 장애가 나거나 재구축되면 언제든 다시 배포할 수 있는 애플리케이션 환경으로 운영한다. DB가 외부에 있으면 EKS를 재구축한 후 DB의 endpoint만 연결하면 된다. PV의 경우에는 EKS를 재구축할때 EBS에 별도로 저장하고 복구해야하는 관리 포인트가 늘어난다.
- 현재는 RDS가 데이터의 자동 백업, 복구를 관리해주고 있다. PV와 StatefulSet의 경우에는 백업이나 로그 보관하는 경우 추가적인 구성이 필요하다.
3-2. service , 네트워크 구조
어떤 Pod를 선택할지와 어떤 포트로 전달할지 정의하는 네트워크 규칙
[ service 분리기준 ]
- (1) 내부요청,외부요청 - 사용자에게 직접 요청 받는지 여부
- (2) 통신 방식이 다른지 - 일반 api호출 , websocket인지
- (3) pod가 분리되어 있는지. - pod의 역할이 다르면 다른 endpoint에 접근하니까
EKS Cluster
│
├─ 회원
│ │
│ ├─ Service: member-service
│ │ └─ selector ─────────────▶ member-api Pods
│ │
│ ├─ Deployment: member-api
│ │ └─ member-api Pods
│ │ ├─ 로그인·회원가입
│ │ ├─ Access Token 발급
│ │ ├─ 회원 정보 관리
│ │ ├─ 온보딩 요청 처리
│ │ └─ onboarding-ai-api-service 호출
│ │(온보딩 Ai)
│ ├─ Internal Service: onboarding-ai-api-service
│ │ └─ selector ─────────────▶ onboarding-ai-api Pods
│ │
│ └─ Deployment: onboarding-ai-api
│ └─ FastAPI Pods
│ ├─ 온보딩 데이터 전처리
│ ├─ Feature 생성
│ └─ onboarding-model-service 호출
│
├─ 홈,추천, 좋아요
│ │
│ ├─ Service: recommendation-service
│ │ └─ selector ─────────────▶ recommendation-api Pods
│ │
│ └─ Deployment: recommendation-api
│ └─ Spring Pods
│ ├─ 홈화면 조회 -> 차단, 좋아요
│ ├─ 좋아요 -> 알림
│ └─ recommendation-ai-api-service 호출
│
├─ 채팅
(일반채팅)
│ │
│ ├─ Service: chat-websocket-service
│ │ └─ selector ─────────────▶ chat-websocket Pods
│ │
│ └─ Deployment: chat-websocket
│ └─ chat-websocket Pods
│ ├─ 사용자 간 WebSocket 연결
│ ├─ 채팅 메시지 처리
│ └─ Kafka 메세지 브로커 역할
│
(AI채팅)
│
├─ Service: chat-ai-service
│ └─ selector ─────────────▶ chat-ai-api Pods
│
└─ Deployment: chat-ai-api
└─ FastAPI Pods
├─ 페르소나 대화
└─ 연습대화
- 통신 방식 : 채팅 service는 다른 api와 통신 특성이 달라 service분리함.
- 내부 요청 , 외부 요청 :
- BE 의 요청으로만 fastapi(ai)요청이 거치기 때문에 ai와 be는 요청 방식이 다름 + 팀도 달라서 배포 주기도 다르기 때문에 pod를 분리했고 결과적으로 service도 분리됨.
- 배포주기와 비지니스 중요도 → pod 분리 → service분리
- BE와 AI분리 이유 비지니스적 중요도가 다르고 각각 배포 주기도 다름.
- 회원 - 사용자 정보 저장, 인증, 정합성 중요
- 홈 - 조회 트래픽 많고 속도가 중요함.
- 명리학 - 비동기 처리하고 응답시간이 다름. 배포주기도 다
- BE와 AI분리 이유 비지니스적 중요도가 다르고 각각 배포 주기도 다름.
https://news.hada.io/topic?id=30262
네트워크
LB vs Nodeport
: ClusterIP는 클러스터 내부 DNS로는 접근이 불가능함. 외부접근 허용 방법이 필요함. LB와 Nodeport방식이 있음.
- Nodeport :모든 Kubernetes Node의 특정 포트를 외부에 개방(IP,port)
- LB : 클라우드 환경에서 외부 Load Balancer를 생성하고 Service와 연결.
gateway api선택이유 ) 팀의 역할 분리
ingress : LB, TLS , rounting gateway :LB,TLS / HTTPRoute : rounting
인프라 팀: 도메인이나 로드 밸런스, 네트워크, TLS 관리
개발팀 : Service 연결과 같은 라우팅 규칙 관리
Gateway
도메인 ,LB, TLS 관리
플랫폼 팀
│
┌────────────┴────────────┐
▼ ▼
/ws, /api/chats /api/members
HTTPRoute HTTPRoute
채팅팀 회원팀
│ │
▼ ▼
WebSocket/채팅 Service 회원 Service
채팅 서버 회원 서버
플랫폼 팀은 공용 Gateway의 도메인,로드밸런서,TLS를 관리한다.
채팅팀은 /ws와 /api/chats를 WebSocket,채팅 서버로 연결하는 HTTPRoute를 관리하고,
회원팀은 /api/members를 회원 서버로 연결하는 HTTPRoute를 독립적으로 관리한다.
(+)ingress의 기능 부족 : ingress 표준 api는 실제 nginx에서 자주 쓰는 것도 ingress에 없습니다. ( rate limits, request timeout, CORS 등등.) 해당 기능은 별도의 어노테이션에 의존해야 합니다.