7장 - 서비스

최시원·2023년 4월 22일
0

쿠버네티스 입문

목록 보기
7/7

여러개 파드에 접근할 수 있는 하나의 IP를 제공한다.
다양한 기능을 제공하지만, 본질적으로는 '로드 밸런서Load Balancer' 역할을 한다.

7.1 서비스의 개념

k8s 클러스터 안에 컨트롤러를 이용해서 파드를 실행했다면, 해당 파드에 접근하는 방법을 알아봐야 한다.
파드는 컨트롤러가 관리한다. 따라서 한군데 고정해서 실행되지 않는다. 클러스터 안을 옮겨다니게 된다. 이 과정에서 노드를 옮겨 실행되거나, 클러스터 안 파드의 IP가 변경되기도 한다. 이렇게 동적으로 변하는 파드들에 고정적으로 접근할 방법이 필요할 것이다.
이때 필요한 것이 '서비스' 이다.

서비스를 사용하면 파드가 클러스터 안의 어디에 있든 고정주소를 이용해 접근할 수 있다. 클러스터 외부에서 클러스터 안 파드에 접근할 수도 있고, 8장의 Ingress로도 접근 가능하다. 서비스는 L4 영역, 인그레스는 L7영역에서 통신할 때 사용한다는 차이점이 있다. 보통 역할을 분리해서 사용한다.

그림 참조

7.2 서비스 타입

서비스 타입은 다음 네가지가 있다.

  • ClusterIP
    기본 서비스 타입이다. k8s 클러스터 안에서만 사용 가능하다. 클러스터 안 노드/파드에서는 클러스터IP를 이용해 서비스에 연결된 파드에 접근한다. 클러스터 외부에선 이용불가.
  • NodePort
    서비스 하나에 모든 노드의 지정된 포트를 할당한다. node1:8080, node2:8080 처럼 노드에 상관없이, 서비스에 지정된 포트번호만 사용하면 파드에 접근할 수 있다. 노드의 포트를 사용하므로 클러스터 안/ 클러스터 외부에서도 접근 가능하다. 만약 파드가 node1에만 실행되어 있고, node2에는 실행되지 않았더라도 node2:8080으로 접근했을 때 node1에 실행된 파드로 연결된다. 클러스터 외부에서 클러스터 안으로 접근하는 가장 쉬운 방법.
  • LoadBalancer
    AWS, GCP 같은 퍼블릭 클라우드 서비스, 프라이빗 클라우드, k8s를 지원하는 로드밸런서 장비에서 사용한다. 클라우드에서 제공하는 로드밸런서와 파드를 연결한 후, 해당 로드밸런서의 IP를 통해 클러스터 외부에서 파드에 접근할 수 있도록 해준다.

    kubectl get service

명령으로 서비스 상태를 확인하면, EXTERNAL-IP 항목에 로드밸런서 IP를 표시한다. 이 IP를 사용해 클러스터 외부에서 파드에 접근한다.

  • ExternalName
    서비스르르 .spec.externalName 필드에 설정한 값과 연결한다. 클러스터 안에서 외부에 접근할 때 사용한다. 이 서비스로 클러스터 외부에 접근하면 설정해준 CNAME 값을 이용해 클러스터 외부에 접근할 수 있다. 클러스터 외부에 접근할 때 사용하므로, 설정시 .spec.selector 필드가 필요 없다.

서비스를 실제로 사용해보겠다.

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP	--------------- 1
  clusterIP: 10.0.10.10	----------- 2
  selector:		------------------- 3
    app: MyApp	------------------- 3
  ports:	----------------------- 4
  - protocol: TCP
    port: 80
    targetPort: 9376	----------- 4
  1. .spec.type 필드에서 서비스타입을 설정할 수 있따. 기본값은 ClusterIP
  2. 클러스터 IP를 직접 설정 가능. 하지않으면 자동으로 IP할당
  3. 서비스와 연결할 파드에 설정한 .labels 필드 값을 설정
  4. 배열형태의 필드. 서비스에서 한꺼번에 포트 여러개를 외부에 제공할 때는 이 하위에 필드값을 설정하면 된다.

서비스타입 각각을 만들고 사용해보자.

kubectl create deployment nginx-for-svc --image=nginx --replicas=2 --port=80

nginx 컨테이너를 실행하는 nginx-for-service 라는 이름의 파드이다. 포트번호는 80, 서비스에 사용할 레이블은 파드이름으로 설정하였다.

7.3.1 ClusterIP 타입 서비스 사용

ClusterIP 타입의 서비스 설정 예시

apiVersion: v1
kind: Service
metadata:
  name: clusterip-service
spec:
  type: ClusterIP	-------- 1
  selector:
    app: nginx-for-svc	---- 2
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  1. 이 필드값을 ClusterIP로 설정
  2. 여긴 nginx-for-svc로 설정해, 앞에서 실행한 nginx-for-service 파드를 선택하도록 하였다.

전체구조는 그림참조

이를 저장하고

kubectl apply -f clusterip.yaml

이걸로 클러스터에 적용하고 서비스 생성을 확인해보겠다.

TYPE이 CLusterIP이고, Cluster-IP 항목에 10.107.139.228로 클러스터 IP가 생성되었다. EXTERNAL-IP는 외부IP가 없으므로 none이 된다. PORT(S)는 80.

좀 더 자세한 정보는 kubectl describe service [서비스이름] 으로 확인한다.

  1. 이 서비스의 이름
  2. 이 서비스가 속한 네임스페이스
  3. 레이블이 app=nginx-for-svc인 파드를 선택하라는 의미
  4. 실제로 이 서비스에 연결된 파드들의 IP

현재 실행중인 파드들의 IP를 확인해보자

앞서 싫애한 nginx-for-service 디플로이먼트의 파드가 2개 실행중이고, IP가 위에서 표시된 clusterip-server 서비스의 Endpoints 항목과 같음을 확인 가능하다.

그럼 실제로 10.1.0.244 이라는 ip로 파드에 접근 가능한가를 살펴보자. ClusterIP는 k8s 클러스터 안에서만 사용가능한 IP이다. 그러므로 k8s 클러스터 안에 파드를 하나 실행하고, 해당 파드 안에서 앞서 만든 클러스터 IP로 접속해보자.

정상적으로 nginx 접속페이지의 HTML 마크업이 출력된다. CLusterIP 서비스가 잘 설정되었고 정상 작동한다.

7.3.2 NodePort 타입 서비스

NodePort 타입 서비스 설정 예시

apiVersion: v1
kind: Service
metadata:
  name: nodeport-service
spec:
  type: NodePort
  selector:
    app: nginx-for-svc
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30080

도커 데탑을 설치하며 만든 가상머신의 30080 포트를 각 파드에서 접근가능하도록 설정한 것이다.
그러므로 clusterip 타입 서비스처럼 k8s 클러스터 안에 따로 파드를 만들어 접속할 필요가 없다. 바로 웹 브라우저를 열고 localhost:30080으로 접속해도 nginx 웹페이지가 보인다.

직접 해보자.

두번째 사진에서 Nodeport 타입이지만, cluster-ip 항목이 10.108.71.88로 설정되었음을 알 수 있다. port(s) 항목에서는 80:30080/TCP로 표현되어 있는데, 이는 노드의 30080 포트가 CLusterIP 타입 서비스의 80 포트와 연결되었다는 뜻이다.

7.3.3 LoadBalancer 타입 서비스

apiVersion: v1
kind: Service
metadata:
  name: loadbalancer-service
spec:
  type: LoadBalancer
  selector:
    app: nginx-for-svc
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

구조는 교재 참고. k8s 클러스터를 외부 로드밸런서와 연계해 설치했을 때 사용하는 타입의 서비스이다.

기본 정보인 CLUSTER-IP 항목에 IP가 할당되었다. EXTERNAL-IP 항목은 이전과는 다르게 localhost이다. PORT(S) 항목도 30267 포트임을 확인 가능하다.

도커 데탑에는 외부 로드밸런서가 없어 EXTERNAL-IP가 localhost로 나타난다. 만약 외부 로드밸런서가 연계된다면 실제 외부에서 접근가능한 IP가 나타날 것이다.

7.3.4 ExternalName 타입 서비스

apiVersion: v1
kind: Service
metadata:
  name: externalname-service
spec:
  type: ExternalName	------- 1
  externalName: google.com	--- 2
  1. 이름 설정
  2. 연결하려는 외부 도메인 설정

클러스터 안에서 사용하지 않으므로 CLUSTER-IP가 none이다. EXTERNAL-IP는 앞서 설정한대로 google.com이다. PORT(S)도 none이다.

잘 동작하는지 테스트해보자

Externalname 서비스의 클러스터 내부 도메인은 externalname-service.default.svc.cluster.local이다.
curl 명령어는 오류 뜨는데 dig 명령어는 잘 작동하낟.
dig는 DNS설정이 올바른지 확인하기 위해 사용했고, DNS레코드가 CNAME타입의 google.com으로 설정되었음을 확인하기 위해서이다.

7.4 헤드리스 서비스

.spec.clusterIP필드 값을 None으로 설정하면 헤드리스 서비스를 만들 수 있다. 로드밸런싱이 필요없거나 단일 서비스 IP가 필요없을 때 사용한다.

여기에 셀렉터.spec.selector를 설정하면 쿠버네티스 API로 확인할 수 있는 엔드포인트가 만들어진다. 서비스와 연결된 파드를 직접 가리키는 DNS A 레코드도 만들어진다. 셀렉터가 없으면 엔드포인트가 만들어지지 않는다. 단, 셀렉터가 없어도 DNS시스템은 ExternalName 타입의 서비스에서 사용할 CNAME 레코드가 만들어진다.

IP항목은 None이지만, Endpoints 항목에는 .spec.selector 필드에서 선택한 조건에 맞는 파드들의 IP와 포트정보를 확인할 수 있다.

DNS A 레코드가 만들어져 있는지 확인 가능하다.

7.5 kube-proxy

k8s에서 서비스를 만들었을 때 클러스터 IP나 노드포트로 접근할 수 있게 만들어 실제 조작을 하는 컴포넌트이다. k8s 클러스터의 노드마다 실해오디면서 클러스터 내부 IP로 연결하려는 요청을 적절한 파드로 전달한다.

kube-proxy가 네트워크를 관리하는 방법은

  • userspace
  • iptables
  • IPVS

가 있다. 초기에는 userspace가 기본 관리 모드였고, 현재는 iptables이다.

7.5.1 userspace 모드

클라이언트에서 서비스의 클러스터 IP를 통해 어떤 요청을 하면 iptables를 거쳐 kube-proxy가 요청을 받는다. 그리고 서비스의 클러스터 IP는 연결되어야 하는 적절한 파드로 연결해준다.

7.5.2 iptables 모드

kube-proxy가 iptables를 관리하는 역할만 한다는 점이 userspace와 다르다. 클라이언트에서 오는 모든 요청은 iptables를 거쳐 파드로 직접 전달된다. 그래서 userspace모드보다 요청 처리 성능이 좋다. userpace모드에서는 파드 하나로의 연결요청이 실패하면 자동으로 다른 파드에 연결을 재시도한다.

그러나 iptables모드에서는 재시도하지 않고 요청이 그냥 실패한다.

7.5.3 IPVS 모드

리눅스 커널에 있는 L4 로드밸런싱 기술이다. 커널 공간에서 동작하고 데이터구조를 해시테이블로 저장하기 때문에 iptables모드보다 빠르고 성능이 좋다.

주요 로드밸런싱 알고리즘

  • round robin : 순서와 시간단위 기준
  • least connection : 접속개수가 적은 서버
  • destination hashing : 목적지 IP주소로 해시값을 계싼해 분산할 서버 선택
  • source hashing : 출발지 IP주소로 해시값 계산
  • shortest expected delay : 응답속도 가장 빠른 서버
  • never queue : sed 와 비슷하나, 활성접속 개수가 0인 서버 선택

0개의 댓글