본문 바로가기

Devops/Kubernetes

[Kubernetes] 쿠버네티스 Service 개념 - ClusterIP, NodePort

서비스(Service) 가 필요한 이유

  • 파드는 일회성이다. 노드에서 파드가 제거되면 새로운 파드가 생성되거나, 클러스터의 노드에 장애가 발생되면 다른 노드로 이동된다.
  • 쿠버네티스의 파드는 노드에 스케쥴된 후 시작하기 전에 IP 주소를 할당하기 때문에 미리 파드의 IP 주소를 알기 어렵다.
  • Scale-out(HPA) 는 여러 파드가 같은 서비스를 제공하는 것을 의미하는데 각 파드는 개별 IP 주소를 가지게 된다. 클라이언트는 서비스를 제공하는 파드의 수와 IP를 신경 쓸 필요가 없어야 한다.

-> 서비스 (Service)를 사용하면 파드가 클러스터 안 어디에 있던 고정 IP 주소 (Endpoint IP Address)를 통해서 접근할 수 있다.

 

CluserIP

기본 서비스 타입으로 클러스터 내부에서 사용이 가능.

클러스터 안 노드나 파드에서는 ClusterIP를 이용해서 서비스에 연결된 파드에 접근할 수 있다.

클러스터 외부에서는 사용할 수 없다.

 

root@master:~/k8s_lab/service# cat clusterip-hostname.yaml
apiVersion: v1
kind: Service
metadata:
  name: clusterip-hostname-service
spec:
  type: ClusterIP
  selector:
    app: hostname-server
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80
root@master:~/k8s_lab/service# cat hostname-server.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostname-server
  labels:
    app: hostname-server
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hostname-server
  template:
    metadata:
      labels:
        app: hostname-server
    spec:
      containers:
      - name: hostname-server
        image: takytaky/hostname
        ports:
        - containerPort: 80

-> 2개의 pod를 생성하고 각 pod에는 80 포트로 server가 동작함.

 

root@master:~/k8s_lab/service# kubectl apply -f hostname-server.yaml
deployment.apps/hostname-server created

root@master:~/k8s_lab/service# kubectl apply -f clusterip-hostname.yaml
service/clusterip-hostname-service created

root@master:~/k8s_lab/service# kubectl get deploy,svc,pods -o wide
NAME                              READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS        IMAGES              SELECTOR
deployment.apps/hostname-server   2/2     2            2           38s   hostname-server   takytaky/hostname   app=hostname-server

NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE   SELECTOR
service/clusterip-hostname-service   ClusterIP   10.106.104.217   <none>        8080/TCP   26s   app=hostname-server
service/kubernetes                   ClusterIP   10.96.0.1        <none>        443/TCP    16d   <none>

NAME                                   READY   STATUS    RESTARTS   AGE   IP                NODE      NOMINATED NODE   READINESS GATES
pod/hostname-server-775f65669c-psgkf   1/1     Running   0          37s   192.168.235.140   worker1   <none>           <none>
pod/hostname-server-775f65669c-tvh8w   1/1     Running   0          36s   192.168.189.81    worker2   <none>           <none>

 

ClusterIP 서비스를 띄우고 describe 명령어로 상세 내역을 보면 서비스 ClusterIP 및 각 POD의 IP 할당 내용을 볼수 있다.

 

root@master:~/k8s_lab/service# kubectl describe svc clusterip-hostname-service
Name:              clusterip-hostname-service
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=hostname-server
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.106.104.217
IPs:               10.106.104.217
Port:              <unset>  8080/TCP
TargetPort:        80/TCP
Endpoints:         192.168.189.81:80,192.168.235.140:80
Session Affinity:  None
Events:            <none>

 

마스터 노드에서 ClusterIP로 http request 테스트를 해보면 아래와 같이 worker1, worker2 노드에 각각 떠있는 pod에서 서버 api 호출 결과가 출력 되는 것을 볼수 있다.

root@master:~/k8s_lab/service# for i in $(seq 10);do curl -s 10.106.104.217:8080 | grep Hello;sleep 1;done
        <p>Hello,  hostname-server-775f65669c-psgkf</p> </blockquote>
        <p>Hello,  hostname-server-775f65669c-tvh8w</p> </blockquote>

 

하지만 앞서 말한 대로 ClusterIP는 클러스터 내부에서만 동작 하므로 Node 외부에서는 접근이 불가능하다.

 

마스터 노드의 외부 IP는 172.30.1.25 이므로 해당 IP로 동일하게 실행시에는 아무런 응답이 발생하지 않는다.

 

root@master:~/k8s_lab/service# for i in $(seq 10);do curl -s 172.30.1.25:8080 | grep Hello;sleep 1;done (결과 X)

root@master:~/k8s_lab/service#

 

NodePort

  • NodePort 타입의 서비스에 클러스터의 모든 노드들의 지정된 포트를 할당.
  • 노드에 상관없이 지정된 포트 번호만 사용하면 파드에 접근 가능.

-> 노드의 주소를 사용하기 때문에 클러스터 안에서 뿐만 아니라 클러스터 외부에서도 접근 가능

worker1 노드에서만 파드가 실행되어 있더라도 worker2 의 주소로 접근이 가능

 

root@master:~/k8s_lab/service# cat nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: nodeport-hostname-service
spec:
  type: NodePort
  selector:
    app: hostname-server
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80
    nodePort: 30080
root@master:~/k8s_lab/service# kubectl delete svc clusterip-hostname-service
service "clusterip-hostname-service" deleted
=> 앞서 실행했던 cluserip service를 삭제

root@master:~/k8s_lab/service# kubectl apply -f nodeport.yaml
service/nodeport-hostname-service created
=> NodePort 서비스 새로 생성

root@master:~/k8s_lab/service# kubectl get deploy,svc,pods -o wide
NAME                              READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS        IMAGES              SELECTOR
deployment.apps/hostname-server   2/2     2            2           14m   hostname-server   takytaky/hostname   app=hostname-server

NAME                                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE   SELECTOR
service/kubernetes                  ClusterIP   10.96.0.1       <none>        443/TCP          16d   <none>
service/nodeport-hostname-service   NodePort    10.99.158.187   <none>        8080:30080/TCP   5s    app=hostname-server

NAME                                   READY   STATUS    RESTARTS   AGE   IP                NODE      NOMINATED NODE   READINESS GATES
pod/hostname-server-775f65669c-psgkf   1/1     Running   0          14m   192.168.235.140   worker1   <none>           <none>
pod/hostname-server-775f65669c-tvh8w   1/1     Running   0          14m   192.168.189.81    worker2   <none>           <none>

 

위에서 nodeport로 할당된 10.99.158.187:8080 으로 내부 IP 접근을 해보면 pod server 결과가 출력된다.

 

root@master:~/k8s_lab/service# curl -s 10.99.158.187:8080
<!DOCTYPE html>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="./css/login.css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">

<div class="form-signin">
        <blockquote>
        <p>Hello,  hostname-server-775f65669c-psgkf</p> </blockquote>
</div>

 

이번에는 node 밖에서 테스트를 해보자. 작업중인 윈도우 PC에서 커맨드 창을 열고 클러스터의 마스터 노드의 외부 IP (172.30.1.25)에 NodePort에서 맵핑한 외부 포트 30080으로 서버 호출을 해보면 정상적으로 결과가 나온다.

 

신기하게도 클러스터와 연결된 3개 노드(172.30.1.25 마스터, 172.30.1.10 Worker1, 172.30.1.36 Worker2) 모두 접근해도 결과가 나온다. 해당 노드에서 pod가 실행하고 있지 않아도 어떤 노드로 접근을 해도 서버 실행 결과를 볼 수 있다.

 

-- The End --