k8s - 서비스

600g (Kim Dong Geun)·2021년 6월 27일
0

서비스

필요성

  • 여러개의 디플로이먼트를 하나의 완벽한 어플리케이션으로 연동하려면 포드 IP가아닌 서로를 발견(Discovery)할 수 있는 방법이 필요

    • ContainerPods 의 IP는 영속적이지 않아 변할 수 있음
  • 포트를 외부로 노출해 사용자들이 접근하거나, 다른 디플로이먼트의 포트들이 내부적으로 접근하려는 방법이 필요함.

정의

서비스는 포드에 접근하기 위한 네트워크 규칙을 정의하는 오브젝트

핵심기능

  1. 여러개의 포드에 쉽게 접근할 수 있도록 고유한 도메인 이름 부여
  2. 여러 개의 포드에 접근할 때, 요청을 분산하는 로드밸런서 기능 수행
  3. 클라우드 플랫폼의 로드밸런서, 클러스터 노드의 포트등을 통해 포드를 외부로 노출

서비스 종류

종류설명
ClusterIp 타입쿠버네티스 내부에서만 포드들에 접근할 때 사용, 외부로 포드 노출 X
따라서 클러스터 내부에서만 사용되는 포드에 적합
NodePort 타입포드에 접근할 수 있는 포트를 클러스터의 모든노드에 동일하게 개방, 따라서 외부에서 접근할 수 있는 서비스 타입. 접근할 수 있는 포트는 랜덤으로 정해지지만, 특정 포트로 지정가능
LoadBalancer 타입로드밸런서를 동적으로 프로비저닝해 포드에 연결, NodePort 타입과 마찬가지로 외부에서 접근할 수 있는 서비스 타입, 일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼환경에서만 사용가능.

실제 목적에 맞는 적절한 서비스 종류를 선택하는 것이 중요.

준비

# 이 Deployment로 Service 수행
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostname-deployment
spec: 
  replicas: 3
  selector:
    matchLabels:
      app: webserver
  template:
    metadata:
      name: my-webserver
      labels:
        app: webserver
    spec:
      containers:
      - name: my-webserver
        image: alicek106/rr-test:echo-hostname
        ports:
        - containerPort: 80
  • 다음명령어로 서비스가 제대로 생성되었는지 확인가능

    kubectl get pods
    kubectl get deployment
  • 포드 IP 를 확인한뒤 curl 로 HTTP 요청보내기
kubectl get pods -o wide

kubectl run -i --tty --rm debug \
--image=alicek106/ubuntu:curl --restart=Never {Pods IP} | grep Hello

--restart : 컨테이너 재시작 정책 always, never, OnFailure 등 존재.

서비스종류 : ClusterIP

apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-clusterip
spec:
  ports:
    - name: web-port
      port: 8080
      targetPort: 80
  selector:
    app: webserver
  type: ClusterIP
  
  • spec.selector: selector 항목은 이 서비스에서 어떠한 라벨을 가지는 포드에 접근할 수 있게 만들 것인지 확인

    kubectl describe deployment
    # 이후 selector name 확인

    위 예시에서는 app: webserver 라는 라벨을 가지는 포드들의 집합에 접근할 수 있는 서비스를 생성

  • spec.ports.port : 서비스 IP에 접근할때 사용할 포트를 설정

  • spec.ports.targetPort: selector 항목에서 정의한 라벨에 의해 접근 대상이 된 포드들이 내부적으로 사용하고 있는 포트를 입력

  • spec.type : 이 서비스가 어떤 타입인지 나타내는 것, 서비스의 종류에는 ClusterIP, NodePort, LoadBalacer 등이 존재

  • 서비스 생성
kubectl apply -f hostname-svc-clusterip.yaml
  • 생성된 서비스 목록 확인
kubectl get services
#or
kubectl get svc
  • 요청 전송
kubectl run -i --tty --rm debug --image=alicek106/ubuntu:curl --restart=Never --bash

curl {serviceIP}:{servicePort} --silent | grep Hello
  • 서비스에는 IP 뿐만 아니라 서비스 이름 그 자체로도 접근할 수 있습니다.

어플리케이션이 서비스나 포드를 쉽게 찾을 수 있도록 내부 DNS를 구동하고 있기때문에 가능.

curl hostname-svc-clusterip:8080 --slient | grep Hello

접근과정 요약

  1. 서비스의 yaml 파일의 selector 항목을 연결할 selector 와 동일하게 정의
  2. yaml 파일의 targetPort 정의
  3. kubectl apply -f 명령어로 클러스터 ip 타입의 ip 할당
  4. 접속요청이 들어오면 service가 endpoint로 해당 요청 전달
  5. 포드접근 수행
  • 서비스 삭제 명령어
kubectl delete svc hostname-svc-clusterip
kubectl delete -f hostname-svc-clusterip.yaml

서비스 종류 : NodePort

  • NodePort 타입은 클러스터 외부에서도 접근 가능
  • 단, 모든 노드의 특정포트를 개방해 서비스에 접근하는 방식
  • yaml 작성
apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-nodeport
spec:
  ports:
    - name: web-port
      port: 8080
      targetPort: 80
  selector:
    app: webserver
  type: NodePort
  • 서비스 확인
kubectl get services
kubectl get services

NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
hostname-svc-nodeport   NodePort    10.107.13.254   {serverIP}       8080:{port}/TCP   9s
kubernetes              ClusterIP   10.96.0.1       {serverIP}        443/TCP          55d

NodePort 타입의 서비스가 생성됐음을 알 수 있는데, PORT항목의 31139라는 숫자는 모든 노드에서 동일하게 접근할 수 있는 포트를 부여 받음을 의미

또한 nodeport 타입또한 ClusterIP가 부여되는 것을 볼 수 있는데, nodeport는 내부적으로 이용할 수 있는 clusterIP도 생성하면서, 외부에서도 접근가능하도록 할수 있음

접근과정

  • 노드 포트 지정
apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-nodeport
spec:
  ports:
    - name: web-port
      port: 8080
      targetPort: 80
      nodePort: 31000
  selector:
    app: webserver
  type: NodePort
  
# nodeport를지정함으로써 사용가능

default 옵션은 노드에서 개방되는 포트는 30000~32768 포트 중에 랜덤으로 선택됨

서비스종류 : LoadBalancer 타입

  • 로드밸런서 타입은 일반적으로 AWS, GCP 등과 같은 클라우드 플랫폼 환경에서만 LoadBalancer 타입을 사용할 수 있습니다.

  • 네이버 클라우드 플랫폼 또한 도커에 대한 로드밸런서를 지원하는듯 하나 현재 네이버 만 이용이 가능한 것으로 보임.

  • 따라서 온프레미스 환경의 MetalLB 를 사용

  • metalLB 설치

#MatalLb 설치
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.2/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.10.2/manifests/metallb.yaml
  • Secret 생성
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
  • configmap 설정
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.219.101-192.168.219.255
  • configmap 적용
kubectl apply -f hostname-configmap.yaml
  • service 적용
apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-lb
spec:
  ports:
    - name: web-port
      port: 8080
      targetPort: 80
  selector:
    app: webserver
  type: LoadBalancer
  • 확인
kubectl get svc -o wide
  • 요청 처리 방법

트래픽의 분배를 결정하는 서비스 속성 : externalTrafficPolicy

  • LoadBalancer타입의 서비스를 사용하면 외부로부터 들어온 요청은 노드 중 하나로 보내지며, 그 노드에서 다시 포드중 하나로 전달
  • 위와 같은 요청 전달 원리가 효율적이지 않을때가 있음.
    • A노드에 들어오는 요청이 B노드의 pod에 요청이 보내질때 등
    • 굳이 A 노드로 들어오는 요청을 B노드로 보낼 필요가 없음
  • 따라서 externalTrafficPolicy 설정에 따라 위 정책을 결정할 수 있음.
  • 서비스 설정 확인
kubectl get svc hostname-svc-nodeport -o yaml

# 혹은

kubectl get svc hostname-svc-lb -o yaml
  • 로드 밸런서 타입 변경
설정 값설명비고
Cluster같은 클러스터내에 묶여진 포드로 요청 전송 가능, 추가적인 네트워크 홉 발생할 수 있음.Default
Local포드가 생성된 노드에서만 포드로 접근 가능, 추가적인 네트워크 홉이 발생하지 않음

externalTrafficPolicy를 무조건 Local로 설정하는 것이 무조건 좋은 것은아님 예를들어, 각 노드에 포드가 고르지 않게 스케줄링 됐을때 요청이 고르게 분산되지 않을 수도 있기 때문입니다.

요청을 외부로 리다이렉트 하는 서비스 : ExternalName

  • 쿠버네티스를 외부 시스템과 연동해야 할 때 사용할 수 있는 옵션
apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-external
spec:
  type: ExternalName
  externalName: www.google.com
profile
수동적인 과신과 행운이 아닌, 능동적인 노력과 치열함

0개의 댓글