Service?
Service 개념
- Pod는 deployment, replicaset, statefulset 같은 controller에 의해 관리되기 때문에 새로 생겨나거나 없어지기도 하고 한 Node에만 떠있는 게 아니라 여러 Node를 옮겨다닐 수 있음
- Pod는 이렇듯 동적으로 변하여 고정된 endpoint로의 호출이 어려운데 (Pod의 IP,hostname이 변하니까 ) 이러한 이슈를 해결하기 위한 오브젝트가 Service임
- Client는 클러스터 안에서 Pod IP가 바뀌던 없어지건 새로 생기건 신경쓸 필요 없이 Service만 바라보면 고정된 endpoint로 접근이 가능함
- Service는 크게 아래와 같이 네가지 Type으로 나뉨
- ClusterIp : kubernets cluster 내부에서 사용하는 service. 외부에선 접근할 수 없음
- LoadBalancer : 토클,aws,gcp 등 퍼블릭 클라우드 서비스를 이용할 때 사용가능한 type으로 loadbalancer의 IP를 이용하여 외부에서 접근가능함
- NodePort : kubernetes cluster의 각 노드의 지정된 port를 service에 할당함. node의 port를 이용하기 때문에 외부에서도 접근가능함
- ExternalName : kubernetes cluster 내부에서 외부로 접근하는 경우 사용, Service를 ExternalName 으로 설정하여 CNAME을 타고 외부로 접근함
- 이 글에서 다루는 redis-cluster 에서는 ClusterIP type의 service를 사용하고 있음 ( DB는 내부통신만 하면 되니까)
Service 사용현황
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kimdubi-test-redis-cluster ClusterIP 10.254.8.60 <none> 6379/TCP 6d
kimdubi-test-redis-cluster-headless ClusterIP None <none> 6379/TCP,16379/TCP 6d
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 6d1h
- kubernetes cluster 내부에서 Pod 간 연결을 위해 사용하는 ClusterIP type의 kimdubi-test-redis-cluster 라는 이름의 service
- ClusterIP type이지만 IP가 설정되지 않은 kimdubi-test-redis-cluster-headless 라는 이름의 service, headless service라고 함
- 두개의 service가 생성되었지만 실제로는 kimdubi-test-redis-cluster-headless 서비스가 사용됨
headless service란?
- kimdubi-test-redis-cluster 같은 보통의 service는 받은 요청을 매핑된 Pod들에게 loadbalancing 형태로 뿌려주는데 이는 stateless 한 web server 처럼, 어떤 web server로 요청이 가도 동일한 결과를 내는 구조에서 의미가 있음
- DB처럼 Master / Slave 같은 stateful 한 구성에서는 loadbalancing 형태로 뿌려주는 게 아니라 Master 인지 Slave인지 파악하여 특정한 Pod에 요청을 뿌려줘야함
- 이처럼 loadbalancing이 필요없고 client 에서 모든 Pod에 접근해야하는 구성에서는 headless service를 사용하며 아래와 같은 특징이 있음
- headless service는 IP 대신 dns 를 가짐
- headless service의 dns에 대해 nslookup을 수행하면 binding 된 모든 Pod들의 IP를 return 함
- Client는 return 받은 모든 Pod의 IP를 통해 원하는 Pod 에 직접 접근할 수 있음
# nslookup kimdubi-test-redis-cluster-headless
Server: 10.254.0.10
Address: 10.254.0.10#53
Name: kimdubi-test-redis-cluster-headless.default.svc.cluster.local
Address: 10.100.71.3
Name: kimdubi-test-redis-cluster-headless.default.svc.cluster.local
Address: 10.100.14.7
Name: kimdubi-test-redis-cluster-headless.default.svc.cluster.local
Address: 10.100.79.12
Name: kimdubi-test-redis-cluster-headless.default.svc.cluster.local
Address: 10.100.14.8
Name: kimdubi-test-redis-cluster-headless.default.svc.cluster.local
Address: 10.100.79.11
Name: kimdubi-test-redis-cluster-headless.default.svc.cluster.local
Address: 10.100.71.4
=> kimdubi-test-redis-cluster-headless service에 대해 nslookup 수행 이 service에 binding 된 모든 Pod의 IP를 return 받음
Service 생성 template을 살펴보자
kimdubi-test-redis-cluster
$ kubectl get service kimdubi-test-redis-cluster -o yaml
apiVersion: v1
kind: Service
metadata:
annotations:
meta.helm.sh/release-name: kimdubi-test
meta.helm.sh/release-namespace: default
creationTimestamp: "2021-02-21T07:33:55Z"
labels:
app.kubernetes.io/instance: kimdubi-test
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: redis-cluster
helm.sh/chart: redis-cluster-4.3.0
name: kimdubi-test-redis-cluster
namespace: default
resourceVersion: "24613"
selfLink: /api/v1/namespaces/default/services/kimdubi-test-redis-cluster
uid: c7a73d74-a532-4689-8d9e-45287df887b3
spec:
clusterIP: 10.254.8.60
ports:
- name: tcp-redis
port: 6379
protocol: TCP
targetPort: tcp-redis
selector:
app.kubernetes.io/instance: kimdubi-test
app.kubernetes.io/name: redis-cluster
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
.spec.clusterIP
- clusterIP type으로 생성된 service를 지정한 IP로 생성되도록 설정
- 이 service는 10.254.8.60 IP를 할당받게됨
.spec.ports[]
- 해당 서비스의 label selector 에 매치되는 Pod의 특정 Port (targetPort) 를 service의 6379 port에 매핑시킴
.spec.selector
- 해당 service가 연결해야하는 대상 Pod의 label 조건
- kimdubi-test , redis-cluster 의 label이 달린 Pod는 이 service를 통해 접근할 수 있음
.spec.sessionAffinity
- 특정 클라이언트가 특정 Pod에 붙어야할 때 사용하는 설정
.spec.type
- service의 type으로 default는 ClusterIP
kimdubi-test-redis-cluster-headless
$ kubectl get service kimdubi-test-redis-cluster-headless -o yaml
apiVersion: v1
kind: Service
metadata:
annotations:
meta.helm.sh/release-name: kimdubi-test
meta.helm.sh/release-namespace: default
creationTimestamp: "2021-02-21T07:33:55Z"
labels:
app.kubernetes.io/instance: kimdubi-test
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: redis-cluster
helm.sh/chart: redis-cluster-4.3.0
name: kimdubi-test-redis-cluster-headless
namespace: default
resourceVersion: "24611"
selfLink: /api/v1/namespaces/default/services/kimdubi-test-redis-cluster-headless
uid: eb2da26a-9264-46a7-91f1-7a3cfa241889
spec:
clusterIP: None
ports:
- name: tcp-redis
port: 6379
protocol: TCP
targetPort: tcp-redis
- name: tcp-redis-bus
port: 16379
protocol: TCP
targetPort: tcp-redis-bus
publishNotReadyAddresses: true
selector:
app.kubernetes.io/instance: kimdubi-test
app.kubernetes.io/name: redis-cluster
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
.spec.clusterIP
- 위에서 본 kimdubi-test-redis-cluster service와는 다르게 clusterIP 값이 None 으로 설정하여 headless service를 생성함
.spec.ports[]
- 해당 서비스의 label selector 에 매치되는 Pod의 특정 Port (targetPort) 를 service의 6379 port에 매핑시킴
.spec.selector
- 해당 service가 연결해야하는 대상 Pod의 label 조건
- kimdubi-test , redis-cluster 의 label이 달린 Pod는 이 service를 통해 접근할 수 있음