DevOps/Kubernetes

쿠버네티스(kubernetes) Deployment, Service

알로그 2022. 5. 14. 10:31
반응형

쿠버네티스(kubernetes) Deployment, Service

 

디플로이먼트(Deployment): 레플리카셋, 포드의 배포를 관리

쿠버네티스 운영환경에서 레플리카셋을 YAML 파일을 통해 사용하는 경우는 거의 없고, 대부분은 레플리카셋과 포드의 정보를 정의하는 디플로이먼트라는 이름의 오브젝트를 YAML 파일로 정의해서 사용한다. (디플로이먼트는 레플리카셋의 상위 수준의 오브젝트)

 

<deployment-nginx.yaml>

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-nginx
  template:
    metadata:
      name: my-nginx-pod
      labels:
        app: my-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.10
        ports:
        - containerPort: 80

 

디플로이먼트 생성

$ kubectl apply -f deployment-nginx.yaml
$ kubectl get deploy
$ kubectl get replicasets
$ kubectl get pods

 

디플로이먼트, 레플리카셋 함께 생성되어 있음

 

디플로이먼트를 삭제하면 레플리카셋, 포드 또한 삭제됨

kubectl delete deploy my-nginx-deployment

 

디플로이먼트를 사용하는 이유는 애플리케이션의 업데이트와 배포를 더 편하게 만들기 위해서다.

디플로이먼트를 이용해 앱의 버전을 업데이트해 배포하는 간단한 예시를 살펴보자.

$ kubectl apply -f deployment-nginx.yaml --record
$ kubectl get pods

 

nginx의 버전을 변경하려면..

$ kubectl set image deployment my-nginx-deployment nginx=nginx:1.11 --record

YAML 파일에서 직접 수정하거나 kubectl edit 명령어로도 사용 가능함

 

 

그 뒤에 레플리카셋의 목록을 출력해보면?

$ kubectl get replicasets

 

두 개의 레플리카셋이 있는 걸 볼 수 있다.

 

디플로이먼트는 포드의 정보를 업데이트함으로써 새로운 레플리카셋과 포드를 생성했음에도 불구하고 이전 버전의 레플리카셋을 삭제하지 않고 남겨두고 있다. 해쉬값이 변경되어 관리되며 이전의 정보를 리비전으로 보존한다.

 

리비전 정보를 다음 명령어로 더 자세히 확인 가능

$ kubectl rollout history deployment my-nginx-deployment

 

이전 버전으로 롤백하고 싶다면?

$ kubectl rollout undo deployment my-nginx-deployment --to-revision=1

 

리소스 정리

$ kubectl delete deployment, pod ,rs --all

 

 

서비스(Service): 포드를 연결하고 외부에 노출

현재까지는 로컬 개발 환경 또는 클러스터 내부에서만 접근이 가능했다.

포트를 외부로 노출해 사용자들이 접근하거나, 다른 디플로이먼트의 포드들이 내부적으로 접근하려면 서비스라고 부르는 별도의 오브젝트를 생성해야 한다.

 

서비스 기능

  • 고유한 도메인 이름을 부여함
  • 로드 밸런서 기능 수행
  • 포드를 외부로 노출

 

호스트 이름을 반환하는 간단한 웹 서버의 디플로이먼트 생성

<deployment-hostname.yaml>

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 apply -f deployment-hostname.yaml

 

서비스는 포드에 어떻게 접근할 것이냐에 따라 종류가 여러개로 세분화 된다.

목적에 맞는 적절한 서비스의 종류를 선택해야 하며 주로 사용하는 서비스 타입은 3가지다.

  • ClusterIP: 쿠버네티스 내부에서만 포드에 접근할 때 (관리자가 주로 사용)
  • NodePort: 클러스터의 모든 노드에 동일하게 개방
  • LoadBalancer: 로드 밸런스를 동적으로 프로비저닝하여 포드에 연결

 

ClusterIP 타입의 서비스

<hostname-svc-clusterip.yaml>

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 어떤 라벨을 갖는 포드에 접근할 수 있게 만들 것인지 결정
  • spec.ports.port: 쿠버네티스 내부에서만 사용할 수 있는 고유한 IP
  • spec.ports.tartgetPort: selector 항목에 의해 정의된 라벨에 의해 접근 대상이 된 포드들이 내부적으로 사용하고 있는 포트

 

서비스 목록 확인

$ kubectl apply -f hostname-svc-clusterip.yaml
$ kubectl get services
$ kubectl get svc # services

 

생성된 서비스를 확인할 수 있고, 출력 내용 중에서 CLUSTER-IP와 PORT(S)를 통해 요청 보내면 된다.

임시 포드를 만들어 요청해보면..

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

# 서버에 접속한 뒤
$ curl 10.101.98.33:8080 --silent | grep Hello
$ curl hostname-svc-clusterip:8080 --silent | grep Hello

 

서비스 이름 자체로도 접근 가능

서비스의 IP와 포트를 통해 포드에 접근하고 있으며, 별도의 설정을 하지 않아도 로드 밸런싱이 수행되어 요청이 분산됨

 

서비스 삭제

$ kubectl delete svc hostname-svc-clusterip
$ kubectl delete -f hostname-svc-clusterip.yaml

 

 

NodePort 타입의 서비스

ClusterIP 타입의 서비스는 내부에서만 접근 가능하지만, NodePort 타입의 서비스는 클러스터 외부에서도 접근 가능함

모든 노드의 특정 포트를 개방해 서비스에 접근하는 방식

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

 

서비스 생성하면..

$ kubectl apply -f hostname-svc-nodeport.yaml
$ kubectl get services

 

PORT(S) 항목에 31514라고 출력되는데, 이는 모든 노드에서 동일하게 접근할 수 있는 포트를 의미한다.

모든 노드에 내부 IP 또는 외부 IP를 통해 31514 포트로 접근하면 동일한 서비스에 연결할 수 있다.

 

한 가지 특이한 점은 kubectl get service 명령어에서 CLUSTER-IP 항목에 내부 IP가 할당되어 있는데, 이는 NodePort 타입의 서비스가 ClusterIP의 기능을 포함하고 있기 때문이다.

 

즉, NodePort 타입의 서비스는 내부 네트워크와 외부 네트워크 양쪽에서 접근할 수 있다.

 

 

 

클라우드 플랫폼의 로드 밸런서와 연동하기

LoadBalancer 타입의 서비스는 서비스 생성과 동시에 로드 밸런서를 새롭게 생성해 포드와 연결한다.

NodePort를 사용할 때는 각 노드의 IP를 알아야만 접근할 수 있었지만 LoadBalancer 타입의 서비스는 클라우드 플랫폼으로부터 도메인 이름과 IP를 할당받기 때문에 더 쉽게 접근할 수 있다.

 

일반적으로 AWS, GCP와 같은 클라우드 플랫폼 환경에서 LoadBalancer 타입을 사용할 수 있으며 가상 머신이나 온프레미스 환경에선 힘들 수 있다.

 

hostname-deployment라는 디플로이먼트는 미리 생성되어 있다고 가정

<hostname-svc-lb.yaml>

apiVersion: v1
kind: Service
metadata:
  name: hostname-svc-lb
spec:
  ports:
    - name: web-port
      port: 80
      targetPort: 80
  selector:
    app: webserver
  type: LoadBalancer

 

서비스 생성

$ kubectl apply -f hostname-svc-lb.yaml

 

LoadBalancer 타입 또한 NodePort나 ClusterIP와 동일하게 IP가 할당됨

눈여겨봐야 할 것은 EXTERNAL-IP가 생성되며 이는 클라우드 플랫폼에서 자동으로 할당된 것임

 

인프런: 대세는 쿠버네티스 강의자료 참조

 

추가 중급 서비스 내용

파드를 동시에 생성하는 경우에 파드에서 파드로 접근할 때, IP를 알 수 없으니 Headless를 이용하여 도메인을 통한 접근하는 방법과 파드와 서비스를 연결하는 Endpoint 그리고 ExternalName도 알아둘 것

 

 

References:

https://kubetm.github.io/k8s/03-beginner-basic-resource/service/

 

Service

ClusterIP, NodePort, LoadBalancer

kubetm.github.io

http://www.yes24.com/Product/Goods/84927385

 

시작하세요! 도커/쿠버네티스 - YES24

본서는 도커를 처음 접하는 개발자를 위한 도커 컨테이너와 이미지의 기본적인 개념을 먼저 설명한 뒤, 도커 컴포즈와 스웜 모드를 통해 컨테이너 애플리케이션을 YAML 파일로 작성하고 클러스

www.yes24.com

 

반응형