Profile picture

[k8s] Deep Dive - Service

JaehyoJJAng2023년 04월 04일

▶︎ 서비스의 필요성

파드가 다른 파드에게 서비스를 제공하는 서비스를 사용하려면 다른 파드를 찾는 방법이 필요하다. 일반적으로 서버의 정확한 IP 주소나 Host 이름을 지정하여 각 Application을 구성하는 것과 달리 쿠버네티스에서 동일한 작업을 수행하면 아래와 같은 문제점이 발생한다.


▶︎ 파드의 특성

Pod는 언제든 사라질 수 있으며 실행중인 노드가 실패할 수도 있고 누군가 Pod를 삭제할 수도 있고 비정상 노드에서 Pod가 제거될 수 있다.

만약 Deployment 서비스를 사용한다면 이러한 Pod의 비영구적인 특성으로 인해 Pod Group이 특정 시점이 지난 Pod Group과 다를 수 있다.

Pod는 고유한 IP주소가 있지만, 클라이언트는 서비스를 지원하는 Pod의 수와 IP에 상관하지 않아야 하며 모든 Pod는 단일 IP주소로 Access할 수 있어야 한다.

쿠버네티스는 이러한 문제점을 해결하기 위해 Service라는 리소스 유형을 제공한다. Service는 어떤 파드가 어디에서 존재하는지(어떤 IP를 가지는지)에 관계없이 파드 중 하나로 연결하여 요청을 처리하도록 한다.


▶︎ 서비스 특징

  • 서비스가 생성되면 정적 IP를 할당받고 서비스가 존속되는 동안 IP가 변경되지 않음
  • 서비스는 동일한 서비스를 제공하는 하나 이상의 파드 그룹의 정적 위치를 나타낸다.
  • 서비스의 IP와 포트로 유입된 요청은 그 순간 서비스에 매핑된 파드 중 하나에게 전달된다.

image


서비스에는 여러 종류가 있지만 주로 사용하는 서비스 타입은 크게 3가지이다.

  • ClusterIP
    • 쿠버네티스 내부에서 파드에 접근할 때 사용한다. 외부로 Pod를 노출하지 않기 때문에 쿠버네티스 클러스터 내부에서만 사용되는 Pod에 적합하다
  • NodePort
    • Pod에 접근할 수 있는 포트를 Cluster 모든 Node에 동일하게 개방한다. 따라서 외부에서 Pod에 접근할 수 있는 타입이다. 접근할 수 있는 포트는 랜덤으로 정해지지만 특정 포트로 접근하도록 설정할 수도 있다.
  • LoadBalancer
    • 클라우드 플랫폼에서 제공하는 Load Balancer를 동적으로 Provisioning하여 포드에 연결한다. NodePort 타입과 마찬가지로 외부에서 포드에 접근할 수 있는 서비스 타입이다. 일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼 환경에서만 이용할 수 있다.

▶︎ 서비스 접근 방법

서비스를 지원하는 Pod가 여러 개 일 수 있다. 서비스 연결은 서비스 뒷단의 모든 Pod로 Load Balancing이 되는데, 그렇다면 정확하게 어떤 Pod가 서비스의 일부분인지 아닌지를 정의할까?

바로 레이블 셀렉터(Label Selector)이다. Deployment에서 Label Selector를 통해 동일한 세트에 속하는 Pod를 지정하는 메커니즘과 같이 Service에도 그대로 사용된다.
image


▶︎ ClusterIP 특징

  • 클러스터 내부에 새로운 IP를 할당
  • 여러 Pod를 바라보는 LoadBalancer 기능을 제공
  • 서비스 이름을 내부 도메인 서버에 등록하여 Pod 간에 서비스 이름으로 통신

‣ 서비스 생성

  • ClusterIP 서비스 생성

svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    app.kubernetes.io/name: web-deploy
  type: ClusterIP # Default
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
  • 포트 80의 연결을 허용
  • app.kubernetes.io/name: web-deploy Label Selector와 일치하는 Pod의 포트 80으로 라우팅

Service Yaml 파일 문법 정리

spec.type
서비스가 어떤 타입인지 나타냄. 서비스 종류에는 ClusterIP,NodePort,LoadBalancer 등을 설정

spec.selector
selector 항목은 이 서비스에서 어떠한 레이블을 가지는 Pod에 접근할 수 있게 만들기 결정

spec.ports.port
생성된 서비스는 k8s 내부에서만 사용할 수 있는 고유한 IP를 할당 받음. port 항목에는 서비스의 IP에 접근할 때 사용할 포트를 설정

spec.port.targetPort
selector 항목에서 정의한 Label에 의해 접근 대상이 된 Pod들이 내부적으로 사용하고 있는 Port를 입력한다


생성한 web-svc 서비스 상세 정보 조회

kubectl get svc web-svc -o wide

NAME      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE   SELECTOR
web-svc   ClusterIP   10.108.212.159   <none>        80/TCP    18m   app.kubernetes.io/name=web-deploy

yaml 파일 적용 후 서비스 리소스를 조회하면 서비스에 내부 Cluster IP가 할당되었는지 확인할 수 있다.


‣ 서비스 테스트

  • 클러스터 내에서 서비스 테스트

간단한 deployment를 생성하여 Selector된 pod로 통신이 되는지 확인해보도록 함.


1. test-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-web-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      name: test-web-deploy
      type: test
  template:
    metadata:
      labels:
        name: test-web-deploy
        type: test
    spec:
      containers:
        - name: web
          image: nginx:1.25

test-deploy 디플로이먼트 생성

kubectl apply -f test-deploy.yaml

2. test-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: test-web-svc
spec:
  selector:
    type: test
  type: ClusterIP
  ports:
    - protocol: TCP
      port: 80

test-svc 서비스 생성

kubectl apply -f test-svc.yaml

생성된 서비스의 ClusterIP를 확인해보자.

kubectl get svc/test-web-svc

NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
test-web-svc   ClusterIP   10.109.163.175   <none>        80/TCP    2m54s

위 ClusterIP의 80번 포트를 마스터 노드에서 테스트해보자.

curl 10.109.163.175

image
클러스터인 마스터 노드에서 test-web-svc 서비스에 연결된 pod들과 정상적으로 통신이 되는 것을 볼 수 있었음.


그럼, 이제 node1로 넘어가서 curl <서비스애서 생성된 Cluster IP>로 명령을 날려보자.

curl 10.109.163.175

image
파드들이 test-web-svc 서비스와 연결이 되어있기에, 노드들에서도 정상적으로 통신이 되는 것을 볼 수 있다.


이번에는, 생성된 파드의 컨테이너로 접속하여 서비스(10.109.163.175)에 요청을 보내보자.

# Pod 확인
$ kubectl get pods
NAME                               READY   STATUS    RESTARTS   AGE
test-web-deploy-6bc86d646b-cntsc   1/1     Running   0          4s
test-web-deploy-6bc86d646b-l7qqf   1/1     Running   0          4s
test-web-deploy-6bc86d646b-mnhz9   1/1     Running   0          4s

# 첫번째 컨테이너로 접속
kubectl exec -it test-web-deploy-6bc86d646b-cntsc -- /bin/bash

# 서비스 주소로 요청
curl 10.109.163.175

image
정상적으로 요청됨.


Loading script...