Kubernetes Service

What is Service??

service_structure

위와 같이 여러 개의 node에 동일한 webserver pod가 생성되서 실행되는데, pod가 제각각이므로 각각의 webserver가 가지는 ip는 달라지게 된다. 하지만, 사용자 입장에서는 어떠한 webserver에 접속하면 될지 모르기 때문에, 이에 대해서 서비스는 해당 IP들을 묶어서 하나의 가상 ip로 관리해서 pod에 대한 단일 진입점을 제공한다. 쉽게 말해, Load Balancing을 기능을 통해 여러 서버에 대해 균등하게 실행될 수 있도록 하는 것이다.

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webui
spec:
  replicas: 3
  selector:
    matchLabels:
      app: webui
  template:
    metadata: nginx-pod
    labels:
      app: webui
    spec:
      containers:
        -name: nginx-container
        version: nginx:1.14

Service

apiVersion: v1
kind: Service
metadata:
  name: webui-svc
spec:
  type: ClusterIP
  clusterIP: 10.96.100.100
  selector:
    app: webui
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

deployment으로 생성된 3개의 웹서버에 대해서 service는 clusterIP를 통한 단일 진입점을 제공한다. 그러면 clusterIP를 통해 요청을 수행하게 되면 각각의 서버에 대해서 균등하게 작업을 요청할 수 있다.

Service Types

아래의 Service에 대한 예제를 확인하기 위해 위에서 정의한 deployment을 통해 웹서버 3개를 실행하도록 한다.

toojey-master@toojeymaster-VirtualBox:~/kubernetes$ kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP          NODE                     NOMINATED NODE   READINESS GATES
deploy-nginx-5cfbcf5f65-7ks45   1/1     Running   0          5m25s   10.36.0.2   toojeynode2-virtualbox   <none>           <none>
deploy-nginx-5cfbcf5f65-9fkrf   1/1     Running   0          5m25s   10.44.0.2   toojeynode1-virtualbox   <none>           <none>
deploy-nginx-5cfbcf5f65-l2lsf   1/1     Running   0          5m25s   10.36.0.1   toojeynode2-virtualbox   <none>           <none>

ClusterIp

service_clusterip

위에서 설명한대로, clusterIP를 이용해서 각각의 node를 연결하는 시켜준다. selector의 label을 활용해서 동일한 pod를 그룹으로 만들어서 하나의 clusterIP로 관리한다, 보통 clusterIP는 10.96.0.0./12 대역에서 기본적으로 할당되는데, 필요하면 고정적으로 설정해서 사용할 수 있다.

Practice

apiVersion: v1
kind: Service
metadata:
  name: clusterip-service
spec:
  type: ClusterIP
  clusterIP: 10.100.100.100
  selector:
    app: webui
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

clusterip_describe

위의 clusterip service를 확인해보면 cluster ip 10.100.100.100에 대해서 위의 node들이 연결된 상태이다.

실제로 load balancing 하게, 랜덤하게 접근하지 테스트하기 위해 위의 웹서버들에 대한 홈페이지를 조작한 후 테스트를 진행해보자 –> homepage 변경은 직접 해당 container에 접근해서 index.html을 수정하면 된다.

아래와 같이 Random 하게 접근하는 것을 확인할 수 있다.

toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #1
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #2
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #2
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #2
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.100.100
Website #2

deployment은 scaling을 진행하는데, 그렇게 되면 유동적으로 clusterip에 연결된 node 개수가 자동적으로 조정된다.

NodePort

service_nodeport

각각의 node에 대해서, 특정 port을 통일해서 node + port로 접속하게 되면, 연결되어 있는 pod 중에 임의로 선택해서 요청을 보내도록 한다. Node 단위의 Load Balancing을 수행한다.

Practice

apiVersion: v1
kind: Service
metadata:
  name: nodeport-service
spec:
  type: NodePort
  clusterIP: 10.100.100.200
  selector:
    app: webui
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30200
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ kubectl get service nodeport-service 
NAME               TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
nodeport-service   NodePort   10.100.100.200   <none>        80:30200/TCP   21s

Nodeport를 통해 노드 IP에 대한 port을 열어놓게 되면 아래와 같이 node IP를 통해 접속했을 때, 웹서버 중에서 임의로 선택되어서 접속하는 것이 가능하다

toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.0.102:30200
Website #1
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.0.104:30200
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.0.102:30200
Website #1
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.0.104:30200
Website #3
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.0.102:30200
Website #1
toojey-master@toojeymaster-VirtualBox:~/kubernetes$ curl 10.100.0.104:30200
Website #2

외부에서의 접속을 허용하기 위해 NodePort을 활용한다.

LoadBalancer

service_loadbalancer

clusterip, nodepart 방식에 추가록 LB를 구성해서 LB의 port와 Nodeport을 연결해서 LB를 통한 Pod로의 요청을 진행한다. 단, AWS, GoogleCloudPlatform과 같은 플랫폼에서만 활용가능하다.

외부의 Load Balancer에서 내부의 Node Port에 대해 대응되서 연결을 수행할 수 있다.

Practice

apiVersion: v1
kind: Service
metadata:
  name: loadbalancer-service
spec:
  type: LoadBalancer
  selector:
    app: webui
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

아래와 같이 Load Balancer type의 service가 생성되며, 기존의 생성한 nodeport와 달리 External IP 부분에 값이 들어가는 것을 확인할 수 있다.(현재는 LB 장비가 없어서 pending 상태로 설정된다.) loadbalancer_service

ExternalName

service_externalname

cluster안에서 외부에 접속 시 사용할 도메인을 등록해서 사용할 수 있다. 그렇게 되면 클래스 도메인이 실제 외부 도메인으로 치환되어 동작하게 된다.

클러스터 내에서 pod에 대한 DNS 서비스를 제공한다고 생각하면 된다. 아래의 동작과정을 통해 자세히 알아보자

Practice

apiVersion: v1
kind: Service
metadata:
  name: externalname-svc
spec:
  type: ExternalName
  externalName: google.com

위와 같이 externalname을 구성하고 난뒤, extername-svc.default.svc.cluster.local 으로 접속하게 되면 아래와 같이 실제 google.com 홈페이지에 접속하는 것을 확인할 수 있다.

value description
externalname-svc external name의 서비스 이름
default.svc.cluster.local kubernetes의 default domain

externalname-service

Headless Service

headless_service

cluster ip가 없는 서비스를 의미한다. 다만, pod들에 대한 endpoint로 DNS record가 생성되어, control plane의 coreDNS에 저장된다. 이에 따라, Pod의 Endpoint에 대한 DNS resolving Service를 지원한다.

Practice

apiVersion: v1
kind: Service
metadata:
  name: headless-service
spec:
  type: ClusterIp
  clusterIP: None
  selector:
    app: webui
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

위와 같이 clusterIp를 None으로 설정하게 되면 headless-service로 생성되게 된다. 아래의 결과를 확인해보면 endpoint는 묶여있지만, clusterIp는 설정되지 않은 것을 확인할 수 있다.

headless-service_description

하지만 headless service의 핵심 기능은 coreDNS을 통한 DNS resolving service를 제공한다는 점이다.

^Ctoojey-master@toojeymaster-VirtualBox:~/kubernetes$ kubectl run testpod --image=centos:7 -it /bin/bash
If you dont see a command prompt, try pressing enter.
[root@testpod /]cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
[root@testpod /]curl 10-36-0-2.default.pod.cluster.local
Website #1

pod를 하나 생성해서, resolv.conf을 통해 DNS 서버를 확인해보면 실제 control plane의 coreDNS IP에 대해 알아낼 수 있다.

이에 대해, pod-ip.default.pod.cluster.local을 요청을 보내게 되면 실제 해당 pod에 접속을 진행하게 된다. 위의 경우는 node1에 접속한 결과이다.

Kube Proxy

Kubernetes Service의 Backend을 구현하는 역할을 수행한다.

아래의 get pods 결과를 보면 총 3개의 kube-proxy가 동작하는데,모든 노드(master,worker1,worker2)에 대해서 동작하게 되며, cluster IP, nodeport와 같은 service를 요청하게 되면 kube-proxy가 동작하여 각각의 노드에 대한 IP table rules을 생성하게 된다.

kubeproxy

아래의 그림을 확인해보면 pod에 대해 ip table이 생성되는 것을 확인할 수 있다.

kubeproxy_iptables

References

영상

따배쿠

공식문서

Docker 공식문서 kubernetes 공식문서

블로그

blog1

댓글남기기