Service
파드 집합에서 실행중인 Application을 네트워크 서비스로 노출시키는 방법, 네트워크 추상화를 제공해 동적으로 할당된 파드에 접근할 수 있는 리소스이다.
Service의 목적
왜 이런 리소스가 필요할까? 서비스 리소스가 필요한 이유를 일반적인 상황을 통해서 알아볼 수 있다.
웹 Application을 구동시키는 클러스터를 운영하고 있다고 가정해보자. 그리고 이 Application이 Deployment나 StatefulSet을 통해 여러 파드로 분산되어 실행되고 있다고 할 때, 일부 파드가 재생성되는 상황을 생각해보자.
파드가 영구적이지 않은 특성(일회성)을 가짐에 따라, 클러스터의 상황에 따라 언제든지 다른 노드들로 옮겨질 가능성이 존재한다. 이렇게 다른 노드로 옮겨져 생성되면, 매번 파드의 IP가 변경되어 클러스터 외부와 통신이 유지되기가 어렵다.
따라서, 클러스터의 외부에서 내부의 파드와 Application에 접근하기 위한 단일 진입점 역할을 하는 Service가 필요하게된다. 또한, Service는 내부로 들어오는 트래픽을 적절하게 분산시켜주는 로드밸런싱 역할을 담당할 수 있다.
Service 유형
이러한 Service는 4가지 유형으로 분류한다.
- ClusterIP
- NodePort
- LoadBalancer
- ExternalName
Manifest 파일로 작성할 때, kind: Service로 지정해 Service 리소스를 생성할 수 있으며, spec.type 항목에 Service 유형을 적어 해당 유형의 Service 리소스를 생성할 수 있다.
Service 리소스에는 spec.ports 항목이 존재한다. Service와 파드를 연결해주는 포트들의 설정이 담기는 항목으로, 아래 2가지 부항목을 지정해준다.
- targetPort : Service와 연결될 파드에서 노출시킨 포트 번호
- port : Service쪽에서 노출시킨 포트 번호
Service와 파드의 포트 관계는 아래 그림으로 설명할 수 있다.
ClusterIP
클러스터 내에서만 사용 가능한 가상의 IP를 할당하는 서비스, 이 IP로 다른 파드들이 이 서비스에 접근 가능하다.
ClusterIP 서비스는 내부 파드들 간의 통신을 위해 사용한다.
ClusterIP의 Manifest 파일 작성은 아래와 같다
apiVersion: v1
kind: Service
metadata:
name: my-clusterip-service
spec:
type: ClusterIP
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
spec에서 type을 별도로 지정하지 않은 경우, 기본값으로 ClusterIP가 지정된다.
selector가 지정되어 app=my-app의 label을 가진 파드들과 ClusterIP Service가 연결됨을 볼 수 있다.
NodePort
클러스터의 모든 노드에 특정한 포트를 열어 외부에서 접근할 수 있게 하는 서비스
노드의 외부 IP와 해당 포트로 파드의 Application에 접근할 수 있다. 클러스터 외부로부터의 트래픽을 처리할 수 있는 가장 기본적인 Service 유형이다.
NodePort의 Manifest 파일 작성은 아래와 같다.
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 30001
spec.ports에 port와 targetPort 외에 nodePort 값을 추가로 지정해준다. nodePort는 클러스터 외부에서 노드 안의 서비스로 접근할 수 있도록 지정하는 포트로, 30000번에서 32767번 사이의 값을 지정해 줄 수 있다. 값을 지정하지 않은 경우, 범위 내에서 랜덤하게 지정된다.
위와 같이 생성된 NodePort는 클러스터의 각 노드에 30001번 포트를 열고, Service에서는 80포트, 내부 파드의 8080포트로 연결해주는 구조를 가지게 된다.
LoadBalancer
클라우드 플랫폼에서 제공하는 외부 로드밸런서를 이용해 클러스터 외부에서 접근 가능하도록 노출하는 서비스
로드밸런서는 노드 앞단에 위치해 각 노드들로 트래픽을 분산시킬수 있다.
외부 IP주소가 자동으로 할당되어, 이 주소로 클러스터 외부에서 접근할 수 있다.
LoadBalancer Service는 일반적으로 클라우드 플랫폼 환경에서만 사용할 수 있다. 이러한 LoadBalancer 서비스는 클라우드 제공자에 종속적이며, 각 클라우드 제공자마다 추가적인 설정이 다르다.
클라우드 환경이 아닌 온프레미스 환경에서 LoadBalancer를 사용할 경우 MetalLB와 같은 베어메탈 로드밸런싱 모듈을 설치해주어야 한다.
아래는 일반적인 클라우드 환경에서 LoadBalancer 서비스를 생성하는 Manifest 구성이다.
apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
annotation: [어노테이션 설정]
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
LoadBalancer 서비스를 생성하기 위해서 metadata의 annotation 구문을 이용해 설정값을 작성한다. 작성하는 annotation 구문 설정값은 각 클라우드 서비스마다 따로 존재한다.
ExternalName
외부에서 클러스터에 접근하기 위한 NodePort와 LoadBalancer 서비스와는 다르게 ExternalName은 외부 서비스에 대한 DNS name을 제공해 내부 파드가 외부의 특정 도메인에 접근하게 하기 위한 리소스이다.
apiVersion: v1
kind: Service
metadata:
name: my-externalname-service
spec:
type: ExternalName
externalName: google.com
externalName에 google.com을 지정해주었다. 이를 통해 이 서비스와 같은 namespace의 파드들에서 name으로 설정한 my-externalname-service로 내린 요청이 google.com으로 연결되는 것을 볼 수 있다.
my-externalname-service로 DNS query → ExternalName 서비스가 CNAME 값으로 google.com 반환 → google.com으로 접속
이렇게 4개의 Service 유형을 알아보았다.
다음으로 쿠버네티스에서의 볼륨을 알아보도록 한다.