Search

Services

Created
2023/09/29 13:13
Tags
k8s
CKA
Mumshad Mannambeth
Core Concept

1) About

쿠버네티스로 배포된 어플리케이션을 어플리케이션 안팎으로 접근하기 위해서 정의하는 것이 서비스
서비스를 정의한다는 것은 어플리케이션들을 논리적으로 동일한 범주 내에 두는 것을 의미하고, 서비스 단위의 그룹으로 묶인 어플리케이션들은 MSA 상에서 결합도를 낮추게 됨

2) YAML

apiVersion: v1, kind: Service
apiVersion: v1 kind: Service metadata: name: svc-sample spec: # ...
YAML
복사

3) NodePort

NodePort라는 것은 말 그대로 노드에 접근할 수 있는 수단을 두는 방식
일반적으로 Nginx를 Pod로 구성했고 별도의 서비스 없이 Nginx에 접근하고자 한다면, 1차적으로는 ssh 등을 통해 Pod를 갖고 있는 노드 내부로 들어가야하고, 2차적으로는 Pod의 IP 주소를 향해 접근을 해야함
하지만 이와 같은 형태는 외부에서 접근하는 것이 아닌데, NodePort로 서비스를 정의하게 되면 노드의 포트와 Pod의 포트가 맵핑된 형태로 구성되므로, 노드의 IP 주소와 포트를 이용한 접근이 Pod로의 접근으로 이어짐 (물론 노드의 IP 주소가 public이어야 가능)
NodePort는 3개의 포트가 사용되는데, 각 포트의 이름은 서비스 관점에서 명명됨
1) 노드의 포트 (서비스로 접근할 수 있는 포트로 NodePort라고 불리고, 실제 인스턴스)
2) 서비스의 포트 (서비스 자체가 구동될 때 필요한 포트로 단순히 Port라고 불리고, 일종의 가상 서버)
3) Pod의 포트 (서비스가 포워딩 하려는 목표 대상이므로 TargetPort라고 불리고, 일종의 가상 서버)
** 가상 서버라는 말은 노드의 포트를 점유한 형태가 아니므로, 서로 중복된 포트 번호를 운용하는 것이 가능
** 또한 이러한 각각의 가상 서버는 클러스터 내부에서 사용되는 고유한 각각의 ClusterIP가 존재 (즉, 노드의 IP 주소를 포함하여 각각의 쿠버네티스 객체가 가진 IP 주소가 모두 다름)
NodePort의 유효한 값은 30,000 ~ 32,767까지의 값만 가질 수 있음

YAML

spec에는 type과 ports, selector를 명시하게 됨
targetPort의 명시가 없다면 서비스가 구동되는 port와 동일하다고 간주되고, nodePort가 명시되지 않으면 30,000 ~ 32,767 사이의 임의 값으로 설정
서비스의 포트가 배열 형태로 주어지는 것을 통해, 한 서비스 객체 내에 여러 포트 맵핑 정책을 기재할 수 있음
selector는 서비스의 포트 정책과 어떤 Pod를 매치시킬지 결정 짓는데 사용 (다중 Pod가 매칭되더라도 서비스 내부에 있는 LB를 이용하여 각각의 Pod들로 적절히 요청을 분산하게 됨)
Pod들은 노드의 구분 없이 한 노드로만 생성이 되지 않는다고 했는데, 그렇다면 이전에 설명된 단일 노드 내의 다중 Pod가 위치하는 것이 아닌, 다중 노드에 다중 Pod가 위치하는 경우엔 어떻게 해야하는지 고민이 생길 수 있음
여러 서비스를 만들어야 하나 싶은 고민을 하지 않아도, 서비스를 생성할 때 쿠버네티스는 자동으로 클러스터 내의 노드들을 가로지르는 형태로 서비스를 생성하게 되고, 이러한 서비스는 여러 노드에 존재하는 매칭된 Pod들의 포트를 적절히 맵핑하여 각각의 노드에서 접근이 가능하도록 만듦
예를 들어 A 노드에 Pod 2개, B 노드에 Pod 3개, C 노드에 Pod 4개가 있다고 했을 때, x라는 30008번 포트를 NodePort로 사용하는 서비스를 한 번만 정의하게 되면 A:30008, B:30008, C:30008 과 같은 형태로 접근이 가능
apiVersion: v1 kind: Service metadata: name: svc-sample spec: type: NodePort ports: - targetPort: 80 port: 80 nodePort: 30008 selector: matchLabels: app: nginx type: ws
YAML
복사

4) ClusterIP

NodePort가 외부로의 접근을 열기 위해 사용되는 형태였다면, ClusterIP는 서로 비슷한 범주의 어플리케이션들을 묶어내는데 사용됨
ClusterIP는 클러스터 내부에서 사용할 가상 IP를 만들어서 동작하는 서비스로, 클러스터 내부의 다른 서비스와 통신하는데 사용됨
Pod들도 각각의 IP 주소가 있음에도 불구하고 ClusterIP가 필요한 것은, Pod에 할당된 IP 주소가 정적 IP가 아닌데 있으며, 각각의 Pod들의 스케일링에 따라 대상 지정이 모호한데 있음
예를 들어, A라는 기능을 하는 Pod가 3개가 있고 B라는 기능을 수행하는 Pod가 3개가 있다고 했을 때, A의 1번 Pod가 B의 Pod로 요청을 보내려고 한다면, B의 동적인 IP에 어떻게 대응해야하며 B의 몇 번 Pod로 요청을 보내야할까?
A와 B를 각각의 ClusterIP 형태의 서비스로 묶으면, Pod가 갖는 동적인 IP에 대응할 수 있도록 서비스 이름으로 Routing을 제공함과 동시에 자체적으로 LB를 수행하여 위 문제를 해결
즉, ClusterIP는 그룹으로 묶인 Pod들에게 접근할 수 있는 단일 인터페이스를 제공하는데 그 목적이 있음

YAML

ClusterIP는 서비스의 기본 타입이기 때문에 type에 ClusterIP를 명시하지 않아도 됨
apiVersion: v1 kind: Service metadata: name: svc-sample spec: type: ClusterIP ports: - targetPort: 80 port: 80 selector: matchLabels: app: nginx type: ws
YAML
복사

5) LoadBalancer

NodePort의 사례를 자세히 생각해봤다면, 문제점이 느껴지는 부분이 있음
서비스를 생성하여 각 노드에 존재하는 Pod들에게 접근할 수 있는 상태가 되었다고 하더라도, 어떤 IP 주소를 이용해야 하는 것인지 결정하기에 모호함
예를 들어 Deployment의 Pod 3개가 A, B, C 노드에 1개씩 위치해 있다면, 각 노드에 접근할 수 있는 IP 주소 중 어떤 것을 사용해야할까?
조금 더 극단적으로 들어가보면… 1번 Deployment의 Pod 3개가 A, B 노드에 존재하고, 2번 Deploymentdml Pod 3개가 C, D 노드에 존재한다면, 1번 Deployment를 접근할 수 있는 IP 주소는 A ~ D 4개, 2번 Deployment를 접근할 수 있는 IP 주소는 A ~ D 4개로 총 8개의 조합이 생김
** 각 Deployment가 2개의 노드에서만 호스팅 되더라도 다중 노드에 걸쳐 있기에 모든 노드에서 접근이 가능해서 발생
즉, Deployment 수 * 노드의 수 만큼 접근 주소가 생기게 되는데, 어떤 주소를 사용하는 것이 올바를까?
적어도 1번 Deployment와 2번 Deployment를 구분할 수 있는 각각의 단일 주소를 두는 방식이나, 1번 Deployment 및 2번 Deployment를 통합하여 접근할 수 있는 주소를 두는 방식 등 정확하게 정해진 접근 주소가 있어야 함
이와 같은 문제를 해결하는 방법으로는 HA Proxy 혹은 Nginx 등의 부하 분산 목적의 인스턴스를 하나 구성하고, 쿠버네티스 클러스터에 존재하는 모든 노드들의 부하 분산을 설정 파일로 관리하는 방법이 있음
** 물론 이와 같은 방식이 지루하고 고된 과정일 수 있지만, 최근에는 AWS, GCP, Azure 등 클라우드 플랫폼에서 네이티브로 동작하는 LB를 사용하여 보다 쉽게 구성할 수 있음
이 때 쿠버네티스는 클라우드 공급자의 네이티브 LB와의 통합을 서비스로 지원하는데, 이것이 LoadBalancer
** 클라우드 공급자가 쿠버네티스와의 통합을 지원하는지 확인해야함
** 만일 쿠버네티스와의 통합을 지원하지 않는 LB를 사용하게 되면 NodePort를 사용하는 것과 크게 다르지 않은 효과를 갖게 됨
즉, LoadBalancer 타입의 서비스는 기본적으로 NodePort로 운용되는 서비스를 클라우드 공급자의 LB로 맵핑해주는 역할

YAML

type을 LoadBalancer로 지정
apiVersion: v1 kind: Service metadata: name: svc-sample spec: type: LoadBalancer ports: - targetPort: 80 port: 80 selector: matchLabels: app: nginx type: ws
YAML
복사

6) Commands

kubectl get service
Service들의 정보를 모두 읽음

7) Abbreviation

Service == svc