[K8s]5-1. 서비스(Service)

[K8s]5-1. 서비스(Service)


이 글은 쿠버네티스 인 액션 이라는 책과 검색을 통해서 공부한 것을 정리합니다.

서비스

클라이언트가 포드를 검색하고 통신을 가능하게 함.

포드가 다른 곳에서 제공하는 서비스를 사용하려면?

포드를 찾아야?! 문제는?

  • 포드는 일회성이라는 문제 : 노드간에 언제든지 이동이 된다는 것
  • 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 의 밸류는 NoneClientIP만 존재

  • 특정 클라이언트가 특정 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