[k8s] 서비스

곽동규·2024년 6월 23일

서비스는 실시간으로 파드가 종료되고 생성되는 환경에서 파드 간 연결을 자동으로 가능하게 하는 리소스이다.

1. 서비스의 필요성:

  • 동적 IP 주소: Kubernetes에서 Pod는 동적으로 생성되고 삭제되며, 각 Pod는 고유의 IP 주소를 갖습니다. 이는 Pod가 재시작될 때마다 IP 주소가 바뀔 수 있다는 것을 의미하며, 따라서 가변적인 IP 가 아닌 다른 방식으로 pod에 접근 할 수 있어야 한다. 그 역할을 service가 담당한다.
  • 안정적인 네트워크 접근: 서비스는 이러한 동적 IP 주소 문제를 해결하여, 클러스터 내의 다른 애플리케이션이 안정적으로 접근할 수 있도록 합니다.

2. 서비스 타입:

  • ClusterIP : 클러스터 내부에서만 접근 가능한 내부 IP 주소를 할당합니다. 외부에서는 접근할 수 없습니다.
  • NodePort: 각 노드의 특정 포트(30000-32767 범위)를 오픈하여, 클러스터 외부에서 접근할 수 있습니다. NodePort는 내부적으로 ClusterIP 서비스를 생성합니다.
  • LoadBalancer: 클라우드 제공자의 로드 밸런서를 사용하여 외부 IP 주소를 할당합니다. 이 타입은 NodePort 및 ClusterIP 서비스를 내부적으로 생성합니다. (On-prem 에서는 metallb 사용)
  • ExternalName: CNAME 레코드를 사용하여 외부 서비스에 대한 DNS 이름을 반환합니다. 외부 DNS 이름을 Kubernetes 서비스 이름으로 매핑합니다.

3. 서비스 구성 요소:

  • Selector: 서비스가 트래픽을 라우팅할 Pod를 선택하는 라벨 선택기입니다.
  • Endpoints: 서비스에 의해 선택된 Pod의 IP 주소와 포트를 나타냅니다. Kubernetes가 자동으로 생성하고 관리합니다.
  • Port: 서비스가 노출하는 포트입니다. 여러 개의 포트를 지정할 수 있습니다.
  • 클러스터 내부에서 파드와 파드를 연결 : ClusterIP, Headless
  • 클러스터 외부에서 클러스터 내부의 파드를 연결 : NodePort, LoadBalancer

클러스터 내부 파드 간 통신

레이블을 가진 nginx 디플로이먼트 파일

nginx-deploy.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-hello
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginxdemos/hello
[root@k8s-master01 yaml]# kubectl apply -f nginx-deploy.yml

[root@k8s-master01 yaml]# kubectl get pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-hello-689c8f77bb-98p6p   1/1     Running   0          34s   10.1.69.214   k8s-worker02   <none>           <none>
[root@k8s-master01 yaml]# kubectl get pod --show-labels
NAME                           READY   STATUS    RESTARTS   AGE   LABELS
nginx-hello-689c8f77bb-98p6p   1/1     Running   0          49s   app=nginx,pod-template-hash=689c8f77bb

클러스터IP 타입의 nginx 서비스

apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  selector:  # 선택해야 할 POD
    app: nginx  # 파드 Label과 동일
  type: ClusterIP
  ports:
  - name: tcp
    port: 80
    targetPort: 80
[root@k8s-master01 yaml]# kubectl apply -f nginx-clusterIP-svc.yml 
service/nginx-svc created

[root@k8s-master01 yaml]# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   7d
nginx-svc    ClusterIP   10.100.103.135   <none>        80/TCP    44s

[root@k8s-master01 yaml]# kubectl get endpoints
NAME         ENDPOINTS          AGE
kubernetes   172.16.1.38:6443   7d
nginx-svc    10.1.69.214:80     4m56s

[root@k8s-master01 yaml]# kubectl get pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-hello-689c8f77bb-98p6p   1/1     Running   0          15m   10.1.69.214   k8s-worker02   <none>           <none>

nginx-svc 라는 이름으로 클러스터IP 타입의 서비스가 생성 되었다.
셀렉터를 이용해 서비스가 생성되면 자동으로 endpoint 가 만들어진다.

endpoint 로 클라이언트가 서비스 이름 또는 clusterIP로 호출 시 도착하는 실제 파드의 IP를 확인할 수 있다.
endpoint를 확인 했을 때 nginx 파드의 IP 주소로 조회되는 것을 볼 수 있다.

서비스 디스커버리

기존 nginx pod 를 삭제하고 새로 생성되는 pod 확인

[root@k8s-master01 yaml]# kubectl delete pod nginx-hello-689c8f77bb-98p6p

[root@k8s-master01 yaml]# kubectl get pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
busybox                        1/1     Running   0          28m   10.1.69.215   k8s-worker02   <none>           <none>
nginx-hello-689c8f77bb-4w6t7   1/1     Running   0          38s   10.1.79.88    k8s-worker01   <none>           <none>

busybox 파드에서 연결 테스트 (서비스로 connect)

[root@k8s-master01 yaml]# kubectl exec -it busybox -- sh
/ # wget -O- nginx-svc|grep nginx-svc
Connecting to nginx-svc (10.100.103.135:80)
-                    100% |******************************************************************************************************************************| 12130   0:00:00 ETA
/ #

새로 생성된 파드로 서비스 디스커버리 되는 것을 볼 수 있다. (기존 10.1.69.214 -> 10.1.79.88)

[root@k8s-master01 yaml]# kubectl get endpoints
NAME         ENDPOINTS          AGE
kubernetes   172.16.1.38:6443   7d1h
nginx-svc    10.1.79.88:80      44m

[root@k8s-master01 yaml]# kubectl get pod -o wide
nginx-hello-689c8f77bb-4w6t7   1/1     Running   0          2m43s   10.1.79.88    k8s-worker01   <none>           <none>

요약하자면 새로운 파드는 기존 파드와 달리 새로운 IP 주소를 할당 받았지만 파드 간 연결은 기존과 동일하게 서비스 이름인 nginx-svc를 이용해 정상적으로 접속 된다.

레플리카 2개로 늘렸을 때

[root@k8s-master01 ~]# kubectl scale deployment nginx-hello --replicas=2

[root@k8s-master01 ~]# kubectl get endpoints
NAME         ENDPOINTS                      AGE 
nginx-svc    10.1.69.216:80,10.1.79.88:80   17h

nginx-hello-689c8f77bb-4w6t7   1/1     Running   0          16h     10.1.79.88    k8s-worker01   <none>           <none>
nginx-hello-689c8f77bb-9mlw4   1/1     Running   0          8m20s   10.1.69.216   k8s-worker02   <none>           <none>

cluster-IP는 가상 IP로 동작하므로 실제 파드가 삭제되고 생성되어도 클라이언트는 동일하게 서비스 이름으로 연결하면 cluster-IP를 통해 정상적으로 변경된 실제 IP 주소로 연결된다.
이처럼 쿠버네티스는 DNS를 이용해 변경되는 파드의 IP내역을 관리한다.

클러스터 외부에서 내부의 파드 연결

노드포트 서비스

노드포트 타입의 서비스 생성

apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport-svc
  namespace: default
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    nodePort: 30080
  selector:
    app: nginx 
  type: NodePort
[root@k8s-master01 yaml]# kubectl apply -f nginx-nodeport-svc.yml 
service/nginx-nodeport-svc created

[root@k8s-master01 yaml]# kubectl get svc
NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes           ClusterIP   10.96.0.1        <none>        443/TCP        7d18h
nginx-nodeport-svc   NodePort    10.108.219.96    <none>        80:30080/TCP   17s
nginx-svc            ClusterIP   10.100.103.135   <none>        80/TCP         18h

[root@k8s-master01 yaml]# kubectl get endpoints 
NAME                 ENDPOINTS                      AGE
kubernetes           172.16.1.38:6443               7d18h
nginx-nodeport-svc   10.1.69.216:80,10.1.79.88:80   37s
nginx-svc            10.1.69.216:80,10.1.79.88:80   18h

외부에서 노드포트 서비스의 정의한 포트 30080 으로 내부 nginx 파드로 접속이 가능하다.

[root@k8s-master01 yaml]# curl 172.16.3.100:30080
<!DOCTYPE html>
<html>
<head>
<title>Hello World</title>
<link href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAGPElEQVR42u1bDUyUdRj/iwpolMlcbZqtXFnNsuSCez/OIMg1V7SFONuaU8P1MWy1lcPUyhK1uVbKcXfvy6GikTGKCmpEyoejJipouUBcgsinhwUKKKJ8PD3vnzsxuLv35Q644+Ue9mwH3P3f5/d7n6/3/3+OEJ/4xCc+8YQYtQuJwB0kIp+JrzUTB7iJuweBf4baTlJ5oCqw11C/JHp+tnqBb1ngT4z8WgReTUGbWCBGq0qvKRFcHf4eT/ZFBKoLvMBGIbhiYkaQIjcAfLAK+D8z9YhjxMgsVUGc84+gyx9AYD0khXcMfLCmUBL68HMZ+PnHxyFw3Uwi8B8hgJYh7j4c7c8PV5CEbUTUzBoHcU78iIl/FYFXWmPaNeC3q4mz5YcqJPI1JGKql2Z3hkcjD5EUznmcu6qiNT+Y2CPEoH3Wm4A/QERW

노드포트 서비스의 단점
1. well-known 포트의 사용이 불가능하다. (30000 ~ 32767 포트만 사용 가능)
2. 노드의 IP 중 하나를 지정해야 하므로 서비스 안정성 및 부하분산 문제가 있다.
노드 IP가 변경되면 외부 접속용 IP 도 변경해야 한다.

0개의 댓글