본문 바로가기
2023~/쿠버네티스 인 액션

Ch05 서비스: 클라이언트가 파드를 검색하고 통신을 가능하게 함

by 경아ㅏ 2024. 10. 13.

 

5.1 서비스 소개

 

서비스가 필요한 이유


파드는 노드에 스케줄링 된 뒤 고유의 IP 주소를 할당 받기 때문에 클라이언트는 파드의 정확한 IP 주소를 미리 알 수 없을 뿐더러, 미리 안다고 하더라도 노드 장애, 스케일링 때마다 달라지는 파드들의 개별 IP 목록을 계속 신경 쓸 수 없음

✅ 동일한 서비스를 제공하는 파드에 대해 고정 IP 를 할당하여 클라이언트가 해당 IP::포트 에 연결할 수 있도록 함 (서비스 리소스)



서비스 생성

 

0) 특정 라벨 셀렉터를 가지는 서비스 yaml 작성

 

서비스 IP: 80 번 포트를 app=kubia 라벨을 갖는 파드의 8080 포트에 연결하겠다는 의미

 

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: kubia

 

 

1) kubia 서비스 CLUSTER-IP 확인

 

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubia        ClusterIP   xxx.xx.xxx.xxx   <none>        80/TCP    47m

 

 

2) app=kubia, 8080 포트를 수신하는 컨테이너가 있는 파드를 레플리카 셋으로 생성

NAME          READY   STATUS    RESTARTS   AGE
kubia-bxspg   1/1     Running   0          35m
kubia-pwr7t   1/1     Running   0          35m
kubia-xrjsj   1/1     Running   0          35m

 

 

3) 한 파드 내부에서 (kubia 서비스의 클러스터 IP) 요청

요청할 때마다 서비스가 app=kubia 라벨이 붙은 파드 중 하나를 선택해서 요청을 수행(요청할 때마다 접근하는 파드가 다름)

 

kubectl exec kubia-bxspg -- curl -s http://xxx.xx.xxx.xxx

 

You've hit kubia-xrjsj

You've hit kubia-bxspg

You've hit kubia-pwr7t 

...

 

+ 서비스의 sessionAffinity 를 ClientIP 로 설정하면 서비스에 대한 요청시 동일한 파드로 요청

+ 서비스에 80번 포트, 433 포트 등 멀티 포트를 파드의 멀티 포트에 연결 가능


5.2 서비스 검색

 

클라이언트 파드에서 서비스의 클러스터 IP 와 포트 정보 알아내는 방법


1) 환경변수를 통한 서비스 검색

서비스 생성 시점 이후 파드 생성 시 파드의 환경 변수 목록에 서비스의 클러스터 IP 와 포트 정보 초기화

kubectl exec kubia-bxspg -- env

 

 

KUBIA_SERVICE_HOST=xxx.xx.xxx.xxx

KUBIA_SERVICE_PORT=80


2) FQDN을 통한 서비스 연결

 

쿠버네티스는 자체 DNS 서비스/파드 서버를 가지며 클러스터 IP 를 대신 FQDN 로 요청 가능

(파드 내부에 bash 실행하여 /etc.resolv.conf 파일을 살펴보면 nameserver 값과 kube-dns 의 클러스터 IP 값 일치)

 

* FQDN: 서비스이름.네임스페이스.클러스터 도메인 접미사

 

kubectl get svc --namespace=kube-system

NAME       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   yyy.yy.y.yy   <none>        53/UDP,53/TCP,9153/TCP   17d

 

kubectl exec -it kubia-bxspg -- bash

root@kubia-bxspg:/# cat /etc/resolv.conf
nameserver yyyy.yy.y.yy // 이 값이 DNS 서비스 클러스터 IP 와 일치
search default.svc.cluster.local svc.cluster.local ...

root@kubia-bxspg:/# curl http://kubia.default.svc.cluster.local // FQDN 으로 요청
You've hit kubia-pwr7t



5.2 클러스터 외부에 있는 서비스 연결

클러스터 내부 파드가 아닌 외부의 ip:포트 와 연결하는 서비스를 만드는 방법

엔드포인트

서비스 yaml 에 라벨 셀렉터를 기술하면 해당 정보를 바탕으로 파드IP:포트에 대한 정보가 엔드포인트 리소스에 저장됨

 

kubectl describe svc kubia

Name:                     kubia
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=kubia
Type:                     ClusterIP
...
IP:                       xxx.xx.xxx.xxx
IPs:                      xxx.xx.xxx.xxx
Port:                     <unset>  80/TCP
TargetPort:               8080/TCP
Endpoints:                xxx.xx.x.xx:8080,xxx.xx.x.xx:8080,xxx.xx.x.xx:8080 // 엔드포인트 파드IP:8080
Session Affinity:         None
Internal Traffic Policy:  Cluster
Events:                   <none>

 

kubectl get endpoints

NAME         ENDPOINTS                                            AGE
kubia        파드IP:포트...                                         28h

 

 

엔드포인트 수동 구성 / 외부 서비스를 위한 별칭 생성

라벨셀렉터를 지정하지 않고 서비스와 이름이 동일한 엔드포인트 리소스를 만들어 외부 서버와 연결 가능
ExternalName type 으로 외부 공개 API 도메인 이름을 사용하여 서비스 생성 가능


5.3 외부 클라이언트에 서비스 노출

 

서비스를 외부로 노출하여 외부 클라이언트가 액세스 할 수 있도록 하는 방법


1) 노드포트 서비스 사용


모든 노드에 특정 번호를 가진 포트를 할당, 해당 포트로 수신된 트래픽을 서비스로 전달
(서비스의 클러스터IP:포트 번호로 서비스에 접근도 가능하지만 노드IP:노드포트 로 액세스도 가능하다)

apiVersion: v1
kind: Service
metadata:
  name: kubia-nodeport
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30123
  selector:
    app: kubia

 

- 노드IP:30123 연결 가능
- 클러스터IP:80 연결 가능

 


2) 외부 로드밸런서로 서비스 노출

특정 노트IP:포트 로만 접근하는 경우 해당 노드가 죽었을 때 대처할 수 있는 방법이 없으므로 보통 상위 단계에 로드밸런서를 사용
(type을 LoadBalancer 로 서비스 yaml 파일을 작성하면 로드밸런서 IP:포트로 접속시 할당된 노드:노드포트 로 연결)

 


3) 외부 연결의 특성 이해

 

서비스 스펙에 externalTrafficPolicy: true 를 설정하면 특정 노드 포트로 트래픽이 수신되었을 때 해당 노드에서 실행되고 있는 파드로만 연결(네트워크 홉 방지 차원), 그렇지만 이렇게 하면 파드간 부하가 고르지 않을 수 있다는 문제가 있음(e.g 원래라면 모든 파드에 33% 씩 부하가 분배될 상황인데, 노드1 에 파드1개, 노드2에 파드 2개이고 로드밸런서로 노드를 배정한다면 각각 파드는 50%, 25%, 25% 씩 부하를 얻게 됨)

클러스터 내 클라이언트가 서비스로 연결할 때 서비스의 파드는 요청 파드의 IP 주소를 알 수 있으나, 노드포트로 연결을 수신하면 소스 네트워크 주소 변환(SNAT) 과정을 거치면서 패킷의 소스 IP가 변경되고 수신한 파드 내에서는 원래 IP 주소를 알 수 없음


댓글