[Kubernetes] 쿠버네티스 Service 란?

[Kubernetes] 쿠버네티스 Service 란?

안녕하세요? 정리하는 개발자 워니즈 입니다. 지난시간에는 쿠버네티스 POD라는 개념에 대해서 알아봤는데요. 이번시간에는 이러한 POD들을 어떻게 서비스를 해주는 지에 대한 관점인 Service에 대해서 알아보는 시간을 가져보도록 하겠습니다.

지난 글들은 아래를 참고 해주시면 됩니다.

필자가 속한 프로젝트에서는 아직 쿠버네티스를 사용하고 있지 않습니다. 그래서 개인적으로 쿠버네티스 클러스터를 연결해서 nginx POD 를 생성해서 배포까지 해봤습니다. 그런데 여기서 POD 가 여러개라면 그 앞에 관문 역할을 하는 것이 필요할 것입니다.

이러한 개념이 바로 Service 입니다.

1. Service Template 작성

서비스 템플릿이란 쿠버네티스에서 Service를 생성하기 위한 YML 로 작성된 파일을 말합니다. 다음은 예시입니다.

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    run: my-nginx

그럼 위의 내용을 한줄 씩 설명해드리겠습니다.

  • 서비스 이름
metadata:
  name: my-nginx

서비스의 이름은 my-nginx이고, labels는 해당 POD에 대해서 라벨링을 해두는것인데, 여기서는 run: my-nginx라고 해두었습니다.

  • 타입
spec:
  type: NodePort

Service는 유형(ClusterIP, NodePort, LoadBalancer) 을 갖고 있는데, Node Port를 여기서 사용하고있습니다.

  • 포트
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP

클러스터 port는 8080 이고 실제 nginx POD가 서비스 되는 포트는 80 포트입니다.

  • 셀렉터
  selector:
    run: my-nginx

이 서비스는 Pod중에서 label 값이 run: my-nginx 인 pod쪽으로 서비스 합니다.

2. Service Object 의 특징

  • 서비스 타입 종류
    • Cluster IP
    • NodePort
    • LoadBalancer
  • Label Selector 통해서 Pod 타겟팅 + 로드밸런싱
  • Service yaml 파일에 기술된 name로 쿠버네티스 클러스터상에 DNS를 생성할 수 있습니다.

2-1. 서비스 타입

  1. ClusterIP : 쿠버네티스의 디폴트 설정으로 외부에서 접근가능한 IP를 할당받지 않기 때문에 Cluster내에서만 해당 서비스를 노출할 때 사용되는 Type
  2. NodePort : 해당 서비스를 외부로 노출시키고자 할 때 사용되는 Service Type으로 외부에 Node IP와 Port를 노출시키는 것으로 아래 그림과 같이 쿠버네티스 클러스터 상에 있는 모든 노드(VM)에 대해서 노출 시킵니다.

  1. LoadBalancer : 클라우드상에 존재하는 LoadBalancer에 연결하고자 할 때 사용되는 Service Type으로 LoadBalancer의 외부 External IP를 통해 접근이 가능합니다.

2-2. 서비스 네임 : DNS

Kubernetes는 자체 DNS서버를 가지고 있어 클러스터 내부에서만 사용가능한 DNS를 설정해서 사용할 수 있습니다. 이것은 Kubernetes상에서 통신할때 IP기반이 아닌 DNS를 통해 연결할 수 있음을 뜻하며 아래 그림과 같이 Pod에서 다른 Pod의 서비스를 연결할때 사용됩니다.

3. Ingress

Ingress는 Kubernetes v1.1 추가된 기능으로 NodePortLoadBalancer 와 마찬가지로 애플리케이션의 Service를 외부로 노출할때 사용되는 리소스입니다.

외부에서 들어온 HTTP와 HTTPS 트래픽을 ingress resouce를 생성하여 Cluster내부의 Service로 L7영역에서 라우팅하며 로드밸런싱, TLS, 도메인 기반의 Virtual Hosting을 제공합니다.

이러한 기능은 NodePort로 서비스를 노출하는 것에 비해 외부의 서비스를 보다 손쉽게 관리할 수 있도록해줍니다.

Ingress는 실질적인 라우팅 기능을 제공하는 Ingress Controller와 Ingress 리소스로 구성할 수 있는데, ingress 리소스는 외부의 URLs을 Cluster 내부의 Service로 라우팅하는 rule이 정의되어 있으며, Ingress Controller에는 다양한 구현체가 존재하며, 여기서는 nginx ingress controller를 설치해 실습해 보도록하겠습니다.

3-1. Single Service Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: single-ingress
spec:
  backend:
    serviceName: my-nginx-svc
    servicePort: 80
root@master:/lab/service/ingress# kubectl get ingress
NAME             HOSTS   ADDRESS         PORTS   AGE
single-ingress   *       192.168.1.240   80      2m17s
root@master:/lab/service/ingress# curl http://192.168.1.240



Welcome to nginx!



Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required. For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com. Thank you for using nginx.

4. 실습

앞서 이야기했던 Service 들에 대해서 개별적으로 실습해보는 내용들을 정리해보겠습니다. 우선 아래와 같이 폴더 구조를 생성하였고, 각 타입에 맞추어 podserivce를 생성하여 실습을 했습니다.

lab
 └── service
     │
     ├── clusterip
     │   ├── nginx-pod.yaml
     │   └── nginx-svc.yaml
     │
     ├── loadbalancer
     │   ├── nginx-pod.yaml
     │   └── nginx-svc.yaml
     │
     └── nodeport
         ├── nginx-pod.yaml
         └── nginx-svc.yaml

# pod & service 배포
# cd /lab/sercie/{servicetype폴더}
# kubectl apply -f .

4-1. Cluster IP

  • 파드 생성하기
root@master:~# gedit /lab/service/clusterip/nginx-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-nginx
  name: my-nginx-pod
  namespace: default
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: my-nginx-container
    ports:
    - containerPort: 80
      protocol: TCP

  • 서비스 생성하기
root@master:~# kubectl apply -f /lab/service/clusterip

  • 결과 확인

Service를 조회해보면 Cluster 내부에서만 사용가능한 Cluster IP가 할당된 것을 확인 할 수 있으며, 클러스터에서 curl 명령을 통해 접근가능한 것을 확인 할 수 있습니다.

root@master:/lab# kubectl get svc -o wide
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
kubernetes     ClusterIP   172.168.1.1             443/TCP   80m   
my-nginx-svc   ClusterIP   172.168.1.240           80/TCP    74m   run=my-nginx

root@master:/lab# kubectl describe svc my-nginx-svc
Name:              my-nginx-svc
Namespace:         default
Labels:            run=my-nginx
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"run":"my-nginx"},"name":"my-nginx-svc","namespace":"default"},...
Selector:          run=my-nginx
Type:              ClusterIP
IP:                172.168.1.240        # ClusterIP
Port:                80/TCP      # Cluster Port
TargetPort:        80/TCP               # Container Port
Endpoints:         10.32.0.5:80         # Container IP
Session Affinity:  None
  • 파드 DNS
[ root@curl-5cc7b478b6-rjq5d:/ ]$ nslookup my-nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      my-nginx-svc
Address 1: 10.101.62.208 my-nginx-svc.default.svc.cluster.local

[ root@curl-5cc7b478b6-kb8w8:/ ]$ curl my-nginx-svc.default.svc.cluster.local

이러한 내부 DNS로 아래 그림과 같이 Pod에서 다른 서비스 또는 다른 Pod로 통신이 가능합니다.

  • Namespaces and DNS

Service Object를 생성하면 해당 Service의 name으로 를 포함해 아래와 같은 규칙을 가진 DNS가 cluster 내에 생성됩니다. 이것은 어떤 container(pod)에서 해당 service를 DNS로 호출하는 경우에 개발계, 운영계 등과 같이 multiful namespace를 구성했을때 동일한 설정의 구성을 가능하게 합니다. 이것은 만약 다른 namespace 예를 들면 개발계에서 운영계의 Service를 호출하고자 할때는 FQDN을 사용해야 한다는 뜻입니다.

..svc.cluster.local 

4-2. NodePort

  • 파드 생성하기
root@master:~# gedit /lab/service/nodeport/nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-nginx
  name: my-nginx-pod
  namespace: default
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: my-nginx-container
    ports:
    - containerPort: 80
      protocol: TCP

  • 서비스 생성하기
# gedit /lab/service/nodeport/nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    run: my-nginx
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    run: my-nginx
kubectl apply -f /lab/service/nodeport/
  • 결과 확인

NodePort로 service를 생성하게 되면 자동으로 3XXXX대의 포트를 확인 할 수 있습니다. 이 Port가 모든 VM에 노출된 Node Port이고 Cluster 외부인 어느 VM에서나 접근이 가능합니다.

root@master:/lab# kubectl get svc
NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
my-nginx-svc   NodePort    172.168.1.240           8080:31331/TCP   140m


root@master:/lab# kubectl describe svc my-nginx-svc
Name:                     my-nginx-svc
Namespace:                default
Labels:                   run=my-nginx
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"run":"my-nginx"},"name":"my-nginx-svc","namespace":"default"},...
Selector:                 run=my-nginx
Type:                     NodePort
IP:                       172.168.1.240       # Cluster IP
Port:                       8080/TCP   # Cluster Port
TargetPort:               80/TCP              # Container Port
NodePort:                   31331/TCP  # Node Port
Endpoints:                10.32.0.5:80        # Container IP, Port
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   

> VM IP로 접근
# curl localhost:31331

> Mater, Node 등 모든 node VM내의 Firefox에서 아래 url로 접근가능
http://localhost:31331

4-3. LoadBalancer

  • 파드 생성하기
root@master:~# gedit /lab/service/loadbalancer/nginx-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-nginx
  name: my-nginx-pod
  namespace: default
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: my-nginx-container
    ports:
    - containerPort: 80
      protocol: TCP

  • 서비스 생성하기
# gedit /lab/service/loadbalancer/nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    run: my-nginx
spec:
  type: LoadBalancer
  ports:
  - port: 3000
    targetPort: 80
    protocol: TCP
  selector:
    run: my-nginx
kubectl apply -f /lab/service/loadbalancer
  • 결과 확인

VM상에 가상으로 설치한 loadbalancer에 서비스가 매핑된것을 확인 할 수 있습니다.

가상으로 설치한 loadbalancer의 IP는 192.168.1.240 이며, Cluster상에서 해당IP로 nginx 서비스에 접근이 가능합니다.(crul http://192.168.1.240:8080), 이 IP는 실제 클라우드 상에서는 클라우드 벤더가 제공하는 로드밸런서 장비의 외부로 노출된 공인IP입니다.

root@master:/lab/service/loadbalancer# kubectl get svc
NAME           TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
kubernetes     ClusterIP      172.168.1.1               443/TCP          7m1s
my-nginx-svc   LoadBalancer   172.168.1.240   192.168.1.240   3000:30947/TCP   30s

root@master:/lab/service/loadbalancer# kubectl describe svc my-nginx-svc
Name:                     my-nginx-svc
Namespace:                default
Labels:                   run=my-nginx
Annotations:              kubectl.kubernetes.io/last-applied-configuration:
                            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"run":"my-nginx"},"name":"my-nginx-svc","namespace":"default"},...
Selector:                 run=my-nginx
Type:                     LoadBalancer
IP:                       172.168.1.240
LoadBalancer Ingress:     192.168.1.240
Port:                       3000/TCP
TargetPort:               80/TCP
NodePort:                   30947/TCP
Endpoints:                10.32.0.5:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason       Age   From                Message
  ----    ------       ----  ----                -------
  Normal  IPAllocated  44s   metallb-controller  Assigned IP "192.168.1.240"

root@master:/lab/service/loadbalancer# curl http://192.168.1.240:3000



Welcome to nginx!



  • 외부 네임 생성하기

여기서는 추가적으로 외부에 노출되는 name에 대해서 정리했습니다.

# gedit /lab/service/external/external-svc.yaml
kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  type: ExternalName
  externalName: www.github.com
  ports:
  - port: 80

오브젝트 생성

kubectl apply -f /lab/service/external/external-svc.yaml

5. 마치며..

필자가 쿠버네티스의 개념에 대해서 정리를 하면서 한개씩 실습을 진행했는데, 위의 내용중 Service의 유형에 대해서 시도해보다가, NodePort만으로 실습을 진행했습니다.

필자가 원하는 방향은 외부에 노출되는 port에 대해서는 fix시켜서 지정을 하고싶어, LoadBalancer타입으로 해봤으나, External-IPPending상태가 지속되면서 연결이 안되었습니다.

또한, Ingress layer를 service 앞단에 연결하였으나, 역시 동작하지 않았습니다.
이부분에 대해서 현재 정리중이며, 위의 내용을 보완해서 정리하도록 하겠습니다.

워니즈 블로그
워니즈 깃헙

2 Replies to “[Kubernetes] 쿠버네티스 Service 란?”

  1. “필자가 원하는 방향은 외부에 노출되는 port에 대해서는 fix시켜서 지정을 하고싶어, LoadBalancer타입으로 해봤으나, External-IP가 Pending상태가 지속되면서 연결이 안되었습니다.
    또한, Ingress layer를 service 앞단에 연결하였으나, 역시 동작하지 않았습니다.”

    이것은 자체적으로 VM을 설치하거나 구성해서 그러는걸로 알고 있습니다.
    AWS나 GCP에서 하면 잘 되고요.

    1. 네, 맞습니다. LoadBalancer Type은 public cloud와 연계하여 사용할 때 생성이 됩니다. 아래는 공식 문서에 대한 내용입니다.

      LoadBalancer: 클라우드 공급자의 로드 밸런서를 사용하여 서비스를 외부에 노출시킨다. 외부 로드 밸런서가 라우팅되는 NodePort와 ClusterIP 서비스가 자동으로 생성된다.

      추가적으로 자체 구축한 경우 Metal lb를 통해서 LoadBalancer 타입의 서비스를 제공하는것도 가능합니다.
      https://docs.k0sproject.io/head/examples/metallb-loadbalancer/

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다