개인적으로 Kubernetes 네트워크가 복잡하다고 생각합니다.
그도 어쩔 수 없는 게 클러스터 내부에 수 많은 애플리케이션들을 연결시키기 위해서는 그럴 수 밖에 없었을 것이라~ 생각합니다.
그래도 나름 간단하게 하기 위한 노력도 보이니 우리 함께 최대한 이해해봅시다!
Kubernetes Service 왜 필요해? 🤔
먼저 우리가 생각해봐야할 게 있습니다.
왜 이게 필요할까요?
Pod의 성질
이는 Pod의 성질에 관련이 있습니다.
예를 들어 Deployment를 통해서 애플리케이션 배포를 관리하고 있는데, Pod가 모종의 이유로 죽게되고 다시 살아났다면
이 전 Pod가 사용했던 IP와 새로 생성된 Pod의 IP는 다르게 생성됩니다.
그래서 Pod IP를 직접 사용하는 것은 위험한 방법이라고 할 수 있습니다.
이를 해결하기 위해서 Deployment와 Pod에 라벨링을 하게 되고, 서비스는 이 라벨링을 찾아서 트래픽을 전달해주는 역할을 하게 됩니다.
그리고 이를 서비스 디스커버리라고 합니다.
예를 들어 아래에 서비스에 접근하는 트래픽은 app.kubernetes.io/name: proxy인 Pod들에 매핑되게 됩니다.
서비스 접근은 보통 http://{service name}.{namespace} 로 가능합니다.
(아래 서비스 접근 예시 http://nginx-service.system)
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namspace: system
spec:
selector: # label이 'app.kubernetes.io/name: proxy'를 가진 Pod를 대상으로함
app.kubernetes.io/name: proxy
ports:
- name: name-of-service-port
protocol: TCP
port: 80
targetPort: 8080
Kubernetes의 복잡성
위에 언급한 대로 Kubernetes의 네트워크는 복잡합니다. 따라서 트래픽이 원하는 대로 전달되게 하기 위한 과정이 복잡합니다.
예를 들어 외부 IP 호출을 통해서 내가 원하는 애플리케이션까지 트래픽이 전달되고 싶다고 합시다.
1. 그렇다면 먼저 etcd에 저장을 해야합니다. 내가 원하는 애플리케이션이 어느 노드에 있는지 알아야하기 때문입니다.
2. kube-proxy는 각 노드의 네트워크를 관리합니다. 따라서 여기에 등록이 되어야 하며, 정확히는 iptable 또는 IP Virtual Service에 등록되게 됩니다.
3. 또한 서비스 이름으로 클러스터 내부 DNS를 등록을 하기 때문에 Coredns와 같은 DNS 시스템에 등록해야합니다.
이러한 네트워크 설정들을 서비스 등록을 통해서 비교적 간단히 해결할 수 있습니다.
어때요? 알고보니 선녀같죠? 😂
Kubernetes Service 종류
Kubernetes에서는 크게 3가지의 type을 제공합니다.
ClusterIP
가장 기본 타입이며, 클러스터 내부 통신에 주로 사용됩니다.
트래픽을 로드밸런싱해주며, 이를 통해 트래픽 분산을 이룰 수 있습니다.
아래 그림을 보면 Proxy를 사용하는 것을 알 수 있는데요.
위에 언급했다시피 각 노드의 네트워크를 관장하는 Kube-Proxy에 서비스의 정보가 저장되기 때문에,
트래픽이 왔을 때 적절한 서비스로 매핑되게 됩니다.
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector: # label이 'app.kubernetes.io/name: proxy'를 가진 Pod를 대상으로함
app.kubernetes.io/name: proxy
ports:
- name: name-of-service-port
protocol: TCP
port: 80 # 외부에서 Service에 접근할 때 사용되는 포트 번호
targetPort: 8080 # Pod 내부의 포트
NodePort
ClsuterIP의 기능에 더해, 모든 노드의 특정 포트를 개방합니다.
이는 클러스터 외부에서 노드의 IP와 할당된 포트를 통해서 클러스터 내부로 접근할 수 있습니다.
아래 그림을 보면 VM(Virtual Machine = Node)의 포트를 사용하는 것을 알 수 있습니다.
노드 포트들은 이미 외부에 오픈되어 있기 때문에 이를 사용해서 간단하게 외부 호출을 받는 방식이에요.
노드 포트를 사용하기 때문에 노드 IP가 변경되면 이에 영향을 받는다는 점과 노트 포트가 한정적 (30000-32767) 이라는 점이 단점입니다.
그래서 보통 운영할 때는 이렇게 사용하는 경우는 거의 없죠.
piVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app.kubernetes.io/name: MyApp
ports:
- port: 80 # 서비스 노출 포드
targetPort: 80 # Pod에서 노출하는 포트
# 선택적 필드 (명시하지 않은 경우 사용 가능한 포트를 자동으로 할당)
# 기본적으로 그리고 편의상 쿠버네티스 컨트롤 플레인은 포트 범위에서 할당한다(기본값: 30000-32767)
nodePort: 30007 # 만약 30007 포트가 사용 중이라면 실패
LoadBalancer
NodePort의 기능을 포함하며, 추가로 클라우드 제공자의 로드 밸런서를 사용합니다.
보통 로드밸런서는 클러스터 외부에 존재하며, AWS, GCP 등의 클라우드 서비스가 제공하는 프로비저닝된 로드 밸런서와 클러스터를 연결하기 위해서 사용됩니다.
그리고 외부에서는 로드 밸런서의 IP를 통해서 클러스터 내부의 애플리케이션에 접근할 수 있습니다.
하나의 IP를 통해서 서비스를 노출시키기 때문에 관리적 측면에서도 편해지며, 운영 중인 서비스에서는 기본적으로 사용하는 방식입니다.
단점은 외부 Load Balancer를 사용하기 때문에 비용이 발생한다는 것입니다.
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 80 # 서비스를 노출하는 포트
targetPort: 80 # 애플리케이션(파드)를 노출하는 포트
clusterIP: 10.0.171.239 # 클러스터 IP
selector:
app: myapp
type: frontend
status:
loadBalancer: # 프로비저닝된 로드 밸런서 정보
ingress:
- ip: 192.0.2.127
정리
쿠버네티스는 동적 IP를 가지는 Pod 환경에서 안정적인 네트워크를 제공하기 위한 아주아주 핵심 요소입니다.
물론 쿠버네티스에서 제공하는 기본 기능이 우리가 원하는 사항을 충족시키지 못 해서 Istio와 같은 외부 프로젝트를 사용하기도 합니다.
이는 나중에 또 알아보는 걸로 하겠습니다 ~~
참고
모든 그림은 아래 사이트에서 가져왔습니다.
https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0
자세한 내용이 알고 싶다면 Kubernetes 공식 문서를 참고해주세요!
https://kubernetes.io/ko/docs/concepts/services-networking/service/
'Engineering 💻 > MLOps' 카테고리의 다른 글
MLOps Engineer와 함께 쿠버네티스(Kubernetes) 구조 살펴보기 (0) | 2025.01.12 |
---|---|
현직 MLOps Engineer의 쿠버네티스(Kubernetes) 간단한 고찰 (0) | 2025.01.11 |
[MLOps] Windows 환경에서 kubeflow 설치하기 (0) | 2023.03.27 |