쿠버네티스 교육

07. Kube 교육 - Service Discovery

Jerry_이정훈 2021. 6. 4. 16:40
728x90

실습

  • NGINX Service를 생성해 보세요.
  • Service 적용 후 Endpoint가 제대로 생성되었는지 확인해 보세요. 
  • 기존 POD를 Delete 후 Service 연결을 검증해 보세요.
  • 복수의 POD를 실행하여 POD Load Balancing 기능을 검증해 보세요. 

Why Service Discovery

Kube는 기본 철학(?)이 POD는 항상 죽을 수 있다 입니다. 기존 POD가 죽고 나서 새로 생성되는 POD는 IP, Hostname 등 환경 정보가 기존 POD와 다릅니다. (재시작이 아니라 새로운 POD가 생성입니다.) 이 때 POD 간 통신이 IP 기반이라면 Client 단에서 일일이 새로운 IP를 추가해야 하므로 관리가 불가능합니다. 그리고 기존 POD를 이중화하여 새로운 POD가 추가되면 해당 IP를 LoadBalancer에 새롭게 추가하는 기능도 필요합니다.  

 

Kube는 이러한 문제를 Service라는 Object에서 DNS 기반으로 처리하여 해결합니다. 그리고 변경된 사항은 자동으로 데이터베이스에 업데이트되어 자동으로 반영합니다. 

 

What is Kubernetes Service

Kubernetes 에서는 Service를 사용하여 POD 간 통신 또는 외부에서 POD 접속을 처리 합니다. (용어가 Service인데, 우리가 아는 Application 서비스와 전혀 상관 없습니다.) 

 

Kube 환경에서 POD는 죽었다 (새로운 POD) 살았다 반복이 가능합니다. 이 때 신규로 생성된 POD는 새로운 POD 이므로 기존과 다른 IP(ex 10.10 -> 10.11)를 가집니다. 따라서 기존 VM간 통신처럼 IP 기반인 경우 클라이언트 단에서 변경된 IP 정보를 계속 업데이트 해야하는 등의 문제가 발생합니다. 

 

이러한 문제를 Kubernetes Service는 IP가 아닌 도메인 이름(서비스 이름)을 사용하여 해결합니다. 

 

그럼, 예제를 통하여 알아 보겠습니다. 

 

1. NGINX POD를 지정(selector)하는 Service를 생성해 보세요

  • 먼저 NGINX의 label을 확인합니다.
NGINX Deploy YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-hello
  labels:
    app: nginx   
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx # Service 등에서 참조할 Label 이름
    spec:
      containers:
      - name: nginx
        image: nginxdemos/hello

[spkr@erdia22 06.Deployment (k3s:nginx)]$ ka nginxhello-deploy.yml 
deployment.apps/nginx-hello created

[spkr@erdia22 06.Deployment (k3s:nginx)]$ k get pod --show-labels
NAME                          READY   STATUS    RESTARTS   AGE   LABELS
nginx-hello-c97cdb45c-9sn4w   1/1     Running   0          17s   app=nginx,pod-template-hash=c97cdb45c
nginx-hello-c97cdb45c-2f2tq   1/1     Running   0          17s   app=nginx,pod-template-hash=c97cdb45c
  • 서비스 YAML 생성 시 위 label(app=nginx)을 selector 로 지정합니다. (selector는 말 그대로 지정자, 지정하는 대상을 가르킵니다.)
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  type: ClusterIP
  ports:
  - name: tcp
    port: 80
  selector:  # 선택해야 할 POD 선택
    app: nginx  # POD Label 과 동일

port 번호는 컨테이너 이미지 생성 시 사용한 port 번호입니다.  

From : 김충섭님 블로그

서비스 확인 

[spkr@erdia22 11.Service (spkn02:nginx)]$ k get svc
NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-svc   ClusterIP   10.233.25.109   <none>        80/TCP    2m2s

2. NGINX 서비스의 endpoint를 확인해 보세요

Kube는 service로 연결되는 실제 대상을 endpoint라는 이름으로 관리합니다. 


Service 생성 후 endpoint로 조회 가능합니다. 

[spkr@erdia22 junghoon2.github.io (spkn02:nginx)]$ k get endpoints
NAME        ENDPOINTS         AGE
nginx-svc   10.233.90.71:80   4m37s

위와 같이 nginx-svc에 해당하는 endpoint 대상의 ip(10.233.90.71)를 확인 가능합니다. 만약 위 endpoint 가 없다면 service가 바라보는 대상이 없으므로 service 설정이 제대로 안되어 있다는 걸 의미 합니다. 

describe로 보시면 좀 더 자세한 정보를 확인하실 수 있습니다.

[spkr@erdia22 junghoon2.github.io (spkn02:nginx)]$ k describe endpoints nginx-svc
Name:         nginx-svc
Namespace:    nginx
Labels:       <none>
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2021-05-21T00:45:58Z
Subsets:
  Addresses:          10.233.90.71
  NotReadyAddresses:  <none>
  Ports:
    Name  Port  Protocol
    ----  ----  --------
    tcp   80    TCP

Events:  <none>

Kube 에서는 아래와 같이 API Server로 service, endpoint 변경 내역을 계속 체크 합니다. 

 

출처: 갓 김충섭 님 블로그

3. 신규 Busybox POD를 생성하여 NGINX POD와 서로 연결해 보세요. 

  • Service 기능 검증을 위하여 새로운 Deploy를 생성하겠습니다.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox
  namespace: nginx
  labels:
    app: busybox
spec:
  replicas: 1
  selector:
    matchLabels:
      app: busybox  # POD label과 일치
  template:    
    metadata:
      labels:
        app: busybox # Selector label과 일치
    spec:
      containers:
      - name: busybox
        image: busybox
        command:
        - "/bin/sh"
        - "-c"
        - "sleep inf"

간단한 busybox pod 입니다.

[spkr@erdia22 11.Service (spkn02:nginx)]$ kgp
NAME                       READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
busybox-6d8496d56f-z4mf2   1/1     Running   0          84s   10.233.90.72   node1   <none>           <none>
nginx-6799fc88d8-rk4lj     1/1     Running   0          20h   10.233.90.71   node1   <none>           <none>

이 때 busybox POD와 NGINX POD 연결 시 IP를 사용하지 않고 service 이름을 사용해서 통신이 가능 합니다.

[spkr@erdia22 11.Service (spkn02:nginx)]$ k exec -it busybox-6d8496d56f-z4mf2 -- sh
/ # 

[spkr@erdia22 junghoon2.github.io (spkn02:nginx)]$ k get svc
NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx-svc   ClusterIP   10.233.25.109   <none>        80/TCP    13m

/ # ping nginx-svc
PING nginx-svc (10.233.25.109): 56 data bytes
64 bytes from 10.233.25.109: seq=0 ttl=64 time=0.078 ms
64 bytes from 10.233.25.109: seq=1 ttl=64 time=0.089 ms

위와 같이 POD간 연결을 IP가 아닌 서비스 이름을 사용합니다.

/ # telnet nginx-svc 80
Connected to nginx-svc

흔히 port 오픈 확인 용도로 사용하시는 telnet도 사용 가능합니다.

 

만약, 실행 중인 POD의 namespace가 서로 다르면 연결 시 namespace 이름까지 붙여 줍니다. ‘default’ namespace POD에서 연결해 보겠습니다. 

[spkr@erdia22 41.NGINX (k3s:nginx)]$ kns default
Context "k3s" modified.
Active namespace is "default".

[spkr@erdia22 41.NGINX (k3s:default)]$ ka busybox-deploy.yml 
deployment.apps/busybox unchanged

[spkr@erdia22 junghoon2.github.io (spkn02:nginx)]$ k exec -it -n default date-pvc-mirror-5cf6bf8f4b-6jljp -- sh
/ # ping nginx-svc.nginx
PING nginx-svc.nginx (10.233.25.109): 56 data bytes
64 bytes from 10.233.25.109: seq=0 ttl=64 time=0.084 ms
64 bytes from 10.233.25.109: seq=1 ttl=64 time=0.923 ms
^C
--- nginx-svc.nginx ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.084/0.503/0.923 ms

/ # ping nginx-svc
ping: bad address 'nginx-svc'

위와 같이 nginx-svc.nginx (namespace 이름)는 가능하지만 nginx-svc로는 안 됩니다. 즉 다른 namespace에서는 namespace 이름까지 같이 지정해 주셔야 합니다. 

 

4. NGINX POD 삭제하여 Service 접속 여부를 확인해 보세요. 

 

기존 POD를 삭제하고 새로운 POD를 생성해 보겠습니다.

[spkr@erdia22 ~ (spkn02:nginx)]$ kgp
NAME                       READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
nginx-6799fc88d8-rk4lj     1/1     Running   0          20h   10.233.90.71   node1   <none>           <none>

[spkr@erdia22 ~ (spkn02:nginx)]$ k delete pod nginx-6799fc88d8-rk4lj
pod "nginx-6799fc88d8-rk4lj" deleted

[spkr@erdia22 ~ (spkn02:nginx)]$ kgp
NAME                       READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
nginx-6799fc88d8-xqrcv     1/1     Running   0          47s   10.233.92.50   node3   <none>           <none>

위와 같이 새로운 POD가 생성되어 IP가 변경되었습니다. (90.71 -> 92.50)

 

그럼 POD 간 연결을 확인해 보겠습니다.

[spkr@erdia22 junghoon2.github.io (spkn02:nginx)]$ k exec -it busybox-6d8496d56f-z4mf2 -- sh
/ # ping nginx-svc
PING nginx-svc (10.233.25.109): 56 data bytes
64 bytes from 10.233.25.109: seq=0 ttl=64 time=0.067 ms
64 bytes from 10.233.25.109: seq=1 ttl=64 time=0.077 ms

기존처럼 동일하게 서비스 이름(nginx-svc)으로 연결 가능합니다.

Service에서 자동으로 신규 생성된 POD IP를 endpoint로 등록하기 때문입니다. 따라서 POD IP가 변경되어도 동일하게 서비스 이름으로 POD간 통신이 가능합니다. 

 

endpoint를 확인해 보면 ip가 변경(90.71 -> 92.50) 된 걸 확인 가능합니다.

[spkr@erdia22 ~ (spkn02:nginx)]$ k get endpoints
NAME        ENDPOINTS         AGE
nginx-svc   10.233.92.50:80   21m

이상으로 간단히 Service Discovery에 대하여 알아 보았습니다. 

 

Kubernetes 컨설팅, 교육, 기술 지원 문의 : leejunghoon@spkr.co.kr 

 

참조

https://kubernetes.io/ko/docs/tasks/access-application-cluster/connecting-frontend-backend/

 

서비스를 사용하여 프론트엔드를 백엔드에 연결

이 작업은 프론트엔드 와 백엔드 마이크로서비스를 어떻게 생성하는지를 설명한다. 백엔드 마이크로서비스는 인사하기(hello greeter)이다. 프론트엔드는 nginx 및 쿠버네티스 서비스 오브젝트를 사

kubernetes.io

 

반응형