[K8s]5-1. 서비스(Service)
in etc on Kuberenetes
이 글은 쿠버네티스 인 액션 이라는 책과 검색을 통해서 공부한 것을 정리합니다.
서비스
클라이언트가 포드를 검색하고 통신을 가능하게 함.
포드가 다른 곳에서 제공하는 서비스를 사용하려면?
포드를 찾아야?! 문제는?
- 포드는 일회성이라는 문제 : 노드간에 언제든지 이동이 된다는 것
- IP 주소를 미리 알 수 없다 : 포드가 노드로 스케줄된 후 시작하기 전에 IP 주소를 할당. 그래서 클라이언트는 서버의 포드의 IP주소를 미리 알 수 없다. 하나의 IP 영원하지 않아..
- 포드는 수평 스케일 지원하는데
클라이언트는 각 포드의 특정 IP
를 알 필요가 없어야 하는데?
서비스
- 그래서
서비스
는여러 포드 그룹에 단일 진입 점
을 만들기 위해 생성하는 리소스 - 각 서비스에는 서비스가 존재하는 동안 절대 변하지 않는 IP 주소와 포트가 있음.
- 그래서 클라이언트는 해당 IP 및 포트에 연결하고 -> 해당 서비스를 지원하는 포드 중 하나로 라우팅 되는 구조를 가지고 있다.
실습
- 클라이언트, 프론트 엔드 서비스, 백엔드 존재
- (1) 클라이언트는 프론트 엔드 서버(단일이든 수백개 든)로 접속 할 수 있어야 함.
- (2) 프론트 엔드는 백엔드 데이터 베이스에 연결해야함. 시간이 지나면서 변경되는 IP와 상관 없이 가능해야 함.
kubia-svc.yml
- yml에 kubia 서비스를 정의한다. 80 포트로 들어오는 연결을 허용.
- 각 연결을 대상으로 app=kubia 라벨 셀렉터에 매칭되는 포드 중 하나를 8080 포트로 라우팅한다.
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: kubia
5 spec:
6 ports:
7 - port: 80 # Service가 사용 할 포트
8 targetPort: 8080 # Service가 포워드할 컨테이너 포트
9 selector:
10 app: kubia # 라벨이 app=kubia 인 모든 포드는 이 서비스에 속함.
➜ kubectl create -f kubia-svc.yml
service/kubia created
➜ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d4h
kubia ClusterIP 10.98.199.212 <none> 80/TCP 28s
- kubia 라는 서비스로 할당된 IP가
10.98.199.212
라는 것을 알 수 있다. - 클러스터 안에서만 유효하며, 서비스의 주목적은 포드들의 그룹을 클러스터상의 포드에게 노출하는 것이다.
테스트
- 이미 존재하는 포드 중 하나에서 curl 명령어를 통해서 서비스에 요청을 보내보자
$ kubectl exec kubia-7nog1 -- curl -s http://10.98.199.212
Tip 과 해석
kubectl exec
명령어를 통해서 특정한 컨테이너 포드 안에서 원격으로 임의의 명령어를 실행할 수 있다.- node.js 기반 컨테이너 파드에 접속해서 curl을 날려서 연결이 되는지 확인했다.
- -s 옵션은 디폴트가 아닌 다른 API 서버로 연결하라는 kubectl의 옵션 중 하나임
- 그림과 실습의 ip 차이가 있을 수 있음.
예외 1, 서비스의 고정 세션 구성
위 그림은 요청때마다 임의의 pod에 연결됨. 이전 요청과 같은 pod 일수도 아닐수도 있음.
매번 같은 포드로 리다이렉션 하고 싶다면?(고정 세션 구성)
- Service 리소스를 만들 때 아래처럼 설정만 해주면 된다.
1 apiVersion: v1
2 kind: Service
3 spec:
4 sessionAffinity: ClientIP
5 (생략)
sessionAffinity 의 밸류는 None
과 ClientIP
만 존재
- 특정 클라이언트가 특정 Pod로 연결이 되도록 한다: ClientIP
예외 2, 동일한 서비스에서 여러 개의 포트 노출(포트 기준)
포트 번호 기준. 80 포트(http) 로 들어오는 것은 8080로 매핑시킨다.
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: kubia
5 spec:
6 ports:
7 - name: http
8 port: 80
9 targetPort: 8080
10 - name: https
11 port: 443
12 targetPort: 8443
13 selector:
14 app: kubia # 라벨이 app=kubia 인 모든 포드는 이 서비스에 속함.
예외 3, 동일한 서비스에서 여러 개의 포트 노출(네임 기준)
- Service 리소스
1 apiVersion: v1
2 kind: Service
3 metadata:
4 name: kubia
5 spec:
6 ports:
7 - name: http
8 port: 80
9 targetPort: http # pod 중 http 네임으로 가진 포트에 매핑
10 - name: https
11 port: 443
12 targetPort: https # pod 중 https 네임으로 가진 포트에 매핑
13 selector:
14 app: kubia # 라벨셀렉터가 app=kubia 인 모든 포드는 이 서비스에 속함.
- Pod 리소스
1 apiVersion: v1
2 kind: Pod
3 spec:
4 containers:
5 - name: kubia # 단순 컨테이너 이름
6 ports:
7 - name: http # 서비스에 정의된 targetPort
8 containerPort: 8080
9 - name: https
10 containerPort: 8443
예외3의 네임 기준이 왜 편한가?
- 서비스의 스펙 변경 없이 포트 번호를 변경할 수 있다.
- 즉 Pod의 port가 변하더라도 네임으로 찾아서 서비스가 가능해짐.
번외 실습
- kubia-svc.yml 하고 생성
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- port: 80 # Service가 사용 할 포트
targetPort: 8080 # Service가 포워드할 컨테이너 포트
selector:
app: kubia # 라벨이 app=kubia 인 모든 포드는 이 서비스에 속함.
- kubia-svc-client.yml 하고 생성
apiVersion: v1
kind: Pod
metadata:
name: kubia-svc-client
spec:
containers:
- name: kubia-svc-client
image: twowinsh/kubia-svc-client:1.0.0
ports:
- containerPort: 3000
- kubia-svc-not-client.yml 하고 생성
apiVersion: v1
kind: Pod
metadata:
name: kubia-svc-not-client
labels:
app: kubia # 라벨이 붙어있음.
spec:
containers:
- name: kubia-svc-not-client
image: twowinsh/kubia-svc-client:1.0.0
ports:
- containerPort: 3000
Service cluter Ip 확인
➜ minikube kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d21h
kubia ClusterIP 10.98.199.212 <none> 80/TCP 16h
Service 정의대로 붙는지 확인해보기
➜ minikube kubectl exec kubia-svc-client -- curl -s http://10.98.199.212
You've hit kubia-svc-not-client