ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 쿠버네티스 커스텀 리소스(kubernetes Custom Resources)
    Kubernetes 2019. 1. 11. 09:00
    쿠버네티스는 api 구조 들이 잘 정의되어 있습니다. 그래서 뛰어난 확장성을 가지고 있습니다. 쿠버네티스에서 제공하는 내장된 리소스 뿐만 아니라 사용자가 필요한 리소스를 쿠버네티스 내부에 정의해서 사용할 수 있습니다. 이렇게 커스텀리소스(CustomResource)를 정의해 놓으면 쿠버네티스 시스템 내부에 녹아들어서 kubectl같은  쿠버네티스 기본 명령어들과 함께 사용하는 것이 가능해 집니다. 그리고 그런 리소스들을 이용하는 자신만의 api 컨트롤러들을 만들어서 사용하는 것이 가능합니다. 쿠버네티스에서 사용자가 원하는 모든 기능들을 기본 기능으로 제공하려 하기 보다는 자신들에게 필요한 기능들은 직접 추가해서 사용할 수 있도록 커스텀 리소스 관련 기능들을 제공하고 있습니다.

    커스텀 컨트롤러
    커스텀 리소스 자체는 구조화된 데이터일 뿐입니다. 커스텀리소스를 이용해서 원하는 동작을 하기위해서는 커스텀컨트롤러를 이용해야 합니다. 커스텀 리소스를 이용해서 사용자가 원하는 상태를 선언해 두면 커스텀컨트롤러가 그 상태를 맞추기위해 필요한 처리들을 하도록 합니다. 이렇게 쿠버네티스를 확장해서 사용하는 방법중 유명한 것으로는 코어OS사의 오퍼레이터(Operator)패턴과 구글에서 개발하기 시작한 서버리스 플랫폼인 Knative등이 있습니다.

    그럼 언제 커스텀컨트롤러를 이용해서 API를 만들어서 해야 할까요? 다음 몇가지 요건들을 생각해 볼 수 있습니다.
    • 추가하려는 API가 선언적(Declarative) 형식이다.
    • 추가한 타입을 kubectl을 이용해서 사용할 수 있어야 한다.
    • 추가한 타입을 쿠버네티스 대시보드 같은 UI에서 볼 수 있어야 한다.
    • 기존에 동작중인 API를 쿠버네티스에 추가하려는게 아니라 새로운 API를 개발중이다.
    • 쿠버네티스 스타일의 API 그룹과 네임스페이스 형식을 맞춰서 개발하는게 가능하다.
    • 추가하려는 리소스가 쿠버네티스 클러스터내부에서 동작하거나 특정 네임스페이스 내부에서만 동작해야 한다.
    • 쿠버네티스가 제공하는 기본 API지원 기능들을 활용한다.

    커스텀 리소스를 사용할려 할때 주의해야 할 점으로는 커스텀 리소스를 위한 저장공간이 추가로 필요하다는 점입니다. 그리고 커스텀 컨트롤러에 버그가 있어서 예상치 못한 장애가 발생할 수도 있다는 점입니다. 이런 점들을 주의해야 합니다.

    선언적(declarative) API란 어떤 형태일까요? 
    API들이 관련된 작은 객체(리소스)들의 조합으로 이루어져 있어야 합니다. 객체들의 조합으로 쉽게 모델링할수 없는 API는 보통 특정 동작을 해야하는걸 의미하기 때문에 선언적이 아닙니다. 무언가를 하는 동작으로 이루어 지는게 아닙니다. 객체들은 애플리케이션이나 인프라의 설정을 정의합니다. 특정 동작을 하도록 하도록 요청하지 않습니다. 객체들을 다루는 주된 동작은 CRUD(creating-생성, reading-읽기, updating-업데이트, deleting-삭제)입니다. 트랜잭션을 엄수해야하는 정확한 상태를 지정하는 형식은 안됩니다. 객체들이 어떤 상태일지를 바라는 상태만 나타내야합니다.


    커스텀 리소스와 컨피그맵
    커스텀 리소스도 객체의 조합일 뿐이라면 컨피그맵을 사용하면 되는것 아닌가라고 생각할 수도 있습니다. 컨피그 맵을 사용하는 경우와 커스텀 리소스를 사용해야 하는 경우를 생각해보면 다음과 같습니다.

    컨피그맵을 사용할 경우
    • 기존에 잘 정리된 포맷의 설정 파일인 경우 예) mysql.cnf, pom.xml
    • 전체 설정 파일 내용을 컨피그맵에 하나의 키로 등록해서 사용하려는 경우
    • 설정파일의 주용도가 포드내의 프로그램을 실행하는데 필요한 설정들인 경우
    • 쿠버네티스 API를 통하기 보다는 포드내의 파일이나 환경변수 형태로 파일을 사용하려는 경우.
    • 파일이 업데이트되면 디플로이먼트를 통한 롤링업데이트를 하고 싶을때.

    커스텀 리소스를 사용할 경우
    • 새 리소스를 만들거나 업데이트할때 쿠버네티스 클라이언트 라이브러리와 CLI를 사용하고 싶을 때
    • kubectl을 이용해서 리소스를 사용하고 싶을때
    • 객체의 업데이트를 지켜보고 있다가 다른 객체들을 CRUD하거나 반대의 경우에 대한 자동화를 만들고 싶을때.
    • 객체를 업데이트하는 자동화를 만들고 싶을때
    • 쿠버네티스 API에서 제공하는 .spec, .status, .metadata등의 정보를 사용하고 싶을때
    • 관리하는 리소스들이나 다른 리소스들의 모음을 추상화한 객체를 사용하고 싶을때

    CustomResourceDefinition 사용해서 커스텀 리소스 등록하기
    커스텀리소스를 정의하기 위해서는 CRD(CustomResourceDefinitions)을 이용해야 하는 방법과 Aggregated API를 이용하는 방법이 있습니다.
    각각의 특징은 다음과 같습니다.

    CRD(CustomResourceDefinitions)
    • 프로그래밍이 필요 없습니다. 사용자는 CRD컨트롤러를 만들기위해 원하는 언어를 이용할 수 있습니다.
    • 추가 서비스가 없어도 됩니다. 커스텀리소스는 API서버가 관리합니다.
    • CRD는 별도 관리를 하지 않더라도 기본 쿠버네티스 업그레이드와 버그픽스등을 함께 적용받아서 관리가 됩니다.

    Aggregated API
    • GO로 개발해서 바이너리와 이미지를 만들어야 합니다.
    • 추가 서비스를 만들어야 합니다.
    • 주기적으로 업스트림의 소스를 가져와서 변경사항을 반영하고 새로운 API서버 바이너리를 만드는 작업을 직접 진행해야 합니다.


    CustomResourceDefinition을 활용한 Custom Controller 사용하기

    CustomResourceDefinition은 다른 것들과 마찬가지로 yaml파일을 이용하면 됩니다.  아래처럼 파일 내용을 만든 후에 적용합니다.

    crd-mypod-spec.yaml
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      # name : 아래의 spec 필드와 맞아야 한다. spec의 plural와 group를 조합한 값이와야 한다. <plural>.<group>
    spec:
      # REST API 용 그룹 이름: /apis/<group>/<version>
      group: crd.example.com
      # API 버전
      version: v1
      # 이 CustomResourceDefinition이 지원하는 버전 정보
      versions:
        - name: v1
          # 버전이 사용가능한지 아닌지를 표시
          served: true
          # 스토리지 버전으로 지정되어야 하는 버전
          storage: true
      # Namespaced/Cluster 범위 표시
      scope: Namespaced
      names:
        # api URL에서 사용할 복수형 이름 : /apis/<group>/<version>/<plural>
        plural: mypods
        # CLI에서 사용할 단수형 이름
        singular: mypod
        # kind에 사용할 단수형 단어. 카멜케이스 형식.
        kind: MyPod
        # CLI에서 사용할 줄인 단어
        shortNames:
        - mpod


    kubectl apply -f crd-mypod-spec.yaml

    앞의 파일내용을 살펴보면 mypod라는 새로운 리소스를 정의한걸 확인할 수 있습니다.
    커스텀리소스 스펙을 정의했으니 이제 실제로 커스텀리소스를 만들어 보겠습니다.

    crd-mypod-sample.yaml
    apiVersion: "crd.example.com/v1"
    kind: MyPod
    metadata:
      name: my-new-pod-object
    spec:
      image: my-awesome-cron-image:latest
      ports:
        - containerPort: 8080

    kubectl apply -f crd-mypod-sample.yaml


    crd-mypod-sample.yaml 파일 내용을 확인해 보면 앞의 crd에서 정의했던 group에 있는 crd.example.com과 version에 있는 v1이 조합되서 apiVersion을 지정하고 있는걸 확인할 수 있습니다. kind에는 MyPod라는 새로운 리소스를 지정한걸 확인할 수 있습니다. spec부분에는 MyPod에서 사용할 리소스를 정의할 수 있습니다. 
    이제 이 리소스를 kubectl을 이용해서 확인할 수 있습니다. get을 이용해서 확인할 수도 있고 describe를 이용해서 상세내용을 확인할 수도 있습니다.


    mpod로 설정한 단축 리소스명도 잘 동작하는걸 확인할 수 있습니다.

    validation
    그런데 spec에 사용한 image와 ports를 MyPod의 CustomResourceDefinition 에 지정하지 않고 사용한걸 알 수 있습니다. 네, CustomResourceDefinition에는 spec을 명시하지는 않습니다. spec은 커스텀리소스에 설정하는대로 자유롭게 등록이 가능합니다. 쿠버네티스 1.13 버전부터는 spec에 어떤 내용을 설정할 수 있는지 검증할 수 있는 validation기능이 베타기능으로 추가되었습니다. crd-mypod-spec.yaml의 spec부분에 다음 내용을 추가하면 MyPod 커스텀리소를 추가할 때 image에 들어오는 정보가 지정한 패턴에 맞는지를 확인할 수 있습니다.
      validation:
       # openAPIV3Schema is the schema for validating custom objects.
        openAPIV3Schema:
          properties:
            spec:
              properties:
                image:
                  type: string
                  pattern: '^[a-zA-Z0-9_.-]*$'

    additionalPrinterColumns
    커스텀리소스에 대한 정보를 kubectl get으로 확인하면 NAME과 AGE정보만 보입니다. 이 정보만으로는 불충분하기 때문에 필요한 컬럼들을 추가해서 볼 수 있는 기능이 쿠버네티스 1.11 버전부터 추가되었습니다. 다음 내용을 spec에 추가하면 추가 정보를 볼 수 있습니다.
        additionalPrinterColumns:
        - name: Image
          type: string
          description: MyPod에서 사용할 image 정보
          JSONPath: .spec.image
        - name: Age
          type: date
          JSONPath: .metadata.creationTimestamp

    additionalPrinterColumns에 올 수 있는 속성에는 Priority, Type, JSONPath등이 있습니다. 
    Priority를 0으로 하면 일반적인 kubectl get을 했을때 보입니다. Priority를 0보다 크게 설정하면 -o wide 옵션을 주었을때 확인할 수 있습니다.
    Type은 컬럼의 데이터형을 지정하는데 다음과 같은 값이 올 수 있습니다.
    • integer – 정수형 숫자
    • number – 실수형 숫자
    • string – 문자열
    • boolean – true 또는 false
    • date – 생성된 시간



    댓글

Designed by Tistory.