
Kubernetes에서 Service를 만들면 Pod에 직접 접근하지 않고 Service를 통해 접근하게 된다. 이때 Service 뒤에 Pod가 여러 개 붙어 있다면, 요청은 여러 Pod 중 하나로 전달된다. 이번 실습에서는 ClusterIP 타입의 Service가 실제로 여러 nginx Pod에 트래픽을 나눠 보내는지 확인해봤다.
먼저 nginx Deployment가 있고, 그 Deployment가 nginx Pod 3개를 띄우고 있다고 가정한다.
kubectl get pod
예를 들면 이런 식으로 nginx Pod 3개가 떠 있다.
nginx-deployment-7456645bf-4rts6
nginx-deployment-7456645bf-kg1gv
nginx-deployment-7456645bf-lgzv5
그리고 이 Pod들을 바라보는 ClusterIP Service를 하나 만든다.
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
여기서 중요한 부분은 selector다.
selector:
app: nginx
이 Service는 app: nginx 라벨을 가진 Pod들을 찾아서 연결한다. 즉, nginx Pod 3개가 모두 app: nginx 라벨을 가지고 있다면, Service는 그 3개의 Pod를 대상으로 트래픽을 전달할 수 있다.
Service YAML 파일을 적용한다.
kubectl apply -f clusterip-svc.yaml
그리고 Service를 확인한다.
kubectl get svc
예를 들어 다음과 같이 나온다.
NAME TYPE CLUSTER-IP PORT(S)
nginx-svc ClusterIP 10.43.188.207 80/TCP
여기서 10.43.188.207이 Service의 ClusterIP다.
ClusterIP는 클러스터 내부에서만 접근 가능한 IP다. 그래서 내 로컬 PC 브라우저에서 바로 접근하는 용도가 아니라, 클러스터 내부의 Pod나 Node에서 접근하는 용도로 사용한다.
nginx는 기본적으로 /usr/share/nginx/html/index.html 파일을 응답한다.
즉, nginx에 접속했을 때 보이는 화면은 이 파일의 내용이다.
그래서 각 Pod의 index.html 내용을 다르게 바꿔두면, Service가 어느 Pod로 요청을 보냈는지 확인할 수 있다.
예를 들어:
Pod 1 → nginx-1 응답
Pod 2 → nginx-2 응답
Pod 3 → nginx-3 응답
이렇게 만들어두면, Service로 여러 번 요청했을 때 응답이 바뀌는지 확인할 수 있다.
먼저 nginx Pod 이름을 확인한다.
kubectl get pod
그다음 각 Pod에 하나씩 들어가서 index.html 내용을 바꾼다.
첫 번째 Pod:
kubectl exec -it nginx-deployment-7456645bf-4rts6 -- bash
Pod 안에서:
echo nginx-1 > /usr/share/nginx/html/index.html
exit
두 번째 Pod:
kubectl exec -it nginx-deployment-7456645bf-kg1gv -- bash
Pod 안에서:
echo nginx-2 > /usr/share/nginx/html/index.html
exit
세 번째 Pod:
kubectl exec -it nginx-deployment-7456645bf-lgzv5 -- bash
Pod 안에서:
echo nginx-3 > /usr/share/nginx/html/index.html
exit
주의할 점은 같은 Pod 안에서 아래 명령을 연속으로 치면 안 된다는 것이다.
echo nginx-1 > /usr/share/nginx/html/index.html
echo nginx-2 > /usr/share/nginx/html/index.html
echo nginx-3 > /usr/share/nginx/html/index.html
이렇게 하면 같은 파일을 계속 덮어쓰기 때문에 마지막 값인 nginx-3만 남는다.
의도는 Pod 3개에 각각 다른 값을 넣는 것이다.
Pod 1에는 nginx-1
Pod 2에는 nginx-2
Pod 3에는 nginx-3
ClusterIP는 클러스터 내부 전용 IP다. 그래서 로컬 PC에서 바로 접근하지 않고, 클러스터 내부에 테스트용 Pod를 하나 띄워서 접근한다.
사용한 명령어는 다음과 같다.
kubectl run curl-test --image=curlimages/curl -it --rm -- sh
이 명령어는 현재 kubectl이 바라보고 있는 클러스터 안에 curl-test라는 임시 Pod를 만든다.
옵션을 나눠보면 다음과 같다.
kubectl run curl-test
→ curl-test라는 이름의 Pod 생성
--image=curlimages/curl
→ curl이 설치된 컨테이너 이미지 사용
-it
→ 터미널로 직접 들어가기
--rm
→ shell에서 나오면 Pod 자동 삭제
-- sh
→ 컨테이너 안에서 sh 실행
즉, 내 로컬 PC에 curl을 설치하는 것이 아니라 Kubernetes 클러스터 내부에 curl이 설치된 테스트용 Pod를 임시로 띄우는 것이다.
kubectl run으로 생성되는 Pod는 현재 kubectl이 바라보고 있는 클러스터에 생성된다.
현재 context는 다음 명령어로 확인할 수 있다.
kubectl config get-contexts
출력 예시는 다음과 같다.
CURRENT NAME
* k3d-my-cluster
여기서 *가 붙어 있는 context가 현재 사용 중인 클러스터다.
따라서 이 상태에서 실행한:
kubectl run curl-test --image=curlimages/curl -it --rm -- sh
명령은 k3d-my-cluster 안에 curl-test Pod를 생성한다.
K9s에서도 curl-test Pod가 생성된 것을 확인할 수 있다.
default curl-test
이제 curl-test Pod 안에서 ClusterIP로 요청을 보낸다.
curl http://10.43.188.207
한 번만 보내지 말고 여러 번 보내본다.
curl http://10.43.188.207
curl http://10.43.188.207
curl http://10.43.188.207
실제로 다음과 같이 응답이 달라졌다.
nginx-2
nginx-1
nginx-3
이 결과가 의미하는 것은 Service가 하나의 Pod에만 요청을 보내는 것이 아니라, 뒤에 연결된 여러 nginx Pod로 요청을 나눠 보내고 있다는 것이다.
현재 구조를 그림으로 보면 다음과 같다.
curl-test Pod
|
| curl http://10.43.188.207
v
nginx-svc Service
ClusterIP: 10.43.188.207
|
+-------------------+-------------------+
| | |
v v v
nginx Pod 1 nginx Pod 2 nginx Pod 3
nginx-1 nginx-2 nginx-3
사용자는 Service IP 하나로 요청을 보낸다.
10.43.188.207
하지만 실제 요청은 Service 뒤에 있는 여러 Pod 중 하나로 전달된다.
그래서 응답이 다음처럼 바뀔 수 있다.
nginx-1
nginx-2
nginx-3
ClusterIP는 외부 공개용 Service는 아니다. 하지만 클러스터 내부에서는 Service 역할을 한다.
즉, ClusterIP Service는 다음 두 가지 역할을 한다.
1. 고정된 내부 접근 주소 제공
2. selector에 매칭되는 여러 Pod로 트래픽 분산
Pod는 삭제되고 다시 생성될 수 있다. 그러면 Pod IP도 바뀐다.
하지만 Service의 ClusterIP는 유지된다.
그래서 클러스터 내부의 다른 Pod는 매번 바뀌는 Pod IP를 직접 알 필요 없이 Service IP로 접근하면 된다.
직접 Pod IP 접근
→ Pod가 바뀌면 IP도 바뀜
Service 접근
→ Service IP는 유지되고, 뒤의 Pod 목록만 변경됨
이번 실습에서 헷갈리기 쉬운 포인트는 세 가지다.
첫 번째, ClusterIP는 외부 접속용 IP가 아니다.
ClusterIP = 클러스터 내부 전용 IP
그래서 로컬 PC에서 바로 접근하기보다, curl-test 같은 임시 Pod를 클러스터 내부에 띄워서 테스트한다.
두 번째, curl-test Pod는 현재 kubectl context의 클러스터에 생성된다.
kubectl config get-contexts
현재 context가 k3d-my-cluster라면, curl-test도 k3d-my-cluster 안에 생성된다.
세 번째, 각 nginx Pod에 같은 내용을 넣으면 로드밸런싱 여부를 확인하기 어렵다.
모든 Pod가 같은 Welcome to nginx 화면을 보여주면, 요청이 어느 Pod로 갔는지 구분할 수 없다.
그래서 일부러 각 Pod의 응답을 다르게 바꾸는 것이다.
Pod 1 → nginx-1
Pod 2 → nginx-2
Pod 3 → nginx-3
이번 실습에서는 ClusterIP Service가 실제로 여러 Pod에 트래픽을 나눠 보내는지 확인했다.
흐름은 다음과 같다.
1. nginx Deployment로 Pod 3개 생성
2. 각 Pod의 index.html 내용을 다르게 수정
3. ClusterIP Service 생성
4. curl-test 임시 Pod 생성
5. curl-test Pod 안에서 Service IP로 여러 번 curl 요청
6. nginx-1, nginx-2, nginx-3 응답이 번갈아 나오는지 확인
결과적으로 다음과 같은 응답을 확인했다.
nginx-2
nginx-1
nginx-3
이를 통해 nginx-svc Service가 뒤에 있는 nginx Pod 3개로 요청을 분산하고 있음을 확인할 수 있었다.
한 문장으로 정리하면 다음과 같다.
ClusterIP Service는 클러스터 내부에서 고정된 접근 주소를 제공하고, selector에 매칭된 여러 Pod로 트래픽을 분산한다.