90. 서비스 (Service) - K8s 네트워킹의 불변의 간판
⚠️ 이 문서는 쿠버네티스(Kubernetes) 환경에서 파드(Pod)들이 죽고 새로 태어날 때마다 IP 주소가 수시로 바뀌는 극악의 휘발성 문제를 해결하기 위해, **파드들 앞단에 서서 영원히 변하지 않는 단일 고정 IP와 도메인 네임(DNS)을 제공하여 클라이언트의 요청을 파드들에게 안전하게 분산(Load Balancing)시켜 주는 필수 네트워킹 리소스인 '서비스(Service)'**를 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 쿠버네티스의 파드는 언제든 죽을 수 있는 소모품(Cattle)이라서 IP 주소를 믿고 통신하면 안 된다. 서비스는 이 불확실성을 가려주는(Abstraction) 영원불멸의 '논리적인 간판'이다.
- 가치: 프론트엔드 서버가 백엔드 서버를 호출할 때, 백엔드 파드가 3개로 늘어나든(Scale-out) 다 죽고 새로 켜지든 전혀 신경 쓸 필요 없이, 오직
http://backend-service라는 고정된 영문 주소만 찌르면 통신이 완벽하게 알아서 라우팅된다.- 기술 체계: 내부에서만 통신하는 ClusterIP, 외부망으로 살짝 포트를 열어주는 NodePort, 클라우드의 진짜 로드밸런서를 붙여주는 LoadBalancer 등 목적에 따라 3+1가지의 형태로 진화하여 트래픽을 관장한다.
Ⅰ. 파드(Pod) IP의 휘발성과 502 Bad Gateway의 공포
생명주기가 짧은 파드의 IP를 외우는 것은 바보 같은 짓이다.
- 파드 IP의 가변성 (Ephemeral IP):
- 디플로이먼트에 의해 띄워진 파드 A(IP: 10.1.1.2)가 있다.
- 프론트엔드 코드를 짜면서 이 백엔드 API 주소를
10.1.1.2라고 소스에 하드코딩해 두었다. - 어느 날 파드 A가 메모리 초과로 뻗었고, 쿠버네티스는 즉시 똑같은 기능의 새 파드 B(IP: 10.1.1.9)를 띄워 치유(Self-healing)했다.
- 프론트엔드는 여전히 죽어버린
10.1.1.2로 허공에 계속 쿼리를 날리고, 고객은 접속 에러 창을 보게 된다.
- 서비스(Service)의 등장:
- 쿠버네티스는 파드들 앞에 '서비스'라는 추상화된 가상 라우터를 하나 깐다.
- 이 서비스에 고정된 가상 IP(Virtual IP)를 하나 영구적으로 부여하고, 트래픽을 이 서비스가 받아서 살아있는 파드(10.1.1.9)에게 알아서 토스해 주는 우아한 디커플링 구조를 발명했다.
📢 섹션 요약 비유: 파드(Pod)가 수시로 바뀌는 114 콜센터 아르바이트생이라면, 아르바이트생 개인 휴대폰 번호(파드 IP)를 고객에게 알려주면 알바생이 퇴사하는 순간 고객과 연락이 끊깁니다. 그래서 회사 대표번호 1588-0000(서비스 객체)을 하나 만들어 간판에 크게 박아두고, 고객은 대표번호로만 전화하게 하여 출근해 있는 아무 알바생에게나 전화를 돌려주는(로드밸런싱) 원리입니다.
Ⅱ. 서비스의 영혼의 단짝: 라벨 셀렉터 (Label Selector)
서비스는 눈이 없어서 IP 대신 스티커(라벨)를 보고 파드를 찾는다.
- 라벨 기반의 트래픽 라우팅:
- 서비스(Service)의 껍데기 설정(yaml) 파일에는 내가 트래픽을 던져줄 놈들이 누군지
selector: app=backend라고 적어둔다. - 서비스는 1초마다 클러스터를 뒤져서 엉덩이에
app=backend라는 스티커(라벨)가 붙은 파드들의 최신 IP 목록(엔드포인트, Endpoint)을 실시간으로 자기 장부에 업데이트한다. - 방금 새로 태어난 파드라도 스티커만 맞으면 즉시 트래픽을 나눠주고, 스티커를 떼버린 파드는 즉각 장부에서 지워버려 완벽한 로드밸런싱 그룹을 유지한다.
- 서비스(Service)의 껍데기 설정(yaml) 파일에는 내가 트래픽을 던져줄 놈들이 누군지
- CoreDNS와 서비스 디스커버리:
- 쿠버네티스 내부에는 CoreDNS라는 자체 네임 서버가 돌아가고 있다.
- 서비스를 하나 생성하면(예: 이름이
my-db), 이 CoreDNS에my-db.default.svc.cluster.local이라는 긴 도메인이 자동으로 등록된다. 다른 파드들은 이 영문 도메인만 치면 무조건 통신이 성공한다.
📢 섹션 요약 비유: 식당 매니저(서비스)는 요리사(파드)들의 얼굴이나 이름(IP)을 외우지 않습니다. 오직 '빨간색 주방장 모자(라벨)'를 쓴 사람에게만 주문표(트래픽)를 줍니다. 새로 알바생이 오더라도 빨간 모자만 씌워주면 그 순간부터 매니저가 주문을 나눠주기 시작하는, 인간관계 제로의 철저한 규격화된 트래픽 분배 시스템입니다.
Ⅲ. 4가지 서비스 타입 (ClusterIP, NodePort, LoadBalancer, ExternalName)
트래픽을 안에서만 돌릴지, 밖에서 받게 할지에 따라 4단계로 진화한다.
- ClusterIP (기본값 / 사내용):
- 클러스터 내부에서만 통신할 수 있는 가상 IP를 만든다. (외부 인터넷에서는 절대 접속 불가)
- 보안이 생명인 DB(MySQL)나 백엔드 WAS 서버를 감싸는 데 쓴다.
- NodePort (테스트용 / 반자동):
- 외부에서 접속할 수 있도록, 쿠버네티스를 구성하는 **'모든 물리적 서버(Node)'의 특정 포트(예: 30000~32767)**를 활짝 열어둔다. 외부에서 아무 서버 IP에 포트 번호 31234만 치고 들어오면 내부 파드로 연결된다. 포트 번호가 길고 못생겨서 상용 서비스엔 부적합하다.
- LoadBalancer (상용 서비스의 표준):
- AWS나 GCP 같은 클라우드 환경에서만 제대로 돈다. 이것을 띄우면 쿠버네티스가 AWS에 명령을 내려 비싼 진짜 AWS 로드밸런서(ALB/NLB) 기계를 하나 뚝딱 만들어 클러스터 앞단에 붙여준다. 고객은 예쁜 80/443 포트로 완벽하게 접속할 수 있다.
- ExternalName (우회용):
- 파드를 가리키는 게 아니라, 클러스터 밖의 외부 시스템(예: 사내 망의 옛날 오라클 DB 주소
oracle.mycompany.com)을 향해 DNS CNAME 레코드만 쓱 매핑해 주는 껍데기 서비스다. (외부와의 연동 용도)
- 파드를 가리키는 게 아니라, 클러스터 밖의 외부 시스템(예: 사내 망의 옛날 오라클 DB 주소
📢 섹션 요약 비유: ClusterIP는 사옥 안에서 직원들끼리만 쓰는 4자리 내선 전화(보안 철저)입니다. NodePort는 본사 1층 철문에 쥐구멍을 뚫어 밖에서 억지로 팩스를 밀어 넣게 만든(못생기고 불편함) 임시 통로입니다. LoadBalancer는 외부 대로변에 정식으로 예쁜 통유리 고객센터(AWS ALB)를 차려놓고 쾌적하게 손님을 받는 상용화의 끝판왕 모델입니다.