✔️ Service Object의 개념
쿠버네티스에서의 Service는 Pod들의 집합이며 동일한 서비스 동작을 구현하는 여러가지 Pod를 묶어 하나로 관리하는 오브젝트이다.
✔️ Service Object의 등장 배경
1. 서비스를 위한 고정 IP의 필요성
서버는 문제가 생기면 서버를 재시작하고 서비스를 재시작하지만 Pod는 문제가 생기면 그 Pod를 삭제한 뒤 새로운 Pod를 생성한다. 따라서 Pod의 IP는 휘발성이라고 볼 수 있기 때문에, 재할당 될 때마다 Pod로의 고정적인 호출에 대한 보장이 어렵다.
서비스를 위해서는 고정 IP가 필요하므로 동적 IP를 가지는 Pod만으로는 불가능하다.
따라서 Pod의 상위 개념인 서비스가 등장하게 된다.
서비스는 여러 Pod들을 하나의 서비스 오브젝트로 선언할 수 있으며, 이 서비스 객체에는 고정 IP가 할당된다.
서비스 내부의 Pod의 IP가 계속 바뀌더라도 서비스의 IP는 계속 고정적인 것이다.
2. 서비스 제공을 위한 Pod 집합에 대한 경로 제공의 필요성
서비스 오브젝트는 트래픽을 "전달" 하는 역할만 하며 실제 서비스를 수행하는 오브젝트는 Pod 이다.
서비스 오브젝트의 할 일은 트래픽이 들어왔을 때 자신의 서비스와 연관된 Pod들까지의 경로를 찾아 트래픽을 전달하는 것이다.
서비스 오브젝트로 묶여진 Pod들을 endpoint라고 한다.
서비스 오브젝트는 자신의 endpoint들을 label을 통해 찾아낸다.
Label이란 쿠버네티스 오브젝트들의 특성을 식별하기 위한 key-value 값으로 쿠버네티스 오브젝트들을 그룹핑하는 기본 단위이다.
서비스로 트래픽이 들어오면 서비스와 같은 Label을 갖는 Pod endpoint들을 찾아 그곳으로 트래픽을 전달한다.
정리하자면,
- 서비스는 원하는 IP로 생성이 가능하며 고유한 DNS 이름을 가질 수 있다.
- Service는 Label Seclector를 통해 관리하려는 Pod를 정의할 수 있다.
- Service 사용시 사용자는 EndPoint로 Service를 지정하면 Service는 해당 Label Selector와 일치하는 Label을 가진 Pod로 접근을 가능하게 한다.
즉, 서비스에 필요한 기본적인 기능을 스스로 관리하는 오브젝트이다.
이제 Service에 대해 더 자세히 알아보자
✔️ Service Object의 종류
1. Cluster IP - 클러스터 내부에서만 접근 가능한 IP
2. Node IP Port - 번호를 통해 외부에서 접근. (NAT 컨샙)
3. Load Balancer - 외부의 Load Balancer를 사용하는 방법
4. External Name - kube-dns 컴포넌트로 DNS를 이용하는 방법
1. ClusterIP
- Default 설정으로 클러스터 내에서 해당 서비스에 접속하기 위한 타입이다.
- Service 오브젝트에 Cluster 내에서만 접근할 수 있는 ClusterIP를 할당한다.
- Service에 Pod를 연결해놓으면 Service의 ClusterIP를 통해 Pod에 접근 가능
- 클러스터 내부 IP를 할당 받기 때문에, 클러스터 외부에서는 접근이 불가하다. (kube-proxy 사용하면 가능)
클러스터 IP는 존재하나 EXTERNAL-IP가 존재하지 않기 때문에 클러스터 외부에서는 접근이 불가하다.
2. NodePort
- 클러스터 내 모든 노드에 외부에서 접근 가능한 포트를 개방한다.
- NodePort로 개방할 포트 번호를 지정하게 되는데, NodePort가 설정되면 {클러스터 내 임의 노드의 IP}:{지정한 Port 번호}로 서비스에 접근 가능하다.
- 이 때 클러스터 내의 모든 노드들이 Public IP를 갖는다면 외부에서도 접근 가능한 서비스가 된다.
NodePort에 대한 더 자세한 내용
외부의 IP가 192.168.1.1이면 31000번 Port를 통해 Node에 접근할 수 있다.
이때 Node의 어떤 Service를 ..!? 어느Pod로...? 라는 의문이 생기는데, 이걸 yaml 파일에 미리 정의해두어 특정 Pod의 어플리케이션을 접근할 수 있게 되는 것이다.
즉 NodePort 서비스를 만든다는 것은 Service를 하나 만들어 외부의 어떤 Port 번호를 지정해 붙게끔 하고 내부의 어떤 Pod를 서비스 할지를 Label Selector로 지정해주어 Target Port 번호를 정의하는 것이다.
NodePort는 보통 30000 ~ 32767 대역의 포트 번호를 사용한다.
Service를 만들 때 지정해 준 것
1. 어떤 Pod를 묶을 것인지 Selector로 지정
2. 외부에서 들어올 때 어떤 Port 값으로 들어올지에 대한 것
nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: nodeport
spec:
type: NodePort
ports:
- name:http
port:80
protocol: TCP
targetPort: 8080
nodePort: 8081
selector:
app: nodeport
ver: v1
생성하면 기존의 ClusterIP처럼 ClusterIP의 80번 포트를 통해 노드들의 8080 포트로 접근할 수 있다.
위의 방법 말고 nodeport service를 이용하면 아래와 같이 각 각의 노드의 30001번 IP로도 접근이 가능하다.
접근하려는 Pod가 Node1에 존재할때 Node2(1.0.0.2:30001)으로 접속하여도 Node1의 Pod로 접속이 가능하다.
Label이 Myapp인 3개의 Pod를 Selector를 통해 서비스를 묶어주게 되면 자동으로 연결되고 자동으로 LB 기능을 수행하게 된다. 즉 http://192.168.1.1:31000에 접근하면 트래픽이 가장 원할한 곳에 자동으로 연결하는 것
서버가 세대인 경우에도, ReplicaSet은 3개 만들라고 하면 쿠버네티스는 상황을 봐서 균등하게 일거리가 가도록 만들어진다. 다른 곳에 흩어져있어도 Service를 정의할 때 selector를 MyApp이라 지정해주면 자동으로 연결되는 서비스가 만들어진다.
물론 서버마다 주소가 다르기 때문에 외부로 접근하는 주소는 3가지가 나오는데, 무조건 그 서버의 노드로 가는 것이 아니라, 논리적으로 묶여있기 때문에 마찬가지로 트래픽 상황이 가장 좋은 노드(Load Balancing)로 접속하게 된다.
3. LoadBalancer
- 외부 접근이 가능한 LB의 Public IP를 서비스 오브젝트에 할당한다.
- 쿠버네티스 서비스의 LB 타입은 클라우드 프로바이더들 (AWS, GCP, Azure 등)이 지원해줘야만 한다.
- LB 타입의 서비스는 서비스 1개당 LB가 1개씩 필요하다. → 비용 과다의 문제점 → Ingress로 해결
ex) Loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: Loadbalancer
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: Loadbalancer
ver: v1
위의 Service는 app:Loadbalancer, ver:v1의 Label을 가진 Pod에게 부하 분산을 한다.
외부에서 해당 Pod에 접속하기 위한 Service IP는 EXTERNAL-IP (52.141.17.35)를 입력하면 된다.
하지만 외부, 인터넷 망이 아닌 내부, 사설망에서만 접근이 가능하도록 해야하는 경우가 존재하는데,
그 경우에는 다음과 같이 Service yaml을 작성해 생성하면 된다.
internal-Loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
name: internal-loadbalancer
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: internal-loadbalancer
ver: v1
생성된 Service의 EXTERNAL-IP를 보면 이전의 Service와는 다르게 내부 IP인 10.20.x.x 대역의 IP를 가진것을 볼 수 있다.
이제 외부에서 인터넷 망을 통한 접근은 불가하고, 내부에서 같은 대역대인 10.20.x.x 대역에서 10.20.10.107 IP를 통한 접근이 가능하다.
★ yaml 파일 작성 시 name, selector 항목의 값을 대문자로 시작하면 오류가 발생하므로 소문자로 시작해야 한다.
4. External name
- 클러스터 내부에서 외부의 특정 주소로 접근할 때 사용하는 방법이다.
- 쿠버네티스 클러스터 내의 Pod들은 클러스터 IP를 가지고 있기 때문에 클러스터 IP 대역 밖의 서비스를 호출하고자 하면, NAT 설정 등 복잡한 설정이 필요하다.
- 특히 AWS나 GCP와 같은 클라우드 환경을 사용할 경우 데이터베이스나 또는 클라우드에서 제공되는 Managed Service등을 사용하고자 할 경우에는 쿠버네티스 클러스터 밖이기 때문에 호출이 어려운 경우가 있는데 이를 쉽게 해결해줄 수 있는 방법이다.
- 서비스를 ExternalName 타입으로 설정하고, 주소를 DNS로 my.database.example.com으로 설정해주면 이 my-service는 들어오는 모든 요청을 my.database.example.com 으로 포워딩 해준다. (일종의 프록시와 같은 역할)
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
+ Ingress
하나의 IP로 여러 서비스를 노출할 수 없는 LB의 한계를 해결할 수 있는 것
Ingress 객체는 쿠버네티스 서비스 종류가 아니라 서비스들을 묶는 서비스들의 상위 오브젝트이다.
IP 기반이 아닌 URL 기반의 경로를 찾아준다.
Ingress는 사실 각 URL 경로 요청을 어떤 서비스로 연결해라 라는 "규칙"을 정의한다.
실제 Ingress 규칙에 맞게 경로를 설정하는 "행위"를 하는 것은 IngressController 이다.
헤드리스 서비스 (headless service)
서비스는 접근을 위해서 Cluster IP 또는 External IP 를 지정받는다.
즉 서비스를 통해서 제공되는 기능들에 대한 엔드포인트를 쿠버네티스 서비스를 통해서 통제하는 개념인데, 마이크로 서비스 아키텍쳐에서는 기능 컴포넌트에 대한 엔드포인트 (IP 주소)를 찾는 기능을 서비스 디스커버리 (Service Discovery) 라고 하고, 서비스의 위치를 등록해놓는 서비스 디스커버리 솔루션을 제공한다.
Etcd 나 hashcorp의 consul (https://www.consul.io/)과 같은 솔루션이 대표적인 사례인데, 이 경우 쿠버네티스 서비스를 통해서 마이크로 서비스 컴포넌트를 관리하는 것이 아니라, 서비스 디스커버리 솔루션을 이용하기 때문에, 서비스에 대한 IP 주소가 필요없다.
이런 시나리오를 지원하기 위한 쿠버네티스의 서비스를 헤드리스 서비스 (Headless service) 라고 하는데, 이러한 헤드리스 서비스는 Cluster IP등의 주소를 가지지 않는다. 단 DNS 이름을 가지게 되는데, 이 DNS 이름을 lookup 해보면, 서비스 (로드밸런서)의 IP 를 리턴하지 않고, 이 서비스에 연결된 Pod 들의 IP 주소들을 리턴하게 된다.
참고
'DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] Object - Namespace란 ? (0) | 2022.03.28 |
---|---|
[Kubernetes] Service Discovery (0) | 2022.03.17 |
[Kubernetes] Object 개념 (0) | 2022.03.17 |
[Kubernetes] Workload Resources (0) | 2022.03.16 |
[Kubernetes] Pod란 ? (0) | 2022.03.16 |
영차영차 성장 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!