kubernetes started(5) 서비스(Service)

2020. 2. 15. 19:32devops/kubernetes

이전에 오브젝트들인 pod, raplicaset, deployment를 만들면 외부에서 접근할 수 없었습니다. 게다가 도커 컨테이너와 마찬가지로 포드의 IP는 영속적이지 않아 계속해서 변할 수 있습니다. 그리고 이전의 yaml 파일을 확인해보면 containerPort를 볼 수 있는데 그렇다고 해서 이  포트를 통해서 외부에서 접근할 수 없습니다. 

spec: 
      containers:
      - name: nginx
        image: nginx:1.10
        ports: 
          - containerPort: 80

그래서 디플로이먼트의 포드들이 외부에서 접근하려면 서비스라고 불리는 별도의 쿠버네티스 오브젝트를 생성해야합니다.

 

우리는 서비스를 통해 아래와 같은 기능을 사용할 수 있습니다. 

 

1. 여러 개의 포드에 쉽게 접근할 수 있도록 고유한 도메인의 이름을 부여합니다. 

2. 여러 개의 포드에 접근할 때 요청을 분산하는 로드 밸런서 기능을 수행합니다. 

3. 클라우드 플랫폼의 로드 밸런서, 클러스터 노드의 포트 등을 통해 포드를 외부로 노출합니다. 

 

쿠버네티스의 서비스는 포드에 어떻게 접근할 것이냐에 따라 종류가 여러 개로 세분화 돼 있다는 점입니다. 

 

  • ClusterIP: 쿠버네티스 내부에서만 포드들이 접근할 때 사용합니다. 외부로 노출하지 않기 때문에 쿠버네티스 클러스터 내부에서만 사용되는 포드에 적합합니다. 
  • NodePort: 포드에 접근할 수 있는 포트를 클러스터의 모든 노드에 동일하게 개발합니다. 따라서 외부에서 포드에 접근할 수 있는 서비스입니다. 
  • LoadBalancer: 클라우드 플랫폼에서 제공하는 로드 밸런서를 동적으로 프로비저닝해 포드에 연결합니다. NodePort와 같이 외부에서 접근할 수 있지만 특정 클라우드에서만 사용할 수 있다. (AWS, GCP...)

* 프로비저닝: 사용자의 요구에 맞게 시스템 자원 할당, 배치, 배포해 두었다가 필요시 시스템을 즉시 사용할 수 있는 상태로 미리 준비해두는 것을 말한다. 

 

ClusterIP

ClusterIP는 이전에 말했던 것과 같이 클러스터 내부에서만 이용할 수 있는 서비스입니다. 우선 2개의 yaml 파일을 만들어봅시다. 사용법은 apply -f를 사용하여 이전과 같습니다. 

 

1. Deployment

apiVersion: apps/v1
kind: Deployment
metadata: 
  name: service-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

2. Service 용

apiVersion: v1
kind: Service
metadata: 
  name: cluster-svc
spec:
  ports: 
    - name: web-port
      port: 8080
      targetPort: 80
  selector: 
    app: webserver
  type: ClusterIP
  

 

port: 8080을 통해 클러스터 안에서 접근할 수 있습니다. 그리고 위 Deployment가 80이라서 target의 port를 80으로 설정했습니다. selector를 통해 어떤 라벨을 갖고 있는 포드가 접그할 수 있게 만들 것인지 선택할 수 있습니다. 위 Deployment와 동일하게 webserver로 맞추어주었습니다. 

그럼 이제 포드안에 접속하여 내부 망을 통해 curl 요청을 보내보겠습니다. 요청을 보내기 이전에 get svc를 통해서 IP를 알아냅니다. 

kubectl get svc                                                                
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
cluster-svc   ClusterIP   10.111.23.144   <none>        8080/TCP   4s
kubernetes    ClusterIP   10.96.0.1       <none>        443/TCP    2d

아래 명령어로 ubuntu:curl로 실행한 후

kubectl run -i -tty --rm debug --image=alicek106/ubuntu:curl --restart=Never --bash
curl ServiceIP:8080 --silent | grep Hello
// 추가로 IP뿐만 아니라 도메인 이름을 통해서 접근할 수 있습니다. 
curl cluster-svc:8080 --silent | grep Hello

 

NodePort 타입 서비스

NodePort 타입의 서비스는 클러스터 외부에서도 접근할 수 있습니다. 이 방법은 모든 노드에 특정한 포트를 열어서 가능하게 만드는 것입니다. 

apiVersion: v1
kind: Service
metadata: 
  name: svc-nodeport
spec:
  ports:
    - name: web-port
      port: 8080
      targetPort: 80
  selector: 
    app: webserver
  type: NodePort

kubectl get services

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes     ClusterIP   10.96.0.1       <none>        443/TCP          2d1h
svc-nodeport   NodePort    10.104.73.173   <none>        8080:30012/TCP   42s

여기서 보이는 30012가 모든 노드에 동일하게 열린 포트입니다. 

kubectl run -i --tty --rm debug --image=alicek106/ubuntu:curl --restrat=Never -- bash

curl svc-nodeport:8080 --silent | grep Hello
	<p>Hello,  service-deployment-6cd58767b4-gfd5l</p>	</blockquote>
curl 10.104.73.173:8080 --silent | grep Hello

또한 위와 같이 접근해보면 이전 ClusterIP와 같이 기능을 사용할 수 있다. NodePort에는 ClusterIP의 기능을 포함하고 있기때문에 자동으로 clusterIP의 기능을 사용할 수 있습니다. 

 

그렇지만 실제로는 NodePort 서비스를 통해 외부로 제공하는 경우가 많지 않습니다. 왜냐하면 80에서 443으로 설정하기에 적절하지 않고 SSL 인증서, 라우팅 등과 같은 설정을 적용하기에는 어렵기 때문입니다. 그래서 NodePort 보다는 인그레스를 통해 제공합니다. 인그레스에 대해서는 추후에 추가하겠습니다.