학습 예시 안내: 본문의 상황과 출력은 개념 설명을 위한 예시로 정리했습니다. 당시 실행 여부는 확인되지 않았으며, 현재 환경에서의 클러스터 실습도 별도 검증이 필요합니다.
🎯 학습 목표
이 글을 통해 다음을 학습할 수 있습니다:
- Pod 네트워킹의 한계점과 Service의 필요성
- Service의 종류와 각각의 용도
- ClusterIP, NodePort, LoadBalancer 실습
- 서비스 디스커버리와 DNS 이해
- CKA 준비 과정에서 연습할 Service 관련 문제들
📝 앞선 개념과 이번 예제
지난 글에서는 Deployment로 여러 Pod를 관리하는 방법을 다뤘습니다. 이번에는 클라이언트가 여러 Pod에 접근해야 하는 상황을 가정해 봅니다.
예제에서 가정한 환경
# 지난번에 만든 Deployment 확인
kubectl get deployment nginx-deployment
kubectl get pods -l app=nginx -o wide
출력 형식 예시:
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment-7d4c8f5d6c-abc12 1/1 Running 0 1d 172.17.0.3 minikube
nginx-deployment-7d4c8f5d6c-def34 1/1 Running 0 1d 172.17.0.4 minikube
nginx-deployment-7d4c8f5d6c-ghi56 1/1 Running 0 1d 172.17.0.5 minikube
가정한 문제 상황
각 Pod가 서로 다른 IP를 가지고 있는데, 클라이언트는 어떤 IP로 접근해야 할까요?
# Pod IP로 직접 접근 시도
curl 172.17.0.3
curl 172.17.0.4
curl 172.17.0.5
문제점들:
- 변동되는 IP: Pod가 삭제되고 새 Pod로 대체되면 IP가 바뀔 수 있음 (같은 Pod 안의 컨테이너 재시작과는 구분)
- 어떤 Pod에 접근?: 3개 중 어떤 것을 선택해야 할지 모름
- 로드 밸런싱 부재: 트래픽을 고르게 분산할 수 없음
- 외부 접근 설정 필요: 외부에서 Pod IP로 접근 가능한지는 클러스터 네트워크와 라우팅 구성에 따라 달라짐
Pod마다 다른 IP를 클라이언트가 관리하지 않도록 Service라는 접근점을 사용합니다.
🌐 Service란 무엇인가?
Service의 기본 개념
Service는 Pod들에 대한 안정적인 접근점을 제공하는 추상화 계층입니다.
클라이언트 → Service → Pod들
↓ ↓ ↓
안정된 로드밸런싱 실제 워크로드
접근점 & 디스커버리
Service의 핵심 기능
- 안정적인 IP와 DNS 이름 제공
- 로드 밸런싱 - 여러 Pod 간 트래픽 분산
- 서비스 디스커버리 - 다른 서비스 찾기
- 추상화 - Pod의 생성/삭제와 독립적
🔧 첫 번째 Service 만들기
ClusterIP Service (기본 타입)
기본적인 ClusterIP Service 구성 예제입니다:
# nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80 # Service가 노출할 포트
targetPort: 80 # Pod의 실제 포트
type: ClusterIP # 기본값 (생략 가능)
# Service 생성
kubectl apply -f nginx-service.yaml
# Service 확인
kubectl get service
kubectl get svc # 축약형
출력 형식 예시:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service ClusterIP 10.96.123.45 <none> 80/TCP 30s
Service 동작 확인
# Service IP로 접근 테스트
kubectl run test-pod --image=curlimages/curl -it --rm --command -- sh
# Pod 내부에서 Service 접근
curl nginx-service.default.svc.cluster.local
curl nginx-service # 같은 네임스페이스에서는 간단히
curl 10.96.123.45 # ClusterIP로도 접근 가능
확인할 동작: 여러 요청이 어떤 Pod에 전달되는지 살펴봅니다. 요청마다 반드시 다른 Pod가 선택된다고 가정하지 않습니다.
위의 기본 nginx 응답은 Pod마다 같을 수 있습니다. 분산 여부를 재현하려면 각 Pod의 접근 로그나 응답에 포함한 Pod 이름을 함께 확인해야 합니다.
📋 Service 종류별 상세 학습
1. ClusterIP (기본 타입)
용도: 클러스터 내부에서만 접근 가능한 서비스
# clusterip-service.yaml
apiVersion: v1
kind: Service
metadata:
name: internal-service
spec:
selector:
app: nginx
ports:
- port: 8080 # Service 포트
targetPort: 80 # Container 포트
type: ClusterIP
특징:
- 클러스터 내부에서만 접근 가능
- 마이크로서비스 간 통신에 주로 사용
- 기본 타입이므로 type 생략 가능
2. NodePort
용도: 클러스터 외부에서 Node의 특정 포트로 접근
# nodeport-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport
spec:
selector:
app: nginx
ports:
- port: 80 # Service 포트
targetPort: 80 # Container 포트
nodePort: 30080 # Node 포트 (30000-32767 범위)
type: NodePort
# NodePort Service 생성
kubectl apply -f nodeport-service.yaml
# Service 확인
kubectl get svc nginx-nodeport
출력 형식 예시:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-nodeport NodePort 10.96.234.56 <none> 80:30080/TCP 1m
접근 방법:
# minikube에서 Node IP 확인
minikube ip
# 브라우저나 curl로 접근
curl http://192.168.49.2:30080
3. LoadBalancer
용도: 클라우드 환경에서 외부 로드 밸런서 프로비저닝
# loadbalancer-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: LoadBalancer
# LoadBalancer Service 생성
kubectl apply -f loadbalancer-service.yaml
# Service 확인 (로컬 환경에서는 EXTERNAL-IP가 <pending>)
kubectl get svc nginx-loadbalancer
로컬 환경에서 테스트:
# minikube에서 LoadBalancer 시뮬레이션
minikube tunnel # 별도 터미널에서 실행
# 이제 EXTERNAL-IP가 할당됨
kubectl get svc nginx-loadbalancer
🎯 Service와 Pod 연결 이해하기
레이블 셀렉터 동작 원리
Service가 어떤 Pod를 대상으로 삼는지 확인하는 방법입니다:
# Pod의 레이블 확인
kubectl get pods --show-labels
# Service의 셀렉터 확인
kubectl describe service nginx-service
주의할 점: Service의
selector.app: nginx
와 Pod의
labels.app: nginx
가 일치해야 연결됩니다!
Endpoints 확인
2026-09-29 보완: 아래는 기존 Endpoints 조회 예제입니다. Endpoints API는 Kubernetes 1.33부터 사용 중단 예정(deprecated) 상태이며, 새 확인에는
kubectl get endpointslices -l kubernetes.io/service-name=nginx-service -o yaml을 사용합니다. 공식 안내
# Service가 어떤 Pod들을 타겟으로 하는지 확인
kubectl get endpoints nginx-service
# 상세 정보
kubectl describe endpoints nginx-service
출력 형식 예시:
NAME ENDPOINTS AGE
nginx-service 172.17.0.3:80,172.17.0.4:80,172.17.0.5:80 5m
위 출력 예시에는 세 Pod의 IP가 표시되어 있습니다. 엔드포인트 목록에 포함됐다는 사실과 실제 요청이 분산됐다는 사실은 구분해서 확인해야 합니다.
🔍 서비스 디스커버리와 DNS
Kubernetes DNS 이해하기
Kubernetes는 자동으로 DNS 레코드를 생성합니다:
# DNS 테스트 Pod 생성
kubectl run dns-test --image=busybox -it --rm -- sh
# Pod 내부에서 DNS 확인
nslookup nginx-service
nslookup nginx-service.default.svc.cluster.local
DNS 패턴:
<service-name>.<namespace>.svc.cluster.local
환경변수를 통한 서비스 디스커버리
# 새 Pod에서 환경변수 확인
kubectl run env-test --image=busybox -it --rm -- env | grep NGINX_SERVICE
# 결과 예시
NGINX_SERVICE_SERVICE_HOST=10.96.123.45
NGINX_SERVICE_SERVICE_PORT=80
💡 고급 Service 설정
다중 포트 Service
# multi-port-service.yaml
apiVersion: v1
kind: Service
metadata:
name: multi-port-service
spec:
selector:
app: web-app
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8443
type: ClusterIP
세션 어피니티 설정
# session-affinity-service.yaml
apiVersion: v1
kind: Service
metadata:
name: sticky-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
sessionAffinity: ClientIP # 같은 클라이언트는 같은 Pod로
ExternalName Service
# external-service.yaml
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: database.example.com
이 타입은 외부 서비스에 대한 DNS 별칭을 만들어 줍니다.
🚨 문제 해결과 디버깅
Service가 작동하지 않을 때
1. Endpoints 확인
# Endpoints가 비어있는 경우
kubectl get endpoints my-service
# 비어있다면 셀렉터·대상 Pod 존재 여부·Ready 상태를 확인
kubectl describe service my-service
kubectl get pods --show-labels
2. 네트워크 정책 확인
# Pod 간 통신 테스트
kubectl exec -it test-pod -- wget -qO- nginx-service
3. 포트 설정 확인
# Service와 Pod의 포트 매핑 확인
kubectl describe service my-service
kubectl describe pod <pod-name>
자주 하는 실수들
1. 셀렉터 불일치
# ❌ 잘못된 예
Service selector: app=web
Pod labels: app=nginx
# ✅ 올바른 예
Service selector: app=nginx
Pod labels: app=nginx
2. 포트 매핑 실수
# ❌ 잘못된 예
ports:
- port: 80
targetPort: 8080 # Pod는 실제로 80포트 사용
---
# ✅ 올바른 예
ports:
- port: 80
targetPort: 80
🎯 실전 예제: 3-tier 애플리케이션
앞의 개념을 연결하기 위한 가상의 애플리케이션 구성 예제입니다.
Frontend Service (LoadBalancer)
# frontend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
tier: frontend
ports:
- port: 80
targetPort: 3000
type: LoadBalancer
Backend Service (ClusterIP)
# backend-service.yaml
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
tier: backend
ports:
- port: 8080
targetPort: 8080
type: ClusterIP
Database Service (ClusterIP)
# database-service.yaml
apiVersion: v1
kind: Service
metadata:
name: database-service
spec:
selector:
tier: database
ports:
- port: 5432
targetPort: 5432
type: ClusterIP
네트워크 흐름:
외부 클라이언트 → Frontend Service (LoadBalancer)
↓
Frontend Pods → Backend Service (ClusterIP)
↓
Backend Pods → Database Service (ClusterIP)
↓
Database Pods
📊 CKA 대비 연습 패턴
연습할 문제 유형
1. Service 생성과 노출
# 문제: 기존 Deployment를 ClusterIP로 노출
kubectl expose deployment nginx-deployment --port=80 --target-port=80
# 문제: NodePort로 노출
kubectl expose deployment nginx-deployment --type=NodePort --port=80
2. Service와 Pod 매핑 확인
# 문제: Service가 어떤 Pod를 타겟으로 하는지 확인
kubectl get endpoints <service-name>
kubectl describe service <service-name>
3. 서비스 디스커버리 테스트
# 문제: Pod에서 다른 서비스에 접근 가능한지 확인
kubectl exec -it <pod-name> -- nslookup <service-name>
kubectl exec -it <pod-name> -- curl <service-name>
4. 문제 해결
- Service가 Pod와 연결되지 않는 이유 찾기
- 외부에서 서비스에 접근할 수 없는 문제 해결
시간 단축 명령어
# 빠른 Service 생성
kubectl expose deployment <name> --port=80 --target-port=80
kubectl expose deployment <name> --type=NodePort --port=80
# Service 정보 빠른 확인
kubectl get svc -o wide
kubectl describe svc <name>
# 서비스 테스트
kubectl run test --image=curlimages/curl -it --rm --command -- curl <service-name>
📚 Service 타입별 정리
Service 타입 비교표
| 타입 | 접근 범위 | 사용 사례 | EXTERNAL-IP |
|---|---|---|---|
| ClusterIP | 클러스터 내부 | 마이크로서비스 간 통신 | None |
| NodePort | 클러스터 외부 | 개발/테스트 환경 | None |
| LoadBalancer | 클러스터 외부 | 운영 환경 (클라우드) | 할당됨 |
| ExternalName | DNS 별칭 | 외부 서비스 연동 | 설정한 FQDN |
포트 설정 이해
ports:
- port: 80 # Service에서 노출하는 포트
targetPort: 8080 # Pod의 실제 포트
nodePort: 30080 # Node에서 노출하는 포트 (NodePort만)
필수 명령어 정리
# Service 관리
kubectl expose deployment <name> --port=<port>
kubectl get services # 또는 kubectl get svc
kubectl describe service <name>
kubectl delete service <name>
# 연결 확인
kubectl get endpoints <name>
kubectl describe endpoints <name>
# 네트워크 테스트
kubectl exec -it <pod> -- curl <service>
kubectl exec -it <pod> -- nslookup <service>
🚀 다음 학습 계획
Service 다음에는 애플리케이션의 설정을 관리하는 ConfigMap과 Secret을 살펴볼 계획입니다.
다음 주제들
- ConfigMap과 Secret으로 설정 관리 - 환경별 설정 분리
- Pod 리소스 제한과 요청 설정 - 리소스 최적화
- Liveness와 Readiness Probe 구성 - 헬스체크
- Ingress를 통한 외부 트래픽 관리 - 고급 라우팅
- 네임스페이스를 통한 리소스 격리
개인 학습 목표
- 복잡한 네트워크 구조에서의 서비스 디스커버리 이해
- 다양한 Service 타입의 적절한 활용
- 네트워크 문제 발생 시 빠른 진단 능력 향상
Service는 Pod 교체와 클라이언트의 접근 경로를 분리하는 역할을 합니다. 실습할 때는 대상 Pod 선택, 엔드포인트 등록, 실제 요청 전달을 나누어 확인하는 것이 핵심입니다.
다음 글에서는 컨테이너의 설정 데이터를 분리하는 ConfigMap과 Secret을 다룹니다.
🔗 참고 자료:
yellow.log · 2025.08.02에 작성 · 2026.09.29에 수정
CKA 준비 전체 8편
- 1.Pod 생성과 관리 - 쿠버네티스의 기본 단위 이해하기
- 2.ReplicaSet과 Deployment로 Pod 관리하기 - 확장성과 가용성 확보
- 3.Service를 통한 Pod 네트워킹 - 안정적인 접근 경로 만들기읽는 중
- 4.ConfigMap과 Secret으로 설정 관리하기 - 환경별 설정 분리
- 5.Pod 리소스 제한과 요청 설정 - 안정적인 클러스터 운영을 위한 리소스 관리
- 6.Liveness와 Readiness Probe 구성 - 헬스체크와 자동 복구
- 7.네임스페이스를 통한 리소스 격리와 다중 테넌시 - 팀별, 환경별 격리
- 8.Ingress를 통한 외부 트래픽 관리와 라우팅 - 클러스터의 똑똑한 관문 구축