티스토리 뷰

728x90
반응형

Kubernetes의 확장인 CRD Custom Resource Definition 와 CR Custom Resource 에 대한 개념 정리

기존에 Kubernetes 상의 Operator 나름대로 정리 라는 게시글을 작성했다.

게시글 자체는 Operator를 설명하기 위한 내용이었는데, 댓글로 문의를 주신 분들의 의문점들을 살펴보니 Operator의 관점에서 바라봤을 때 CRD와 CR에 대한 실체들에 대한 궁금점들이었기 때문에 근본적인 내용을 설명하는 것이 좋을 것 같아서 이 게시글을 작성한다.

Kubernetes의 기본적 동작 원리

Kubernetes 구성에 대한 자세한 내용은 Kubernetes Components 참고

  • Kubernetes는 상태관리 시스템

    이다.예를 들어 Replica를 3이라고 지정하면 Kubernetes가 Deployment 요청을 받았을 때 Replica 개수를 확인하고 Pod를 3개 실행시키려고 한다. 즉, 처음 배포되면 사용자가 정의한 Replica 값이 Pod 실행 개수라는 상태 값이 된다는 것이다.

  • 운영 중에 3개의 Pod 중에 1개 Pod가 오류로 중지되면 Kubernetes 입장에서는 3개가 유지 (Desired State) 되어야 하는 상태인데, 현재 상태는 2개 (Current State) 가 되므로 이를 다시 3개로 만들려고 액션을 취하게 된다.

  • 아주 간단한 예는 실행될 Pod의 개수를 의미하는 Replicas 설정이라고 생각하면 된다. 보통 애플리케이션을 작성하고 컨테이너 이미지를 만들고 Kubernetes에 실행을 맡기기 위해 Deployment Spec에 애플리케이션 정보 뿐만 아니라 Replica 개수를 지정하고 kubectl 명령을 통해 실행하게 된다.

  • 상태를 관리하는 것은 Controller의 역할

    이다.간단하게 정리하면 다음과 같다.

    1. Kubernetes는 Resource들의 변경을 감시하고 있다.
    2. 변경이 감지되면 Kubernetes는 관련된 이벤트를 발생시킨다.
    3. 발생된 이벤트는 Controller의 Reconcile 함수로 전달된다.
    4. Reconcile 함수에서 전달된 이벤트 데이터에 따라 Current State를 Desired State로 맞추기 위한 작업을 진행한다.
  • 위의 예에서 2개만 존재하는 Pod를 3개로 만들려고 액션을 취한다고 언급했는데, Kubernetes에서 상태가 변경된 것을 감지하고 상태를 맞추기 위해 실제 동작하는 것이 Controller 의 역할이다.

  • 모든 리소스는 GVR로 식별

    된다.G Group, V Version, R Resource 의 조합으로 모든 리소스를 식별한다. 아래와 같이 단순한 Deployment Spec를 보면 알 수 있다.위와 같이 Kubernetes의 모든 리소스들은 GVR 식별 구조를 가진다.

  • apiVersion: apps/v1 <<- Group이 apps, Version이 V1 kind: Deployment <<- Resource가 Deployment ...

  • Pod, Deployment, .. 모두 Kubernetes의 리소스로 Controller의 관리 대상들이다.

Kubernetes 확장을 위한 CRD 와 CR, 그리고 Operator

Kubernetes에서는 실제 애플리케이션 동작 및 운영에 필요한 Pod, Deployment, Service 등과 같이 기본적인 리소스 오브젝트만 제공하고 있다. 물론 이 정도만 있어도 사용하는데 문제가 없다.

요즘 많이 사용하고 있는 프로메테우스를 기준으로 확장을 검토해 보자.

Kubernetes 기본 오브젝트만을 기준으로 운영한다면 수집해야할 정보와 규칙들이 많아질 수록 프로메테우스의 설정이 복잡해지고, 대상 시스템에 따라서 하나 이상의 프로메테우스를 실행해서 연계 (Federation) 하거나 각각 메트릭 수집을 분리해서 운영하는 등의 작업이 필요한 상황들이 발생하게 된다.

운영자의 입장에서는 이런 작업들이 자동화되어 관리만 할 수 있는 것을 원할것이다. 그러나 Kubernetes에서는 이런 작업을 할 수 있는 방법이 없다. 이유는 Kubernetes는 상태관리 시스템이기 때문에 자동화를 위한 상태정보를 관리할 대상이 없기 때문이다.

Notes


실제 CRD, CR 구성을 위해서는 Operator Framework, KubeBuilder 등의 툴을 사용해서 개발해야 한다.

아래의 내용은 그냥 개념적인 이해를 위해 서술한 것이므로 주의해야 한다.

Kubernetes의 관점에서는 사용자정의 리소스를 의미하지만 아래의 설명에서는 개발적인 관점에서 이해하기 쉽도록 오브젝트라고 명기 또는 혼용한다.

개발 언어 (여기서는 Go) 관점에서 풀어보면 구조체 Structure 를 오브젝트 데이터 관리용으로 사용한다. 구조체에서 관리할 데이터 항목과 형식을 지정하며, 관리할 데이터를 정의한다.

type struct HelloSpec {
  Message string    `json:"message"`
  ...
}

우리가 오브젝트를 만들었다고 해도 Kubernetes는 이 오브젝트를 인식하지 못하기 때문에 GVR 형식으로 Kubernetes가 인식할 수 있도록 등록해 줘야 한다. 즉,

Kubernetes에 사용자가 정의한 오브젝트(Kubernetes에서는 리소스)에 대한 이름과 형식과 사이즈등의 데이터 관리 정보를 GVR 기준으로 정의한 것이 CRD

다.

아래의 내용은 간단하게 CRD를 구성한 매니페스트 파일이다. (hello_crd.yaml)

apiVersion: apiextensions.k8s.io/v1        # Kubernetes에서 제공하는 CRD용 Group과 Version
kind: CustomResourceDefinition                # Kubernetes에서 제공하는 Resource
metadata:
  name: hellos.examples.com              # CRD 식별명
spec:
  group: examples.com                # Group
  versions: 
    - name: v1alpha1        # Version
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                message:        # 필드명
                  type: string  # 필드 형식
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
  names:
    kind: Hello                            # Resource
    plural: hellos                    # List 등으로 표현할 Resource의 복수형
  scope: Namespaced                    # Namespace 범위로 한정

이 CRD는 아래의 명령으로 실행하고 생성된 내역을 확인할 수 있다.

> kubectl apply -f hello_crd.yaml
customresourcedefinition.apiextensions.k8s.io/hellos.examples.com created

> kubectl get crd
NAME                                                  CREATED AT
...
hellos.examples.com                                   2021-11-19T04:30:20Z
...

단지 Kubernetes에 사용할 오브젝트에 대한 정보만 등록을 한 것 뿐이기 때문에 현재는 할 수 있는 것이 아무것도 없다.

Kubernetes가 상태관리 시스템이라고 했기 때문에

CRD로 Kubernetes가 인식할 수 있는 오브젝트의 정의를 등록했다면, 실제 상태 정보를 관리할 수 있는 오브젝트가 CR

이다. 개발 언어로 이해한다면 클래스가 CR 이라고 생각하면 된다. CR로 생성한 실체들이 인스턴스가 된다.

아래의 내용은 간단하게 CR을 구성한 매니페스트 파일이다. (hello_cr.yaml)

apiVersion: examples.com/v1alpha1        # CRD에서 지정한 Group/Version
kind: Hello                                                    # CRD에서 지정한 Resource Kind
metadata:
  name: my-new-hello-object                    # CR 식별명 (오브젝트 인스턴스 식별)
spec:
  message: "hi crd!!"                                # 필드에 저장할 값

이 CR은 아래의 명령으로 실행하고 생성된 내역을 확인할 수 있다.

> kubectl apply -f hello_cr.yaml
hello.examples.com/my-new-hello-object created

> kubectl get Hello        # Hello Resource Kind에 대해 생성된 인스턴스들 조회
NAME                  AGE
my-new-hello-object   33m

> kubectl describe Hello my-new-hello-object  # 인스턴스 정보 상세 조회
Name:         my-new-hello-object
Namespace:    koreobs-system
Labels:       <none>
Annotations:  <none>
API Version:  examples.com/v1alpha1
Kind:         Hello
Metadata:
  Creation Timestamp:  2021-11-19T05:00:07Z
  Generation:          1
  Managed Fields:
    API Version:  examples.com/v1alpha1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
      f:spec:
        .:
        f:message:
    Manager:         kubectl-client-side-apply
    Operation:       Update
    Time:            2021-11-19T05:00:07Z
  Resource Version:  47889293
  Self Link:         /apis/examples.com/v1alpha1/namespaces/koreobs-system/hellos/my-new-hello-object
  UID:               89f3c291-64d7-4e77-aacb-fec1106813f8
Spec:
  Message:  hi crd!!        # 필드 값을 가지고 있다.
Events:     <none>

위의 같이 생성된 CR의 인스턴스가 상태정보를 가지는 실체가 된다. 위의 예에서 Hello은 CRD로 정의한 오브젝트고, my-new-hello-object는 생성되어 실체를 가지는 인스턴스가 된다.

단, 지금까지 작업한 것은 단지 사용자가 운영할 새로운 리소스를 생성하고 etcd에 정보를 저장하는 것 뿐이다. 아직 Kubernetes의 기본 리소스인 Pod, Deployment, Service와 같이 실행 가능한 리소스들과 연계해서 움직이는 것은 아니다.

위에서 Kubernetes의 기본 리소스들의 상태가 변경되면 이를 처리해주는 것이 Controller라고 언급했다. 따라서 여기서 생성한 Hello 의 인스턴스인 my-new-hello-object 의 상태 값이 변경되면 (예를 들어 “hi crd!!” 값을 “hi controller” 라고 변경했을 경우 등) 연결될 Controller가 없기 때문에 동작하지 않는 상태다.

따라서 사용자 리소스의 인스턴스들에 변경이 발생했을 때 Kubernetes를 통해 변경 이벤트를 받아서 처리할 사용자 정의 Controller가 필요하다.

Notes


이 부분은 Operator에 대한 샘플들을 찾아보면 된다. 여기서는 개념적인 이해를 위한 것이기 때문에 따로 설정하지 않는다.

상태 값을 출력하는 Pod를 운영한다는 가정을 하고 어떻게 운영되는지를 정리해 보도록 한다.

  1. Hello CRD 를 구성해서 Kubernetes에 등록 : Kubernetes에서는 CRD를 인식할 수 있고, CR 인스턴스가 생성되면 상태를 저장할 수 있다.
  2. Custom Controller 작성 및 Kubernetest에 연결 : Operator 작성 및 배포 방식에 따라서 Kubernetes에 등록, Custom Controller는 CR 인스턴스에서 변경이 발생하면 정보를 받아서 처리할 Reconcile 함수를 가지고 있다. 여기서는 전달된 CR 인스턴스를 통해 단순히 Eco 기능만 제공하는 Pod를 동작 시키는 Deployment를 구성하고 실행하는 것으로 가정한다.
  3. 사용자가 Hello 인스턴스 생성 : 생성도 상태 변경에 해당한다.
  4. Kubernetes는 이미 등록된 CRD와 Custom Controller를 인지하고 있기 때문에 다음과 같이 처리한다.
    4.1. Hello 인스턴스 생성에 따른 이벤트를 Custom Controller의 Reconcile 함수 호출 (이 부분의 연결고리는 Operator에 대해 검토해 보면 된다)
    4.2. Custom Controller에서 전달된 이벤트의 Hello 인스턴스 정보를 기준으로 Echo Deployment 구성 후 반환
    4.3. Kubernetes에서 반환된 Deployment를 실행해서 Pod 실행
  5. 사용자가 Hello 인스턴스의 Spec 값 변경 : 여기서는 Message ()
    1. 작업 재 실행.

위의 같이 단순한 작업의 흐름으로 볼 수 있다.

지금까지 설명한

CRD 구성 및 배포, Custom Controller 연계 및 실행등을 모두 합쳐 놓은 것이 Operator

다.

실제 사례로 바라보기

이전 게시글에서 가장 문의가 많았던 프로메테우스를 기준으로 다시 한번 정리해 보도록 한다.

Prometheus Operator

  • 그림에 점선 박스는 CRD를 의미하는 내용이다. 정확하게는 “ServiceMonitor” 와 “Prometheus” 라는 사용자 정의 리소스를 의미하고 있다.
    • “ServiceMonitor 1”, “ServiceMonitor 2” 는 “ServiceMonitor” 의 CR 인스턴스를 나타낸다.
      • ServiceMonitor 1 인스턴스는 Metric을 제공하는 Service 1, 2, 3 를 연계할 수 있는 Endpoint 정보를 상태 정보로 갖도록 정의되어 생성된 것이다.
      • ServiceMonitor 2 인스턴스는 Metric을 제공하는 Service 4, 5 를 연계할 수 있는 Endpoint 정보를 상태 정보로 갖도록 정의되어 생성된 것이다.
    • Prometheus 라는 CR 인스턴스는 ServiceMonitor CR 인스턴스와 관련된 정보 뿐만 아니라 Prometheus Server 구동에 필요한 정보들을 상태 정보로 갖도록 정의되어 생성된 것이다.
  • Operator는 ServiceMonitor와 Prometheus 라는 CR의 변경에 대한 처리를 담당한 Custom Controller를 구동하는 실행 모듈이다.
  • Prometheus Server는 실제 동작하는 Prometheus Server다.

이런 상황에서 사용자의 액션에 따라 다음과 같이 동작한다.

  • 사용자가 ServiceMonitor CR 인스턴스를 추가로 생성 (ServiceMonitor 3) 한 경우
    • Kubernetes에서 동작하는 Operator로 변경이 감지된다.
    • ServiceMonitor CR 정보를 Controller의 Reconcile 함수로 전달
    • Reconcile에서 ServiceMonitor CR 정보를 기준으로 Prometheus Server에서 인식할 수 있도록 Configmap 정보 재구성
    • 동작하고 있는 Prometheus 설정 (Configmap)을 재 로드하도록 처리
  • 사용자가 Prometheus CR 인스턴스의 값을 변경한 경우
    • Kubernetes에서 동작하는 Operator로 변경이 감지된다.
    • Prometheus CR 정보를 Controller의 Reconcile 함수로 전달
    • Reconcile에서 Prometheus CR 정보를 기준으로 Prometheus Server를 재 시동하도록 처리

정확하고 상세한 내용은 아니지만, 기존 게시글에 문의 되었던 것들이 이해될 수 있기를 바랍니다.

728x90
반응형
댓글
  • 프로필사진 pwc 그동안 알고 싶었던 Operator 뿐만 아니라 GVR에 대해서도 다시 한번 이해가 되네요. 좋은 글 보고 갑니다. 2022.02.27 15:40
댓글쓰기 폼