본문 바로가기
쿠버네티스 :: Kubernetes/01 쿠버네티스 용어 살짝 맛보기

03 쿠버네티스 기본이해

by Jasie 2020. 6. 30.

1장은 쿠버네티스를 맛보기 위한 공간입니다.

 

 

 

구글의 내부 컨테이너 서비스를 Borg라고 하는데, 이 구조를 오픈소스화한것이 쿠버네티스이다.
GO 언어로 구현이되었으며, 특정 클라우드벤더사나 플랫폼에 종속되지 않기 때문에 대부분의 
퍼블릭 클라우드 (GCP,AWS,Azure)등에 사용이 가능하고 오픈 스택과 같은 프라이빗 클라우드 구축 환경이나 
가상화 환경을 사용하지 않는 일반 서버에도 배포가 가능하다.

 

 

 

 

하드웨어 자원 활용의 효율성이 좋기때문이다.
컨테이너 환경은 말그대로 하드웨어 자원을 컨테이너 화하여 격리(Isolation) 하는 기능이고 
그에 반해 가상화 환경은 격리(Isolation) 기능이 있고 더불어 가상화를 통해서 자원과 CPU의 수를 늘릴 수 있다.

 

 

 

 

1. 마스터와 노드

쿠버네티스는 전체 클러스터를 관리하는 마스터와 컨테이너가 배포되는 노드로 구성되어 있다.

 

모든 명령은 마스터의 API 서버를 호출하고 노드는 마스터와 통신하면서 필요한 작업을 수행하는데 특정 노드의

 

컨테이너에 명령하거나 로그를 조회할 때도 노드에 직접 명령하는 게 아니라 마스터에 명령을 내리고 마스터가 노드에 접속하여 대신 결과를 응답합니다.

 

  • Master

마스터 서버는 다양한 모듈이 확장성을 고려하여 기능별로 쪼개져 있는 것이 특징이며관리자만 접속할 수 있도록 보안 설정을 해야 하고 마스터 서버가 죽으면 클러스터를 관리할 수 없기 때문에 보통 3대를 구성하여 안정성을 높입니다.

AWS EKS 같은 경우 마스터를 AWS가 관리하도록하여 안정성을 높였다 하지만 마스터에 접속이 불가능하다. 가끔 개발 환경이나 소규모 환경에선 마스터와 노드를 분리하지 않고 같은 서버에 구성하기도 한다.

 

[그림] Master 구성 요소

 

  • API Server (kube-apiserver)

    API 서버는 모오오든 요청을 처리하는 마스터의 핵심 모듈입니다.
    kubectl의 요청뿐 아니라 내부 모듈의 요청도 처리하며 권한을 체크하여 요청을 거부할 수 있습니다. 실제로 하는 일은 원하는 상태를 key-value 저장소에 저장하고 저장된 상태를 조회하는 매우 단순한 작업입니다.

    Pod을 노드에 할당하고 상태를 체크하는 일은 다른 모듈로 분리되어 있습니다. 노드에서 실행 중인 컨테이너의
    로그를 보여주고 명령을 보내는 등 디버거 역할도 수행합니다.

  • etcd (분산 데이터 저장소)

    RAFT 알고리즘을 이용한 key-value 저장소입니다. 여러 개로 분산하여 복제할 수 있기 때문에 안정성이 높고 속도도 빠른 편입니다. 단순히 값을 저장하고 읽는 기능뿐 아니라 watch 기능이 있어 어떤 상태가 변경되면 바로 체크하여 로직을 실행할 수 있습니다.

    클러스터의 모든 설정, 상태 데이터는 여기 저장되고 나머지 모듈은 stateless하게 동작하기 때문에 etcd만 잘 백업해두면 언제든지 클러스터를 복구할 수 있습니다. etcd는 오직 API 서버와 통신하고 다른 모듈은 API 서버를 거쳐 etcd 데이터에 접근합니다. k3s 같은 초경량 쿠버네티스 배포판에서는 etcd대신 sqlite를 사용하기도 합니다.


  • 스케쥴러& 컨트롤러

    API 서버는 요청을 받으면 etcd 저장소와 통신할 뿐 실제로 상태를 바꾸는 건 스케줄러와 컨트롤러 입니다.
    현재 상태를 모니터링하다가 원하는 상태와 다르면 각자 맡은 작업을 수행하고 상태를 갱신합니다.


  • 스케줄러 kube-scheduler

    스케줄러는 할당되지 않은 Pod을 여러 가지 조건(필요한 자원, 라벨)에 따라 적절한 노드 서버에 할당해주는 모듈입니다.


  • 큐브 컨트롤러 kube-controller-manager

    큐브 컨트롤러는 다양한 역할을 한다. 쿠버네티스에 있는 거의 모든 오브젝트의 상태를 관리 하는데 오브젝트별로 철저하게 분업화되어 Deployment는 ReplicaSet을 생성하고 ReplicaSet은 Pod을 생성하고 Pod은 스케줄러가 관리하는 식이다.

  • 클라우드 컨트롤러 cloud-controller-manager

    클라우드 컨트롤러는 AWS, GCE, Azure 등 클라우드에 특화된 모듈이다. 노드를 추가/삭제하고 로드 밸런서를 연결하거나 볼륨을 붙일 수 있는데 각 클라우드 업체에서 인터페이스에 맞춰 구현하면 되기 때문에 확장성이 좋고 많은 곳에서 자체 모듈을 만들어 제공하고 있습니다.


  • Node

    노드 서버는 마스터 서버와 통신하면서 필요한 Pod을 생성하고 네트워크와 볼륨을 설정한다.

    실제 컨테이너들이 생성되는 곳으로 수백, 수천대로 확장할 수 있고 각 서버마다 라벨을 붙여 사용목적(GPU 특화, SSD 서버 등)을 정의할 수 있다.

[그림] Node 구성요소

  • Kubectl

노드에 할당된 Pod의 생명주기를 관리하고 Pod을 생성하는데 Pod 안의 컨테이너에 이상이 없는지 확인하면서 주기적으로 마스터에 상태를 전달합니다.

API 서버의 요청을 받아 컨테이너의 로그를 전달하거나 특정 명령을 대신 수행하기도 합니다.

API 서버는 Json 또는 Protobuf형식을 이용한 http 통신을 지원한다.하지만 이러한 방식을 그대로 사용하면 불편하므로 보통 kubectl 이라는 명령 도구를 사용한다.

 

2. 쿠버네티스 오브젝트

쿠버네티스는 상태를 배포 및 관리하기 위한 대상을 오브젝트로 정의합니다.

기본으로 수십 가지 오브젝트를 제공하고 새로운 오브젝트를 추가하기가 매우 쉽기 때문에 확장성이 좋고 또한 커맨드 라인을 통해서 오브젝트 생성시 인자로 전달하여 정의를 하거나 또는 yaml이나 json 파일로 스펙을 정의할 수 있다.

Pod 내의 컨테이너는 IP와 Port를 공유한다. 그러므로 같은 Pod내의 모든 컨테이너가 통신할수있게된다.

그리고 Pod내의 배포된 컨테이너간에 디스크 볼륨을 공유할 수 있다.
최근 어플리케이션외의 솔루션 (로그수집기,Reverse proxy)이 같이 배포되는 경우가 많다.

각 컨테이너를 독립 시키면 파일 시스템이 분리되기 때문에 로그수집기가 다른 컨테이너까지 접근하지 못한다. 쿠버네티스의 경우 디스크 볼륨을 공유하면 Pod내에 컨테이너끼리 로그파일등을 읽어올수 있게된다.

 

  • Pod

쿠버네티스에서 가장 기본적인 배포 단위로 컨테이너를 포함하는 단위다.

쿠버네티스 특징은 컨테이너를 하나씩 배포하는 것이 아니라 Pod 라는 단위로 배포하고 Pod는 하나 이상의 컨테이너를 포함한다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.7.9
    ports:
    - containerPort: 8090

 

  • apiVersion은 이 스크립트를 실행하기 위한 쿠버네티스 API 버전이다 대게 v1을 사용한다.
  • kind 에는 리소스의 종류를 정의하는것이고 Pod를 정의하려고 할 것이기 때문에 Pod를 써준다.
  • metadata에는 이 리소스의 각종 메타 데이타를 넣는데, 라벨(뒤에 설명할)이나 리소스의 이름및 각종 메타데이타를 넣는다
  • spec 부분에 리소스에 대한 상세한 스펙을 정의한다.

Pod는 컨테이너를 가지고 있기 때문에 container 를 정의한다. 이름은 nginx로 하고 도커 이미지 nginx:1.7.9 를 사용하고, 컨테이너 포트 8090을 오픈한다.

 

  • Service


클러스터내의 어디에 있는지에 상관없이 고정된 주소를 이용해서 접근이 가능하며 네트워크와 관련된 오브젝트이다. Pod 외부 네트워크와 연결을 담당하고 여러 개의 Pod로 로드밸런싱이 필요할때 생성할 때 사용된다.

내부 DNS에 서비스 이름을 도메인으로 등록하기 때문에 Service Discovery역할을 하기도 한다.

 

kind: Service
apiVersion: v1
metadata:
  name: test-service
spec:
  selector:
    app: testapp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9333

 

- 리소스 종류가 Service이므로 kind를 Service라 지칭하였다.
- 스크립트를 실행할 API 버전을 v1로 지정했다.
- 서비스의 이름을 test-service로 지정했다.
- spec에는 현재 서비스에 대한 스펙을 정의한다
> selector를하여 라벨에 app:testapp인 Pod만 선택해 서비스를 제공하게한다.
> 포트는 TCP를 이용하며 서비스는 80번 포트로한다. 그리고 서비스의 80번 포트 요청을 컨테이너의 9376번 포트로 연결해서 서비스를 제공한다.

 

  • Volume

저장소와 관련된 오브젝트입니다.
컨테이너마다 로컬 디스크를 그대로 사용할 수도 있고 EBS 같은 스토리지를 동적으로 생성하여 사용할 수도 있습니다.

하지만 컨테이너의 로컬 디스크는 영구적이지 못하고 Pod 설정에 따라서 새롭게 정의되서 배포되기 때문에 디스크에 기록된 내용이 유실된다.

쿠버네티스는 인기 있는 대부분의 저장 방식을 지원합니다.

볼륨은 컨테이너의 외장 디스크로 생각하면 된다.

 

  • ReplicaSet

Pod을 1개 이상을 복제하여 관리하는 오브젝트입니다.
Pod을 생성하고 개수를 유지하려면 반드시 ReplicaSet을 사용해야 합니다.

ReplicaSet은 복제할 개수, 개수를 체크할 라벨 선택자, 생성할 Pod의 설정값을 가지고 있습니다.
직접적으로 ReplicaSet을 사용하기보다는 Deployment등 다른 오브젝트에 의해서 사용되는 경우가 많습니다.

  • Deployment

디플로이먼트에서 의도하는 상태 를 설명하고, 디플로이먼트 컨트롤러(Controller) 는 현재 상태에서 의도하는 상태로 비율을 조정하며 변경한다.

새 레플리카셋을 생성하는 디플로이먼트를 정의하거나 기존 디플로이먼트를 제거하고, 모든 리소스를 새 디플로이먼트에 적용할 수 있다.

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

 

metadata.name 필드에 따라 nginx-deployment 이름으로 디플로이먼트가 생성된다.

replicas 필드에 따라 디플로이먼트는 3개의 레플리카 파드를 생성한다. selector 필드는 디플로이먼트가 관리할 파드를 찾는 방법을 정의한다

이 사례에서는 간단하게 파드 템플릿에 정의된 레이블(app: nginx)을 선택한다. 그러나 파드 템플릿 자체의 규칙이 만족되는 한, 정교한 선택 규칙의 적용이 가능하다.

template 필드에는 다음 하위 필드가 포함되어있다. Pod는 labels 필드를 사용해서 app: nginx 이라는 레이블을 붙인다.

Pod 템플릿의 사양 또는 .template.spec 필드는 Pod가 도커 허브의 nginx 1.7.9 버전 이미지를 실행하는 nginx 컨테이너 1개를 실행하는 것을 나타낸다.

컨테이너 1개를 생성하고, name 필드를 사용해서 nginx 이름을 붙인다.

 

 

  • 쿠버네티스 배포방식

쿠버네티스는 애플리케이션을 배포하기 위해 원하는 상태(desired state)를 다양한 오브젝트(object)에 라벨Label을 붙여 정의(yaml)하고 API 서버에 전달하는 방식을 사용합니다.

 

 “컨테이너를 Pod으로 감싸고 type=app, app=web이라는 라벨을 달아줘.

그리고난후 type=app, app=web이라는 라벨이 달린 Pod이 3개 있는지 
체크하고 없으면 Deployment Spec에 정의된 템플릿을 참고해서 Pod을 생성해줘.

그리고 해당 라벨을 가진 Pod을 바라보는 가상의 서비스 IP를 만들고 외부의 80 포트를 방금 만든 서비스 IP랑 연결해줘.”

 

다음과 같이 뭐 하나를 배포하더라도 이런식으로 설정을 해줘야한다.

그리고 쿠버네티스의 배포방식은 다음과 같다.

 

1. 블루/그린 배포방식 (무중단배포)

 

블루/그린 배포 방식은 블루(예전)버전으로 서비스 하고 있던 시스템을 그린(새로운)버전을 배포한 후, 트래픽을 블루에서 그린으로 한번에 돌리는 방식이다.

 

여러가지 방법이 있지만 가장 손쉬운 방법으로는 새로운 RC을 만들어서 새로운 템플릿으로 Pod를 생성한 후에, Pod 생성이 끝나면, 서비스를 새로운 Pod로 옮기는 방식이다.

 

여러가지 방법이 있지만 가장 손쉬운 방법으로는 새로운 RC을 만들어서 새로운 템플릿으로 Pod를 생성한 후에, Pod 생성이 끝나면, 서비스를 새로운 Pod로 옮기는 방식이다.

 

2. 롤링 배포 방식

 

 

롤링 업그레이드 방식은 Pod를 하나씩 업그레이드 해가는 방식이다. 이렇게 배포를 하려면 먼저 새로운 RC를 만든후에, 기존 RC에서 replica 수를 하나 줄이고, 새로운 RC에는 replica 수를 하나만 준다.

 

라벨을 같은 이름으로 해주면 서비스는 자연히 새로운 RC에 의해 생성된 Pod를 서비스에 포함 시키고 다음으로 기존 RC replica를 하나 더 줄이고 새로운 RC replica를 하나 더 늘린다.

 

그러면 기존 버전의 Pod가 하나더 서비스에서 빠지게 되고 새로운 버전의 Pod가 서비스에 추가되고 마찬가지 작업을 반복하게 되면, 아래 그림과 같이 예전 버전의 Pod가 모두 빠지고 새 버전의 Pod만 서비스 되게 된다.

 

만약에 배포가 잘못되었을 경우에는 기존 RC replica 수를 원래대로 올리고 새버전의 replicat 수를 0으로 만들어서 예전 버전의 Pod로 롤백이 가능하다.

 

이 과정은 kubectl rolling-update라는 명령으로 RC 단위로 컨트롤이 가능하지만 여전히 수작업이 필요하고 배포 과정을 모니터링 해야 한다.

 

그리고 가장 문제는 kubectl rolling-update 명령은 클라이언트에서 실행 하는 명령으로 명령어 실행중에 클라이언트의 연결이 끊어 지면 배포작업이 비정상적으로 끊어질 수 있는 문제가 있고 또한 롤백 또한 수동작업 해야할 필요도 있다.

 

이러한 과정을 자동화하고 추상화한 개념을 Deployment라고 보면 된다.

댓글