Pod 에게 트래픽 분산을 담당하는 기본 오브젝트 - Service

Created
March 13, 2022
Created by
D
DaEun Kim
Tags
Kubernetes
Property

Service 의 핵심 기능

  • 여러 개의 파드에 쉽게 접근할 수 있도록 고유한 도메인 이름을 부여한다.
  • 여러 개의 파드를 대상으로 요청을 분산시키는 로드밸런서 역할을 한다.
  • 클라우드 플랫폼의 로드밸런서 또는 클러스터 노드의 포트번호를 통해 파드를 외부에 노출시킨다.

Service 의 종류

ClusterIP

클러스터 외부로 파드를 노출하지 않는다.

클러스터 내부(노드 또는 파드)에서만 파드들에 접근할 때 사용한다. (컨트롤 플레인 담당하는 서버에서도 clusterIP로 접근 불가)

NodePort

파드에 접근할 때 쓰는 포트번호를 클러스터 내에 있는 모든 노드에 개방한다.

클러스터 외부에서 파드에 접근할 수 있다.

LoadBalancer

클라우드 플랫폼에서 제공하는 로드밸런서를 동적으로 파드에 연결한다.

NodePort 와 마찬가지로 클러스터 외부에서 파드에 접근할 수 있다.

클라우드 플랫폼 환경에서 주로 사용한다.

로드밸런서에게 External IP 를 할당하는 플러그인이 별도로 필요하다.

ClusterIP

서비스 오브젝트를 따로 정의하지 않아도 Deployment 를 생성하면 kubernetes 라는 이름의 서비스가 자동으로 만들어지고 클러스터 IP가 할당된다. 이 서비스는 파드 내부에서 쿠버네티스 API 에 접근하는 데 필요한 서비스다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-webserver
spec:
  replicas: 3
  selector:
    matchLabels:  # matchLabels 에 있는 라벨이 붙은 파드들을 리플리카셋으로 묶음.
      app: nginx
  template:
    metadata:
      # 같은 네임스페이스에 중복되는 파드 이름은 불가하므로 이 이름은 무시된다.
      # 대신 <deployment 이름>-<해시값> 으로 각 파드 이름이 만들어짐.
      name: pod-webserver
      labels:
        app: nginx
    spec:
      containers:
        - name: webserver
          image: nginx:latest
          ports:
            - containerPort: 80
ubuntu@ip-10-220-12-225:~/k8s-practice$ ku apply -f deployment/deployment-echo-hostname.yaml
deployment.apps/deployment-echo-hostname created


ubuntu@ip-10-220-12-225:~/k8s-practice$ ku get deploy -o wide
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS      IMAGES                            SELECTOR
deployment-echo-hostname   0/3     3            0           5s    echo-hostname   alicek106/rr-test:echo-hostname   app=webserver


ubuntu@ip-10-220-12-225:~/k8s-practice$ ku get po -o wide
NAME                                      READY   STATUS              RESTARTS   AGE   IP       NODE             NOMINATED NODE   READINESS GATES
deployment-echo-hostname-8d556f78-876fl   0/1     ContainerCreating   0          12s   <none>   ip-10-220-6-77   <none>           <none>
deployment-echo-hostname-8d556f78-8mqmx   0/1     ContainerCreating   0          12s   <none>   ip-10-220-6-77   <none>           <none>
deployment-echo-hostname-8d556f78-pj5lx   0/1     ContainerCreating   0          12s   <none>   ip-10-220-6-77   <none>           <none>
ubuntu@ip-10-220-12-225:~/k8s-practice$ ku get services
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   12d

service-clusterip-nginx 를 정의하고 클러스터에 생성한다.

클러스터 IP 10.101.177.94 에 해당하는 서비스가 생성되었다.

apiVersion: v1
kind: Service
metadata:
  name: service-clusterip-nginx
spec:
  type: ClusterIP
  selector:
    # app=nginx 라벨을 갖는 파드들을 서비스 대상으로 간주함.
    app: nginx
  ports:
    - name: web-port
      port: 8080
      targetPort: 80
ubuntu@ip-10-220-12-225:~/k8s-practice$ ku get services
NAME                              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes                        ClusterIP   10.96.0.1       <none>        443/TCP    13d
service-clusterip-nginx           ClusterIP   10.101.177.94   <none>        8080/TCP   81s


ubuntu@ip-10-220-12-225:~/k8s-practice$ ku describe services service-clusterip-nginx
Name:              service-clusterip-nginx
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.101.177.94
IPs:               10.101.177.94
Port:              web-port  8080/TCP
TargetPort:        80/TCP
Endpoints:         11.244.1.47:80,11.244.1.48:80,11.244.1.49:80
Session Affinity:  None
Events:            <none>

워커 노드에 접속해서 10.101.177.94:8080 에 요청을 날려본다.

ubuntu@ip-10-220-6-77:~$ curl 10.101.177.94:8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...
</body>
</html>

NodePort

  • NodePort 타입의 서비스는 기본적으로 클러스터 IP도 제공한다.
  • 클러스터 외부에 노출되어있는 노드의 IP와 spec.ports.nodePort 에 지정된 포트번호로 접근할 경우 app=nginx 라벨을 가지고 있는 파드에 트래픽이 전달된다.
apiVersion: v1
kind: Service
metadata:
  name: service-nodeport-nginx
spec:
  type: NodePort
  selector:
    # app=nginx 라벨을 갖는 파드들을 서비스 대상으로 간주함.
    app: nginx
  ports:
    - name: web-port
      # targetPort: 파드 내부에서 열린 포트번호. 외부에 노출하는 대상.
      targetPort: 80
      # port: 클러스터 내부에서 clusterIP를 통해 파드에 접근할 때 쓰는 포트번호.
      port: 8080
      # nodePort: 클러스터 외부에서 노드 IP를 통해 파드에 접근할 때 쓰는 포트번호. (미설정 할 경우 30000 ~ 32767 사이에서 랜덤으로 지정됨.)
      nodePort: 30000

특이한 점

클러스터 외부에서 Node1의 IP를 가지고 접근했다고 하더라도 Service 의 로드밸런싱 기능에 의해 Node2에 있는 파드에 트래픽이 전달될 수 있다.

→ 하나의 노드에서 다른 노들로 요청이 이동하는 데 불필요한 홉(hop)이 발생한다.

→ 노드 간에 리다이렉션이 생기면 트래픽의 출발지 주소가 바뀌는 SNAT(Source Network Address Translation)이 발생하여 클라이언트의 IP주소가 유실된다. 자세한 내용은 여기 참고.

metadata.externalTrafficPolicyLocal 으로 설정해서 특정 노드에 들어온 트래픽은 그 노드에 있는 파드에서 처리하도록 한다. 대신 노드에 모든 파드가 종료됐을 경우 트래픽 처리가 불가함.

image

컨트롤 플레인 담당하는 서버에서 노드의 호스트 IP:30000 으로 요청을 날리면 응답이 오는 것을 확인할 수 있다.

ubuntu@ip-10-220-12-225:~/k8s-practice/service$ ku get nodes -o wide
NAME               STATUS   ROLES                  AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION   CONTAINER-RUNTIME
ip-10-220-12-225   Ready    control-plane,master   19d   v1.23.4   10.220.12.225   <none>        Ubuntu 18.04.6 LTS   5.4.0-1060-aws   docker://20.10.7
ip-10-220-6-77     Ready    <none>                 19d   v1.23.4   10.220.6.77     <none>        Ubuntu 18.04.6 LTS   5.4.0-1060-aws   docker://20.10.7
ubuntu@ip-10-220-12-225:~/k8s-practice/service$ curl 10.220.6.77:30000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

LoadBalancer

추후에 Ingress 와 같이 다룬다. TBD.

참고자료