Kubernetes Service와 ClusterIP, NodePort, LoadBalancer 동작 원리
Kubernetes Service와 ClusterIP, NodePort, LoadBalancer 동작 원리
1. Kubernetes Service란 무엇인가?
Kubernetes에서 애플리케이션은 일반적으로 Pod 단위로 실행됩니다.
예를 들어 웹 서비스를 운영한다고 가정하겠습니다.
Kubernetes Cluster
|
+-------+-------+
| |
v v
+-------+ +-------+
| Pod A | | Pod B |
| API | | API |
+-------+ +-------+
10.10.1.2 10.10.2.3
Pod A와 Pod B는 각각 다른 IP 주소를 사용합니다.
그런데 Pod A가 장애로 삭제되고 새로운 Pod가 생성되면 IP 주소가 변경될 수 있습니다.
이때 다른 애플리케이션에서 Pod IP를 직접 참조하고 있다면 연결 설정을 변경해야 하는 문제가 발생합니다.
Kubernetes Service는 이러한 문제를 해결하기 위해 만들어졌습니다.
Service는 여러 Pod를 하나의 안정적인 네트워크 접근 지점으로 묶어주는 리소스입니다.
Client
|
v
+----------------+
| Kubernetes |
| Service |
| 10.96.10.100 |
+----------------+
|
+-----+-----+
| |
v v
+------+ +------+
| Pod A| | Pod B|
+------+ +------+
10.10.1.2 10.10.2.3
클라이언트는 Pod IP가 아니라 Service를 통해 애플리케이션에 접근합니다.
Pod가 재생성되어 IP가 변경되더라도 Service는 선택된 Pod 목록을 갱신하여 안정적인 접근 지점을 제공합니다.
2. Kubernetes Service의 기본 동작 원리
Service는 일반적으로 Label Selector를 사용하여 대상 Pod를 선택합니다.
예를 들어 다음과 같은 Pod가 있다고 가정하겠습니다.
apiVersion: v1
kind: Pod
metadata:
name: api-pod-01
labels:
app: api
spec:
containers:
- name: api
image: nginx:alpine
ports:
- containerPort: 80
여기서 중요한 설정은 다음 부분입니다.
labels: app: api
Service에서 app: api라는 Label을 지정하면 해당 Label을 가진 Pod가 Service의 대상이 됩니다.
Service 구성 예시:
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
ports:
- port: 80
targetPort: 80
type: ClusterIP
각 설정의 의미는 다음과 같습니다.
항목설명selector연결할 Pod를 선택portService가 제공하는 포트targetPort실제 Pod 컨테이너의 목적지 포트typeService 접근 방식
Service는 선택된 Pod의 정보를 EndpointSlice로 관리합니다.
EndpointSlice는 Service가 트래픽을 전달할 대상 Endpoint를 관리하는 Kubernetes 리소스입니다.
확인 명령어:
kubectl get endpointslices
상세 정보:
kubectl describe endpointslice
Service와 Pod의 연결 상태를 이해하려면 Service뿐 아니라 EndpointSlice도 함께 확인해야 합니다.
3. ClusterIP — 클러스터 내부 통신
ClusterIP는 Kubernetes Service의 기본 유형입니다.
클러스터 내부에서 다른 Pod나 애플리케이션이 Service에 접근할 수 있도록 가상 IP를 제공합니다.
Kubernetes Cluster
|
+-----------+
| ClusterIP |
| 10.96.1.10|
+-----------+
|
+-----+-----+
| |
v v
+------+ +------+
| Pod A| | Pod B|
+------+ +------+
ClusterIP는 일반적으로 외부 네트워크에서 직접 접근할 수 없습니다.
3-1. ClusterIP YAML 작성
파일 생성:
vi clusterip.yaml
내용:
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: ClusterIP
selector:
app: web
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
적용:
kubectl apply -f clusterip.yaml
확인:
kubectl get svc
예시:
NAME TYPE CLUSTER-IP PORT(S) web-service ClusterIP 10.96.1.10 80/TCP
이제 클러스터 내부에서 다음 주소로 접근할 수 있습니다.
http://10.96.1.10
같은 Namespace에서는 Service 이름으로도 접근할 수 있습니다.
http://web-service
다른 Namespace에서는 일반적으로 다음과 같은 DNS 이름을 사용합니다.
web-service.default.svc.cluster.local
3-2. ClusterIP 통신 실습
테스트용 Pod를 생성합니다.
kubectl run test-client \ --image=busybox:1.36 \ --restart=Never \ --command -- sleep 3600
Service 연결 테스트:
kubectl exec test-client -- \ wget -qO- http://web-service
정상적으로 통신된다면 Nginx 기본 페이지의 HTML이 출력됩니다.
여기서 확인할 내용은 클라이언트가 Pod IP를 직접 지정하지 않았다는 점입니다.
Service 이름을 이용하여 내부 DNS를 통해 접근했습니다.
4. NodePort — Worker Node를 통한 외부 접근
NodePort는 Kubernetes Worker Node의 특정 포트를 열어 외부에서 Service에 접근할 수 있도록 합니다.
기본적인 NodePort 범위는 다음과 같습니다.
30000 ~ 32767
실제 범위는 Kubernetes API Server 설정에 따라 변경될 수 있습니다.
구조는 다음과 같습니다.
External Client
|
| Node IP:30080
v
+------------------+
| Worker Node 1 |
| NodePort :30080 |
+------------------+
|
v
+------------------+
| ClusterIP |
| web-service |
+------------------+
|
+---+---+
| |
v v
Pod A Pod B
NodePort는 특정 Worker Node의 IP와 포트를 통해 접근할 수 있습니다.
4-1. NodePort YAML 작성
vi nodeport.yaml
내용:
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
spec:
type: NodePort
selector:
app: web
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
적용:
kubectl apply -f nodeport.yaml
확인:
kubectl get svc
예시:
NAME TYPE CLUSTER-IP PORT(S) web-nodeport NodePort 10.96.2.10 80:30080/TCP
외부에서 다음 주소로 접근할 수 있습니다.
http://WorkerNode-IP:30080
4-2. NodePort 동작 특징
NodePort는 기본적으로 모든 적절한 Worker Node에서 동일한 NodePort를 통해 Service에 접근할 수 있도록 구성됩니다.
예를 들어 Worker Node가 세 대라면 다음과 같이 접근할 수 있습니다.
http://192.168.66.10:30080 http://192.168.66.11:30080 http://192.168.66.12:30080
단, 실제 접근 가능 여부는 노드 방화벽, 네트워크 경로, kube-proxy 또는 대체 데이터 경로, Service 설정에 따라 달라집니다.
5. LoadBalancer — 외부 로드밸런서 연결
LoadBalancer는 외부 로드밸런서를 통해 Kubernetes Service에 접근하는 방식입니다.
일반적으로 클라우드 환경에서는 클라우드 제공자의 Load Balancer와 연동됩니다.
External User
|
v
+---------------+
| Load Balancer |
| External IP |
+---------------+
|
v
+---------------+
| Kubernetes |
| Service |
+---------------+
|
+----+----+
| |
v v
Pod A Pod B
예를 들어 AWS, Azure, GCP 등에서는 해당 클라우드의 로드밸런서와 연동할 수 있습니다.
온프레미스 환경에서는 MetalLB와 같은 솔루션을 이용해 LoadBalancer 유형의 Service에 외부 IP를 제공할 수 있습니다.
중요한 점은 Kubernetes 자체가 모든 환경에서 외부 로드밸런서를 자동으로 만들어 주는 것은 아니라는 것입니다.
실제 외부 IP 할당과 트래픽 전달은 클라우드 컨트롤러 또는 별도 로드밸런서 구현이 필요합니다.
5-1. LoadBalancer YAML 작성
vi loadbalancer.yaml
내용:
apiVersion: v1
kind: Service
metadata:
name: web-lb
spec:
type: LoadBalancer
selector:
app: web
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
적용:
kubectl apply -f loadbalancer.yaml
확인:
kubectl get svc
클라우드 또는 LoadBalancer 구현이 정상적으로 연동되었다면 EXTERNAL-IP에 외부 IP가 표시됩니다.
NAME TYPE CLUSTER-IP EXTERNAL-IP web-lb LoadBalancer 10.96.3.10 203.0.113.10
외부 접근:
http://203.0.113.10
외부 IP가 <pending>으로 표시된다면 LoadBalancer를 제공하는 환경이 구성되어 있는지 확인해야 합니다.
6. ClusterIP, NodePort, LoadBalancer 비교
세 가지 Service 유형의 차이를 정리하겠습니다.
구분ClusterIPNodePortLoadBalancer접근 범위클러스터 내부노드 IP를 통한 외부 접근외부 로드밸런서기본 포트Service 포트NodePort 범위외부 서비스 포트외부 IP기본 제공 안 함노드 IP 사용환경에 따라 할당주요 용도내부 서비스 통신테스트 및 제한적 외부 접근외부 서비스 제공
운영 환경에서는 일반적으로 다음과 같이 구성할 수 있습니다.
- 내부 API: ClusterIP
- 개발 및 테스트 서비스: NodePort
- 외부 공개 서비스: LoadBalancer 또는 Ingress
단, 실제 아키텍처는 네트워크 환경과 보안 요구사항에 따라 결정해야 합니다.
7. kube-proxy와 Service 트래픽 처리
Kubernetes Service는 일반적인 서버 프로세스처럼 가상 IP에서 직접 Listen하는 방식이 아닙니다.
대표적인 구현 방식에서는 kube-proxy가 Service와 Endpoint 정보를 바탕으로 노드의 네트워크 규칙을 관리합니다.
대표적인 데이터 처리 방식은 다음과 같습니다.
- iptables
- IPVS
또한 Cilium과 같은 솔루션은 eBPF를 이용해 kube-proxy의 기능을 대체할 수 있습니다.
7-1. iptables 방식
iptables 기반 환경에서는 Service IP로 들어온 패킷을 실제 Pod IP로 전달하도록 NAT 규칙을 구성합니다.
Client | v ClusterIP 10.96.1.10 | v iptables NAT | +-----------+ | | v v Pod A Pod B 10.10.1.2 10.10.2.3
확인:
iptables -t nat -L -n
Kubernetes 관련 규칙만 확인하려면:
iptables-save | grep KUBE-
iptables 기반 구성이 아닌 환경에서는 해당 규칙이 없을 수 있습니다.
7-2. IPVS 방식
IPVS는 Linux 커널의 IP Virtual Server 기능을 이용해 로드밸런싱을 수행합니다.
확인:
ipvsadm -Ln
출력 예시:
TCP 10.96.1.10:80 rr -> 10.10.1.2:80 -> 10.10.2.3:80
여기서 rr은 Round Robin 방식입니다.
실제 스케줄링 방식은 설정에 따라 달라질 수 있습니다.
7-3. kube-proxy 상태 확인
kubectl get pods -n kube-system -o wide
kube-proxy가 DaemonSet으로 실행되는 환경이라면 다음과 같이 확인할 수 있습니다.
kubectl get daemonset -n kube-system kube-proxy
로그 확인:
kubectl logs -n kube-system \ -l k8s-app=kube-proxy \ --tail=100
CNI가 kube-proxy 대체 기능을 사용하는 환경에서는 kube-proxy가 설치되어 있지 않을 수도 있습니다.
8. EndpointSlice와 Service 연결 관계
Service가 정상적으로 생성되었다고 해서 실제 애플리케이션까지 연결된다는 의미는 아닙니다.
Service가 선택한 Pod가 존재해야 하고, 해당 Pod가 실제 트래픽을 처리할 준비가 되어 있어야 합니다.
이때 중요한 리소스가 EndpointSlice입니다.
확인:
kubectl get endpointslices
특정 Service의 EndpointSlice 확인:
kubectl get endpointslices \ -l kubernetes.io/service-name=web-service
상세 확인:
kubectl describe endpointslice \ -l kubernetes.io/service-name=web-service
예시:
ENDPOINTS 10.10.1.2:80 10.10.2.3:80
EndpointSlice에 대상 Pod가 등록되지 않았다면 다음을 확인합니다.
- Service의 selector
- Pod의 Label
- Pod의 Ready 상태
- Service의 targetPort
- Pod의 실제 컨테이너 포트
예를 들어 Service는 다음과 같이 설정되어 있는데,
selector: app: web
Pod의 Label이 다음과 같다면 연결되지 않습니다.
labels: app: nginx
Label이 일치하지 않기 때문입니다.
9. Service DNS 동작 원리
Kubernetes에서는 Service 이름을 통해 내부 통신을 수행할 수 있습니다.
이 기능은 CoreDNS가 담당합니다.
예를 들어 다음 Service가 있다고 가정하겠습니다.
Service Name: web-service Namespace: default
같은 Namespace에서는 다음 주소를 사용할 수 있습니다.
web-service
다른 Namespace에서는 다음과 같이 사용할 수 있습니다.
web-service.default
전체 DNS 이름은 다음과 같습니다.
web-service.default.svc.cluster.local
DNS 확인:
kubectl exec test-client -- \ nslookup web-service
전체 도메인 확인:
kubectl exec test-client -- \ nslookup web-service.default.svc.cluster.local
DNS 장애가 발생하면 CoreDNS Pod 상태와 로그를 확인합니다.
kubectl get pods -n kube-system kubectl logs -n kube-system \ -l k8s-app=kube-dns
10. 실전 장애 분석
이제 실제 운영 환경에서 발생할 수 있는 Service 장애를 분석하겠습니다.
장애 1. Service IP로 접속되지 않는 경우
증상:
Connection timed out
확인 순서:
kubectl get svc kubectl describe svc web-service kubectl get endpointslices \ -l kubernetes.io/service-name=web-service
확인 항목:
- Service가 정상 생성되었는가?
- ClusterIP가 할당되었는가?
- Selector가 Pod Label과 일치하는가?
- EndpointSlice에 대상 Pod가 등록되었는가?
- Pod가 Ready 상태인가?
장애 2. NodePort로 접속되지 않는 경우
증상:
http://192.168.66.10:30080 Connection refused
확인:
kubectl get svc kubectl get nodes -o wide
노드에서 포트 확인:
ss -lntp | grep 30080
여기서 주의할 점이 있습니다.
NodePort는 구현 방식에 따라 실제 사용자 공간 프로세스가 포트를 Listen하지 않을 수 있습니다.
따라서 ss에서 포트가 보이지 않는다는 이유만으로 NodePort 장애라고 판단하면 안 됩니다.
다음 항목을 함께 확인해야 합니다.
- 노드 방화벽
- kube-proxy 또는 대체 데이터 경로
- NodePort 설정
- EndpointSlice
- Pod의 애플리케이션 상태
- 노드 간 네트워크 연결
장애 3. Service는 정상인데 Endpoint가 없는 경우
확인:
kubectl get pods --show-labels kubectl describe svc web-service
예를 들어 Service가 다음과 같이 설정되어 있다면,
selector: app: web
Pod에도 동일한 Label이 있어야 합니다.
labels: app: web
또한 Pod가 Ready 상태가 아니면 일반적인 Service 트래픽 대상에서 제외될 수 있습니다.
장애 4. ClusterIP 접속은 되지만 DNS 이름으로 접속되지 않는 경우
확인:
kubectl exec test-client -- \ nslookup web-service
CoreDNS 확인:
kubectl get deployment -n kube-system coredns kubectl get svc -n kube-system kubectl logs -n kube-system \ -l k8s-app=kube-dns
DNS 설정, CoreDNS 상태, NetworkPolicy 등을 확인합니다.
장애 5. LoadBalancer EXTERNAL-IP가 Pending인 경우
확인:
kubectl get svc kubectl describe svc web-lb
주요 원인:
- 클라우드 Load Balancer 연동 미구성
- 클라우드 컨트롤러 오류
- 온프레미스 MetalLB 미설치
- MetalLB IP Pool 설정 오류
- 외부 IP 할당 가능한 주소 부족
온프레미스 환경이라면 LoadBalancer 구현체의 상태와 IP Pool 설정을 별도로 확인해야 합니다.
11. 운영 환경에서 권장하는 점검 순서
Kubernetes Service 장애가 발생하면 다음 순서로 점검하면 효율적입니다.
1. Service 상태
|
v
2. Service IP와 Port 확인
|
v
3. Selector와 Pod Label 확인
|
v
4. EndpointSlice 확인
|
v
5. Pod Ready 상태 확인
|
v
6. Pod 내부 애플리케이션 확인
|
v
7. kube-proxy 또는 CNI 데이터 경로 확인
|
v
8. Node Firewall 및 물리 네트워크 확인
핵심은 Service 자체의 문제인지, 실제 Pod의 문제인지 구분하는 것입니다.
Service IP가 존재하더라도 EndpointSlice에 대상 Pod가 없다면 애플리케이션으로 트래픽이 전달되지 않습니다.
12. 시스템 엔지니어가 기억해야 할 핵심 명령어
명령어용도kubectl get svc -A전체 Service 확인kubectl describe svcService 상세 정보kubectl get endpointslicesEndpointSlice 확인kubectl get pods -o widePod IP 및 노드 확인kubectl get pods --show-labelsPod Label 확인kubectl get nodes -o wide노드 IP 확인kubectl get daemonset -n kube-system네트워크 관련 DaemonSet 확인iptables-saveiptables 규칙 확인ipvsadm -LnIPVS 상태 확인ss -lntpTCP 리스닝 상태 확인tcpdump -ni any패킷 분석
13. 마무리
이번 편에서는 Kubernetes Service의 기본 구조와 세 가지 주요 유형을 살펴봤습니다.
핵심 내용은 다음과 같습니다.
- Service는 변경될 수 있는 Pod IP를 대신하는 안정적인 접근 지점이다.
- ClusterIP는 클러스터 내부 통신에 사용한다.
- NodePort는 Worker Node의 특정 포트를 통해 접근한다.
- LoadBalancer는 외부 로드밸런서와 연동해 서비스를 공개한다.
- Selector와 Pod Label이 일치해야 Endpoint가 생성된다.
- EndpointSlice는 실제 트래픽 대상 Pod 정보를 관리한다.
- kube-proxy 또는 대체 데이터 경로가 Service 트래픽 전달을 처리한다.
- CoreDNS는 Service 이름을 이용한 내부 DNS 조회를 제공한다.
시스템 엔지니어는 Service가 생성되었다는 사실만으로 네트워크가 정상이라고 판단해서는 안 됩니다.
Service IP, Selector, EndpointSlice, Pod 상태, 실제 애플리케이션 포트를 함께 확인해야 합니다.
다음 편에서는 Kubernetes에서 외부 사용자가 내부 서비스에 접근하도록 구성하는 Ingress와 Ingress Controller를 알아보겠습니다.
다음 편: 시스템 엔지니어 실전 교육 26편 — Kubernetes Ingress와 Ingress Controller, HTTP/HTTPS 라우팅 및 TLS 구성
실습용 Pod 배포 단계를 먼저 추가해줘Service 포트 세 가지를 명확히 구분해줘
댓글
아직 댓글이 없습니다.
로그인 후 댓글을 남길 수 있습니다.