서비스
서비스
외부와 접하는 단일 엔드포인트 뒤에 있는 클러스터에서 실행되는 애플리케이션을 노출시키며, 이는 워크로드가 여러 백엔드로 나뉘어 있는 경우에도 가능하다.
kubernetes.io
서비스 소개
🌱 서비스란?
- 디플로이먼트의 파드를 연결하고 포트를 외부에 노출하는 오브젝트
- 파드의 논리적 집합과 그것들에 접근할 수 있는 정책을 정의하는 추상적 개념
- 서비스 추상화의 Decoupling : 백엔드 세트를 구성하는 파드가 프론트엔드 세트를 구성하는 파드에 기능을 제공하는 상황을 가정해보자. 백엔드 세트를 구성하는 실제 파드는 변경될 수 있지만, 프론트엔드 클라이언트는 이를 인식할 필요 없이 의존성을 유지할 수 있다. (이거 의존성주입 아녀~)
🌱 서비스의 기능
- 여러개의 파드에 쉽게 접근할 수 있도록 고유한 도메인 부여
- 여러 파드에 접근할 때, 요청을 분산하는 로드 밸런서 기능 수행
- 클라우드 플랫폼의 로드 밸런서, 클러스터 노드 등을 통해 파드를 외부로 노출
🌱 서비스의 종류
- 서비스의 종류에 따라 파드에 접근할 수 있는 방법이 달라짐
- ClusterIp : 쿠버네티스 내부에서만 파드들에 접근할 때 사용
- NodePort : 포트를 클러스터의 모든 노드에 개방하여 외부에서 파드에 접근 가능
- LoadBalancer : 클라우드 플랫폼이 제공하는 로드 밸런서를 동적으로 프로비저닝해 파드에 연결하여 외부 개방, 실제 운영 환경에서 사용
ClusterIP : 내부 파드 연결
🌱 yaml 파일
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-clusterip
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
selector:
app: webserver
type: ClusterIP
- spec.selector : 이 서비스를 통해 접근 가능한 파드를 선택
- spec.ports.port : 서비스가 받는 내부 IP로 개방할 포트
- spec.ports.targetPort : 연결된 파드가 내부적으로 사용하는 포트
🌱 서비스 생성하고 내부 접속 테스트
- 서비스 생성 : kubectl apply -f hostname-svc-clusterip.yaml
- 서비스 목록 확인 : kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
**hostname-svc-clusterip ClusterIP 10.8.5.213 <none> 8080/TCP 12s**
kubernetes ClusterIP 10.8.0.1 <none> 443/TCP 36h
- 임시 파드 생성 : kubectl run -i --tty --rm debug --image=alicek106/ubuntu:curl --restart=Never -- bash
- 서비스 IP와 포트로 파드에 요청 전송 : curl 10.8.5.213:8080 --silent | grep Hello
- 서비스 이름으로 요청 전송(일반적) : curl hostname-svc-clusterip:8080 --silent | grep Hello
- 서비스와 연결된 여러 파드에 자동으로 요청이 분산된다
클러스터 내부에서 파드끼리 요청과 응답을 주고 받을 때는 ClusterIP 타입의 서비스가 이들을 중개한다. 같은 클러스터 안의 어떤 파드가 다른 파드를 연결하는 서비스의 내부 IP와 개방 포트로 요청을 보내면, 내부적으로 로드 밸런싱을 수행해서 응답을 처리한다.
NodePort
모든 노드의 동일한 포트를 개방한다. 외부에서는 노드 IP와 포트로 요청을 보낸다.
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-nodeport
spec:
ports:
- name: web-port
port: 8080
targetPort: 80
selector:
app: webserver
type: NodePort
- spec.ports.port : 서비스가 받는 내부 IP로 개방할 포트
- 노드의 포트는 랜덤으로 선택된다
🌱 노드의 포트 개방
NodePort 타입 서비스를 만들면 모든 노드에서 동일하게 접근할 수 있는 포트를 개방한다. 이때 포트는 랜덤하게 선택되었는데, 확인해보니 30144번이 개방되었다. 따라서 모든 노드에 대해 내부 IP 혹은 외부 IP의 30144번을 통해 파드에 접근할 수 있다.
- 임시 파드 생성 : kubectl run -i --tty --rm debug --image=alicek106/ubuntu:curl --restart=Never -- bash
- 요청 : curl 10.128.0.4:**30144** --slient | grep Hello
- GKE 방화별 설정 추가 : gcloud compute firewall-rules create temp-nodeport-svc --allow=tcp:32765
🌱 ClusterIP도 포함
NodePort 타입 서비스는 ClusterIP의 기능을 포함하고 있어서, NodePort로 만들면 서비스 내부 네트워크와 외부 네트워크 양쪽에서 접근할 수 있다.
LoadBalancer
서비스 생성과 함께 로드밸런서를 생성하여 파드와 연결한다. 모든 노드의 동일한 포트를 개방한다.
외부에서는 로드밸런서의 IP로 요청을 보낸다.
apiVersion: v1
kind: Service
metadata:
name: hostname-svc-nodeport
spec:
ports:
- name: web-port
port: 80
targetPort: 80
selector:
app: webserver
type: LoadBalancer
- spec.port : 로드 밸런서에 접근하기 위한 포트
🌱 로드밸런서의 IP와 포트로 파드 접근
- 서비스 생성과 동시에 로드 밸런서를 새롭게 생성해 파드와 연결한다.
- IP 확인 : kubectl get services → 34.171.151.96:80
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostname-svc-nodeport LoadBalancer 10.8.13.76 **34.171.151.96** 80:30144/TCP 19m
- 로드밸런서에 요청 보내기 : curl 34.171.151.96:80 --silent | grep Hello
minhwi@minhwiui-MacBookPro ~/kubernetes/chap6 curl 34.171.151.96:80 --silent | grep Hello
<p>Hello, hostname-deployment-**9664ffd7f-9958g**</p> </blockquote>
minhwi@minhwiui-MacBookPro ~/kubernetes/chap6 curl 34.171.151.96:80 --silent | grep Hello
<p>Hello, hostname-deployment-**9664ffd7f-plskp**</p> </blockquote>
minhwi@minhwiui-MacBookPro ~/kubernetes/chap6 curl 34.171.151.96:80 --silent | grep Hello
<p>Hello, hostname-deployment-9664ffd7f-9958g</p> </blockquote>
🌱 NodePort의 간접적인 사용
로드밸런서를 연결하더라도 모든 노드에 대해 동일한 포트가 연결되기 때문에 NodePort 기능을 사용할 수 있다. 위의 출력 결과에서 본 대로 30144번 포트로 접근할 수 있다.
- 임시 파드 생성 : kubectl run -i --tty --rm debug --image=alicek106/ubuntu:curl --restart=Never -- bash
- 요청 : curl 10.128.0.4:30144 --slient | grep Hello
LoadBalancer : externalTrafficPolicy 옵션
로드 밸런서 타입 서비스를 사용할 때 externalTrafficPolicy 옵션을 선택할 수 있다. externalTrafficPolicy는 어떤 노드의 포트를 개방할지 결정한다. 위에서 사용한 예제는 디폴트 옵션인 Cluster을 사용하여 모든 노드의 랜덤 포트를 개방한다.
🌱 externalTrafficPolicy 옵션
- Cluster : 모든 워커 노드의 동일한 랜덤 포트를 개방
- Local : 파드가 위치한 노드만 랜덤 포트 개방
kind: Service
# ..
spec:
externalTrafficPolicy: Local # Cluster(기본값)
🌱 Cluster 설정의 한계
외부 트래픽은 노드 중 하나로 보내지고, 그 노드에서 다시 파드 중 하나로 전달된다. 모든 노드의 랜덤 포트를 개방하면 노드에서 파드를 선택하는 과정에서 자신 파드가 아닌 다른 노드의 파드에 전달할 수도 있다. 이렇게 되면 불필요한 네트워크 hop이 발생하고, 클라이언트의 IP 주소가 보존되지 않는다.
🌱 Local 설정의 문제 해결
Local로 설정하면 파드가 위치한 노드만 랜덤한 포트를 개방한다. 로드밸런서는 파드가 위치한 노드로만 요청을 전달하고, 해당 노드 안에서만 요청이 분산된다. 따라서 네트워크 홉이 한 단계 적으며, 클라이언트 IP를 보존할 수 있다.
🌱 Local 설정의 한계
하지만 각 노드에 파드가 고르지 않게 스케줄링되는 경우, 요청이 고르게 분산되지 않는 문제가 있다. 즉 자원 활용률 측면에서 바람직하지 않다.
🌱 Cluster와 Local 중 무엇을 선택해야할까?
불필요한 네트워크 홉으로 인한 Latency나 클라이언트 IP 보존이 중요하다 → Local
그런것보다는 균등한 트래픽 분배가 더 중요하다 → Cluster
서비스 타입의 비교
🌱 참고 : ClusterIP, NodePort, LoadBalancer, Ingress의 비교
[발번역] Kubernetes NodePort vs LoadBalancer vs Ingress?? 언제 무엇을 써야 할까??
본 글은 아래 글을 발번역 한 내용입니다. 누락되거나 잘못 옮겨진 내용이 있을(아니 많을;;) 수 있습니다. 어색하거나 잘못된 표현은 알려주세요. 원글: Kubernetes NodePort vs LoadBalancer vs Ingress? When s
blog.leocat.kr
ExternalName
쿠버네티스를 외부 시스템과 연동해야할 때 ExternalName 타입의 서비스를 사용한다.
서비스가 외부 도메인을 가리키도록 설정한다. 서비스에 이름을 부여하고, 파드들이 이 이름으로 요청을 보낼 경우, 서비스가 이 트래픽을 외부 도메인으로 포워딩한다.
apiVersion: v1
kind: Service
metadata:
name: externalname-svc # 서비스 이름
spec:
type: **ExternalName**
externalName: my.database.com # 포워딩할 외부 서비스
쿠버네티스 내부의 파드가 externalname-svc에게 요청을 보내면, 이 요청을 서비스가 받아서 my.database.com으로 포워딩한다.
'Cloud > Kubernates' 카테고리의 다른 글
설정값 전달 : ConfigMap, Secret (1) | 2023.10.29 |
---|---|
NameSpace 관리 (1) | 2023.10.29 |
ReplicaSet, Deployment (0) | 2023.10.29 |
Pod, NameSpace (1) | 2023.10.29 |
쿠버네티스 시작하기 : 내부 구조 (0) | 2023.10.29 |