교육, 커뮤니티 후기/인프런 교육

<인프런> 대세는 쿠버네티스 [초급] - No.10 Object - Service 실습

Somaz 2022. 8. 31. 17:38
728x90
반응형

Overview

이전 글에서 이론적으로 학습한 Kubernetes의 Service 오브젝트에 대해, 이번에는 실습을 통해 직접 적용해보는 시간을 가졌다.


Pod를 외부 또는 클러스터 내에서 접근 가능한 방식으로 노출하는 다양한 Service 타입 중,
ClusterIP, NodePort, LoadBalancer 를 중심으로 구성하고 각각의 동작 방식과 네트워크 흐름을 확인했다.

 

실습은 사내의 3대 VM 환경(dh-k8s-master, dh-k8s-node, dh-k8s-node2)에서 진행되었으며,
실제 요청을 curl 명령어로 수행하면서 서비스 유형에 따른 트래픽 분산, 접근 범위,
그리고 externalTrafficPolicy에 따른 트래픽 라우팅의 차이를 직접 확인해볼 수 있었다.

 

 

2022.08.29 - [교육, 커뮤니티 후기] - <인프런> 대세는 쿠버네티스 [초급] - No.9 Object - Service

 

<인프런> 대세는 쿠버네티스 [초급] - No.9 Object - Service

Overview 오늘은 kubernetes service에 대해서 공부해보려고 한다. Object - Service ClusterIP service는 기본적으로 자신의 ClusterIP를 가지고 있다. Service를 Pod에 연결을 시켜놓으면, Service IP를 가지고..

somaz.tistory.com

 

 

 

N/W

서버 유형 Hostname OS CPU 메모리 서비스망 IP 내부망 IP 계정
가상 머신 dh-k8s-master CentOS 7 2 Cores 4G 192.168.21.112 (/24) 10.1.1.112 (/8) root, somaz
가상 머신 dh-k8s-node CentOS 7 2 Cores 4G 192.168.21.113 (/24) 10.1.1.113 (/8) root, somaz
가상 머신 dh-k8s-node2 CentOS 7 2 Cores 4G 192.168.21.114 (/24) 10.1.1.113 (/8) root, somaz

 

 

 

 

 


 

 

1. ClusterIP

 

 

실습 1) Pod 생성 후 ClusterIP 로 Service 생성

 

pod를 하나 생성한다.

$ vi pod-1.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-1
  labels:
     app: pod
spec:
  nodeSelector:
    kubernetes.io/hostname: dh-k8s-node
  containers:
  - name: container
    image: tmkube/app
    ports:
    - containerPort: 8080

$ kubectl apply -f pod-1.yaml 
pod/pod-1 created

 

service를 생성한다.

apiVersion: v1
kind: Service
metadata:
  name: svc-1
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
type: ClusterIP		# type의 default 값이 ClusterIP이다. 생략 가능하다.

 

 

 

service apply 해보자.

$ kubectl apply -f svc-1.yaml 
error: error validating "svc-1.yaml": error validating data: ValidationError(Service): unknown field "type" in io.k8s.api.core.v1.Service; if you choose to ignore these errors, turn validation off with --validate=false

# 에러가 발생한다. type:ClusterIP를 지우고 apply 해보자.

$ kubectl apply -f svc-1.yaml 
service/svc-1 created

$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    45h   <none>
svc-1        ClusterIP   10.108.27.243   <none>        9000/TCP   14s   app=pod

$ curl 10.108.27.243:9000/hostname
Hostname : pod-1

 

 

 

그러나 web에서는 열리지 않는다. 왜냐하면 ClusterIP로 설정되어 있기 때문이다.

이해가 가지 않는다면 아래의 포스팅을 참고하기 바란다.

2022.08.29 - [교육, 커뮤니티 후기] - <인프런> 대세는 쿠버네티스 [초급] - No.9 Object - Service

 

 

 

 

실습 2) Pod 삭제 후 재생성

# pod 확인
$ kubectl get po -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP              NODE          NOMINATED NODE   READINESS GATES
pod-1   1/1     Running   0          4m27s   172.16.12.146   dh-k8s-node   <none>           <none>

# pod 삭제 후 재생성
$ kubectl delete -f pod-1.yaml
pod "pod-1" deleted
$ kubectl apply -f pod-1.yaml
pod/pod-1 created

# pod 다시 확인
$ kubectl get po -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
pod-1   1/1     Running   0          32s   172.16.12.147   dh-k8s-node   <none>           <none>

# service 확인
$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    46h   <none>
svc-1        ClusterIP   10.108.27.243   <none>        9000/TCP   31m   app=pod

$ curl 10.108.27.243:9000/hostname
Hostname : pod-1

 

 

 

 

 

 


 

 

 

2. NodePort

 

 

실습 1) svc-1 삭제 후 NodePort 로 svc-2 생성

$ kubectl delete -f svc-1.yaml 
service "svc-1" deleted


apiVersion: v1
kind: Service
metadata:
  name: svc-2
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
    nodePort: 30000
  type: NodePort
  
$ kubectl apply -f svc-2.yaml
service/svc-2 created
  
$ kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          46h   <none>
svc-2        NodePort    10.101.105.144   <none>        9000:30000/TCP   4s    app=pod

# 9000번은 ClusterIP로 접근했을 때 사용하는 포트이다.
# 30000번은 NodePort로 접근했을 때 사용하는 포트이다.

 

먼저 dh-k8s-node는 192.168.21.113 (/24) 사용하고, dh-k8s-node2는 192.168.21.114 (/24) 를 사용한다.

나는 사내 서버를 이용해 TestServer를 구성했다. 사내 서버에서 접근을 해보자.

$ curl 192.168.21.113:30000/hostname
Hostname : pod-1
$ curl 192.168.21.114:30000/hostname
Hostname : pod-1

 

 

 

실습 2) pod-2 생성 후 Traffic 분산을 확인

$ vi pod-2.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-2
  labels:
     app: pod
spec:
  nodeSelector:
    kubernetes.io/hostname: dh-k8s-node2
  containers:
  - name: container
    image: tmkube/app
    ports:
    - containerPort: 8080

$ kubectl apply -f pod-2.yaml
pod/pod-2 created

 

이제 사내서버에서 Traffic 분산을 확인해보자.

$ curl 192.168.21.113:30000/hostname
Hostname : pod-2
$ curl 192.168.21.113:30000/hostname
Hostname : pod-2
$ curl 192.168.21.113:30000/hostname
Hostname : pod-1
$ curl 192.168.21.113:30000/hostname
Hostname : pod-1

$ curl 192.168.21.114:30000/hostname
Hostname : pod-2
$ curl 192.168.21.114:30000/hostname
Hostname : pod-2
$ curl 192.168.21.114:30000/hostname
Hostname : pod-1
$ curl 192.168.21.114:30000/hostname
Hostname : pod-1
  • Traffic 분산이 잘 되고 있다.

 

 

 

실습 3) svc-2 삭제 후 `externalTrafficPolicy: Local` 옵션을 써서 svc-2 생성

$ kubectl delete -f svc-2.yaml
service "svc-2" deleted

$ vi svc-2.yaml

apiVersion: v1
kind: Service
metadata:
  name: svc-2
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
    nodePort: 30000
  type: NodePort
  externalTrafficPolicy: Local

$ kubectl apply -f svc-2.yaml
service/svc-2 created

 

 

 

이제 확인해보자.

$ curl 192.168.21.113:30000/hostname
Hostname : pod-1
$ curl 192.168.21.113:30000/hostname
Hostname : pod-1
$ curl 192.168.21.113:30000/hostname
Hostname : pod-1
$ curl 192.168.21.113:30000/hostname
Hostname : pod-1

$ curl 192.168.21.114:30000/hostname
Hostname : pod-2
$ curl 192.168.21.114:30000/hostname
Hostname : pod-2
$ curl 192.168.21.114:30000/hostname
Hostname : pod-2
$ curl 192.168.21.114:30000/hostname
Hostname : pod-2
  • `externalTrafficPolicy` 옵션을 써주었기 때문에 이제 해당 node IP로는 해당 node의 pod만 불러오는 것이다.

 


 

 

 

3. Load Balancer

 

 

실습 1) type: LoadBalancer로 svc-3 생성

$ vi svc-3.yaml

apiVersion: v1
kind: Service
metadata:
  name: svc-3
spec:
  selector:
    app: pod
  ports:
  - port: 9000
    targetPort: 8080
  type: LoadBalancer

$ kubectl apply -f svc-3.yaml
service/svc-3 created

$ kubectl get svc svc-3
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
svc-3   LoadBalancer   10.104.60.113   <pending>     9000:31735/TCP   65s
# pending 상태인 이유는 LoadBalancer 플러그인이 설치가 안되어 있기 때문이다.

 

 

 

 

 


 

 

4. 마무리

 

`Sample.yaml`

apiVersion: v1
kind: Service
metadata:
  name: svc-3
spec:
  selector:             # Pod의 Label과 매칭
    app: pod
  ports:
  - port: 9000          # Service 자체 Port
    targetPort: 8080    # Pod의 Container Port
  type: ClusterIP, NodePort, LoadBalancer  # 생략시 ClusterIP
  externalTrafficPolicy: Local, Cluster    # 트래픽 분배 역할

 

 

NodePort

  • Node Port의 범위 : 30000~32767

 

 

 

 


 

 

 

 

마무리

이번 실습을 통해 Kubernetes 서비스의 구조와 동작 원리를 훨씬 더 명확하게 이해할 수 있었다.

  • ClusterIP: 기본 타입으로, 내부 통신 전용이며 외부에서는 접근 불가.
  • NodePort: 외부에서 접근 가능, 클러스터의 모든 노드 IP + 노출 포트(30000~32767)를 통해 접속.
  • externalTrafficPolicy: Local: 클라이언트 IP 보존 가능, 해당 노드의 Pod만 트래픽을 받음.
  • LoadBalancer: 클라우드 환경에서 외부 IP를 자동 할당받아 사용하지만, 메탈 환경에서는 별도 구성 필요.

 

이처럼 Kubernetes의 서비스 오브젝트는 단순한 네트워크 연결 수단이 아니라, 트래픽 분산, 접근 제어,
확장성 및 안정성을 보장하는 핵심 요소이다. 특히 실무에서 서비스 노출 방식 선택은 아키텍처 설계에 큰 영향을 미치므로
이러한 차이점을 정확히 이해하는 것이 중요하다.

실습을 통해 이론을 체화하니, 쿠버네티스 네트워크의 퍼즐이 조금씩 맞춰지는 느낌이다.
다음엔 Ingress와의 연계를 통해 더 풍부한 시나리오도 다뤄보자!

 

 

 

 

 

 

 

 

 

 


Referenece

 

Kubernetes

Others

728x90
반응형