Headless Service
Headless 서비스는 서비스를 이용한 로드밸런싱 기능이 지원되지 않는다. 서비스를 거치지 않고 파드에 직접 접근한다.
서비스 생성 시 .spec.clusterIP 필드 값을 None으로 설정하면 클러스터 IP가 없는 서비스를 만들 수 있다.
❯ cat headless-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: my-headless-service
namespace: service-test
spec:
clusterIP: None
selector:
app: my-app
ports:
- port: 80
targetPort: 80
❯ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-headless-service ClusterIP None <none> 80/TCP 3s
그럼 이런 기능이 언제/왜 필요하냐?
- 기본 서비스와 연결된 파드에는 서비스가 LB 역할을 한다. 만약 3개의 파드가 연결돼있으면 3개의 파드가 돌아가며 랜덤으로 통신한다
- 그러나 데이터베이스와 같이 master, slave 구조가 존재하는 경우에는 랜덤으로 통신이 되면 안되고 모든 파드 주소를 알고 있거나 master를 알고있거나 해야하므로 특정 파드에 선택적으로 통신을 할 수 있게 해야한다.
- 그렇기 때문에 주로 statefulset 리소스(스토리지와 관련된 서비스를 띄울 경우 사용하는 쿠버네티스 리소스 종류)를 사용해야하는 경우 함께 사용된다.
[replicaset 리소스 배포]
❯ cat myweb-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: myweb-rs
spec:
replicas: 3
selector:
matchLabels:
app: web
env: dev
template:
metadata:
labels:
app: web
env: dev
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
ports:
- containerPort: 8080
protocol: TCP
❯ kubectl apply -f myweb-rs.yaml
replicaset/myweb-rs created
❯ kubectl get pods
NAME READY STATUS RESTARTS AGE
myweb-rs-5ltrj 1/1 Running 0 7s
myweb-rs-fldm7 1/1 Running 0 7s
myweb-rs-jtdll 1/1 Running 0 7s
[service, headless service 배포]
❯ cat myweb-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: myweb-svc
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 8080
❯ cat myweb-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: myweb-svc-headless
spec:
type: ClusterIP
clusterIP: None # <-- Headless Service
selector:
app: web
ports:
- port: 80
targetPort: 8080
❯ kubectl apply -f myweb-svc.yaml
service/myweb-svc created
❯ kubectl apply -f myweb-svc-headless.yaml
service/myweb-svc-headless created
❯ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myweb-svc ClusterIP 10.96.221.72 <none> 80/TCP 33s
myweb-svc-headless ClusterIP None <none> 80/TCP 30s
[테스트를 위한 파드 생성 및 접속 후 DNS 질의]
쿠버네티스는 파드 IP 리스트를 알려주는 방법을 DNS Lookup을 통해 제공한다.
보통은 DNS Lookup을 수행하면 서비스의 ClusterIP 하나를 반환한다. 그러나 Headless 서비스의 경우 소속된 파드 IP 주소 목록을 전부 반환한다.
❯ kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
If you don't see a command prompt, try pressing enter.
/ # host myweb-svc
myweb-svc.service-test.svc.cluster.local has address 10.96.221.72
/ # host myweb-svc-headless
myweb-svc-headless.service-test.svc.cluster.local has address 10.244.0.20
myweb-svc-headless.service-test.svc.cluster.local has address 10.244.0.19
myweb-svc-headless.service-test.svc.cluster.local has address 10.244.0.21
/ # host myweb-rs-5ltrj.myweb-svc-headless
Host myweb-rs-5ltrj.myweb-svc-headless not found: 3(NXDOMAIN) # => replicaset으로 만들어진 pod의 경우 <pod이름>.<서비스이름> 으로 DNS 질의 불가능
/ # host 10-244-0-20.myweb-svc-headless
10-244-0-20.myweb-svc-headless.service-test.svc.cluster.local has address 10.244.0.20
[statefulset 리소스 배포]
❯ cat myweb-sts.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myweb-sts
spec:
replicas: 3
serviceName: myweb-svc-headless
selector:
matchLabels:
app: web
env: dev
template:
metadata:
labels:
app: web
env: dev
spec:
containers:
- name: myweb
image: ghcr.io/c1t1d0s7/go-myweb
ports:
- containerPort: 8080
protocol: TCP
❯ kubectl apply -f myweb-sts.yaml
statefulset.apps/myweb-sts created
[테스트를 위한 파드 생성 및 접속 후 DNS 질의]
❯ kubectl run nettool -it --image ghcr.io/c1t1d0s7/network-multitool --rm
If you don't see a command prompt, try pressing enter.
/ # host myweb-sts-0.myweb-svc-headless
myweb-sts-0.myweb-svc-headless.service-test.svc.cluster.local has address 10.244.0.23 # => statefulset으로 만들어진 pod의 경우 <pod이름>.<서비스이름> 으로 DNS 질의 가능
ExternalName
외부에서 접근하기 위한 목적이 아닌 내부 파드가 외부 도메인에 쉽게 접근하기 위해 사용한다.
접속하기 위한 외부 도메인 주소가 바뀌더라도 coredns가 세팅해준 내부 접근 도메인은 그대로 유지할 수 있기 때문에 애플리케이션을 다시 작성하거나 빌드하지 않고 externalName에서 도메인만 변경해서 적용해주면 된다.
externalName 필드에 google.com을 넣을 후 서비스를 생성한다.
❯ cat external-name-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: my-external-service
namespace: service-test
spec:
type: ExternalName
externalName: google.com
❯ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-external-service ExternalName <none> google.com <none> 69m
서비스 도메인에 curl을 보내기 위한 테스트용 파드를 생성한다.
❯ cat external-name-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-externalname-pod
namespace: service-test
spec:
containers:
- name: curl-container
image: curlimages/curl:7.87.0
command: [ "sleep", "3600" ]
생성된 파드 내부에 들어가서 curl 명령어를 통해 서비스 도메인으로 curl을 날려주면 google에 대한 정보가 넘어오는 것을 확인할 수 있다.
❯ kubectl exec -it test-externalname-pod -- curl http://my-external-service.service-test.svc.cluster.local
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
<title>Error 404 (Not Found)!!1</title>
<style>
*{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
</style>
<a href=//www.google.com/><span id=logo aria-label=Google></span></a>
<p><b>404.</b> <ins>That’s an error.</ins>
<p>The requested URL <code>/</code> was not found on this server. <ins>That’s all we know.</ins>
Endpoint
서비스가 트래픽을 전달할 수 있는 실제 IP 주소와 포트의 목록을 관리한다.
파드가 생성되거나 삭제될 때 쿠버네티스 컨트롤러는 자동으로 해당 서비스와 연결된 Endpoint 를 업데이트한다.
이를 통해 서비스는 항상 최신의 파드 목록과 연결된다.
예를들어, 특정 서비스의 레이블과 일치하는 파드가 새로 생성되면 해당 파드의 IP 주소가 자동으로 Endpoint리소스에 추가된다.
$ kubectl get endpoints mongodb-headless
NAME ENDPOINTS AGE
mongodb-headless 10.0.0.1:27017,10.0.0.2:27017,10.0.0.3:27017 12d
$ kubectl get pods mongodb-0 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mongodb-0 1/1 Running 0 12d 10.0.0.1 worker1 <none> <none>
$ kubectl get pods mongodb-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mongodb-1 1/1 Running 0 12d 10.0.0.2 worker2 <none> <none>
$ kubectl get pods mongodb-2 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mongodb-2 1/1 Running 0 12d 10.0.0.3 worker3 <none> <none>
'클라우드 > Kubernetes(쿠버네티스)' 카테고리의 다른 글
[Kubernetes] Cilium (2) | 2024.09.17 |
---|---|
[Kubernetes] ArgoCD (0) | 2024.07.30 |
[쿠버네티스] 클러스터 구축 (0) | 2024.06.08 |
[kubernetes] kubernetes의 update 종류와 동작 방법 (apply, edit, patch, replace) (0) | 2023.08.18 |
[kubernetes] pod lifecycle (0) | 2023.08.10 |