Kubernetes Operator를 만들어보자 1일차 - Operator란

0

Kubernetes Operator

목록 보기
1/5

Operator framework란

대부분의 개발 패러다임이 MSA구조로 변해가면서 kubernetes의 사용은 필수 불가결한 일이 되었다. 그러나, kubernetes를 사용하는 것은 굉장히 어려운 일이다. error들도 많고, 정교하게 config값들을 설정해주어야만 정상적인 동작들이 가능하다.

operator frameowrk는 이러한 문제를 해결하기 위해 kubernetes에 도입되었다. 이번 chapter에서는 operator에 대해서 알아보고 이 framework가 기존의 문제들을 어떻게 해결하는 지 알아보도록 하자.

Operator 없이 cluster 관리

kubernetes에는 다양한 design pattern, resource, controller들이 존재한다. 이러한 특징들 때문에 kuberntes에 배포되는 application들은 굉장히 복잡한 환경에 있을 수 밖에 없다.

가량, 간단한 web application이 user input을 받아서, 처리하고 저장한다고 하자. 가장 간단하게 생각해볼 수 있는 것은 user input을 받는 frontend pod와 user input을 받아 처리하고 database와 통신하는 backend pod가 있을 수 있다.

물론, database에 대한 pod도 있어야 한다. 해당 database는 Persistent Volume과 연결되어야 한다.

----------     ---------
|Frontend|-----|Backend|
----------     ---------
    \            /
     \          /
      ----------      ------------------
      |Database|------|PersistentVolume|
      ----------      ------------------

3 pod들 끼리의 interaction이 있고, 이들은 지속적으로 communication을 할 것이다. 문제는 이들 중 어떤 application pod는 언젠가 down되고 만다는 것이다. 이러한 분산 처리 시스템에서 에러가 발생하여 pod가 down되는 현상은 자연스러운 것이고, 오히려 문제없이 계속 동작할 것이라 생각하는 것이 잘못된 것이다.

cluster의 상태가 변경될 수 있는 여러가지 이유들이 있는데, 이러한 문제들을 수동으로 분석하고 처리해주는 것은 매우 귀찮은 일이다. 가령, database access 자격 증명이 변경되면, 해당 변경 사항을 모든 pod들에 전파해야한다. 이 전파 작업을 수동으로 처리해야한다면 매우 귀찮은 작업이 될 수 밖에 없다.

예상치 못한 장애가 발생한 경우 시간과 노력을 들여 하나하나 고치는 것도 중요하지만, operator framework가 자동으로 이러한 문제들을 해결해줄 수 있다. 이 application을 구성하는 pod 중 하나에 exception이 발생하거나 application 성능이 일부 저하되기 시작하면, '개입'이 필요하게 된다. '개입'을 위해서는 엔지니어가 배포 세부 사항을 알아야 할 뿐만 아니라 언제든지 가동 시간을 유지하기 위해 대기 중이어야 함을 의미한다.

관리자를 위해서 metric 집계 서버와 같은 application state와 성능을 모니터링 하는 추가 구성 요소를 만들 수있지만, 이러한 구성 요소는 기본적으로 작동 여부를 확인하기 위해 정기적으로 모니터링 해야하는 추가 application이므로 이를 클러스터에 추가하면 application을 수동으로 관리할 때와 동일한 문제가 모니터링 application에도 발생하는 것이다.

operator framework는 이러한 kubernetes 관리를 위한 수동 업무들을 자동으로 해주는 것이 전부이다. 또한, 딱히 새로운 개념이 아닌 것이 kubernetes cluster를 이미 자동화하는 많은 핵심 구성 요소와 기능적으로 크게 다르지 않다. 즉, controller와 핵심적으로 동일하며, operator는 controller와 같다.

Kubernetes controllers 탐색

kubernetes 자체는 다양한 default controller로 구성된다. 이 controller들은 사용자와 관리자가 설정한 cluster의 원하는 상태를 유지하도록 한다. Deployment, ReplicaSet, Endpoints는 자체 controller에서 관리하는 cluster의 몇 가지 resource 예이다. 이러한 resource에 관리자가 원하는 cluster 상태를 선언하는 것이 포함되며, 그런 다음 controller의 작업이 해당 state를 유지한다. 만약 설정한 state와 약간 다르면 controller는 해당 state를 설정한 state로 제어하기 위해 조치를 취한다.

이러한 controller들이 동작하는 방식 아주 간단하다. 현재 state를 모니터링하고 이를 설정한 state와 비교하여 작업하는 것이 전부이다. 가령 ReplicaSet의 pod가 3개를 유지해야하는데, 두 개뿐이라면 한 개를 신속하게 올려준다.

kubernetes의 controller들은 kube Controller Manager에 의해서 집합적으로 관리되어진다. kube Controller Manager는 controller의 또 다른 타입인데, controller의 상태를 감시하고 오류가 발생한 경우 오류 복구를 시도하거나 자동으로 복구할 수 없는 경우는 사람의 개입을 위해 오류를 보고한다. 따라서 다른 controller를 괸리하는 controller를 가지는 것이 가능한 것이다.

같은 방식으로, kubernetes operator는 운영 controller 개발을 사용자의 손에 맡긴다. 이는 관리자에게 kubernetes cluster 또는 사용자 정의 application의 모든 측면을 관리할 수 있는 controller를 작성할 수 있는 유연성을 제공한다. 보다 구체적인 놀리를 정의할 수 있는 기능을 통해 개발자는 kubernetes 주요 이점을 자신의 application의 고유한 사항에 맞게 확장할 수 있는 것이다.

Operator Framework의 지침에 따라 작성된 Operator는 default controller와 매우 유사하게 동작하도록 설계되었다. 도한, cluster의 현재 상태를 모니터링하고 이를 원하는 상태와 조정하는 방식으로 이를 수행한다. 특히 Operator는 고유한 workload 또는 구성 요소에 맞게 조정된다. 그런 다음 운영자는 다양한 방식으로 해당 구성 요소와 상호작용하는 방법을 알고 있는 것이다.

Operator의 핵심 용어들

operator에 의해 관리되는 component들을 operand라고 한다. 이들은 일종의 application, workload로서 operator에 의해 조정(reconciled)되어진다. 조심해야할 것은 operator는 operand를 조정하는 것을 도와주는 것이지 operand의 일을 대신해주는 것이 아니다. 가령 database backup이라던지, 복구와 같은 workload에 관한 일을 operator가 해주는 것이 아니라, 이 작업을 해주는 workload를 operand로 받아 도와주는 것이다.

cluster관리자는 operator와 상호작용하여 그들의 application을 설정하기 위해서 Custom Resource를 통해 접근해야한다. 즉, operator는 Custom Resource를 사용하여 operator의 설정, option들을 외부로 노출하는 것이다.

custom resource는 CustomResourceDefinition(CRD)를 따르는 API object이다. CRD는 user와 관리자가 kubernetes platform을 자신들의 resource object를 통해 확장시킬 수 있는 것이다. 즉, pod와 같은 API object를 custom하게 만들어 operator에서 의미있는 행동을 할 수 있도록 하는 것이다.

operator framework는 이러한 operator에 대한 개발, 배포에 관한 것으로 3가지 주요 부분이 존재한다. 이는 'coding', 'deployment', 'publishing of operators'이다. 이들을 Operator Framework가 제공하는 것이고, 이 3가지 부분을 잘게나누면 'Operator SDK', 'OLM', 'OperatorHub'이다. 참고로 OLM은 'Operator Lifecycle Manager'이다.

coding과 개발에 관한 것은 operator sdk가 담당하여 수많은 pattern들에 대해서 효율적으로 처리할 수 있다. 반면에 operator를 배포하고 공유하고 관리할 필요가 있는데, 이 부분의 경우 OLMOperatorHub가 담당한다. 이 둘을 통해서 operator를 자신의 cluster에 설치할 수 있으며, 남들과 공유할 수 있는 것이다.

Operator SDK를 통한 개발

Operator SDK를 통해서 이전에 정의한 API, 추상화된 common function, code generator, project scaffolding tool을 쉽게 제공해주어 operator project를 처음부터 개발할 수 있도록 해준다.

operator SDK는 주요하게 go로 만들어져있지만, go code 이외에도 ansible, helm으로도 가능하다. java와 같은 다른 언어들도 있지만, 굳이 go로 만들어진 operator를 꾸역꾸역 다른 언어로 할 필요가 없다고 생각한다.

operator-sdk라는 command를 통해서 개발자는 Operator SDK와 상호작용할 수 있는데 https://github.com/operator-framework/operator-sdk 다음의 site를 통해서 code를 보고 설치할 수 있다.

operator-sdk init 명령어를 사용하면 project source directory를 만들어주어 golang boilerplate와 의존성, script, Dockerfile, Makefile 등을 만들어준다. operator-sdk create api를 사용하면 operator와 상호작용하여 동작할 operand에 대한 CRD를 만들 수 있는데 필수적인 API를 만들어준다.

operator-sdk create apiflag를 통해 만드려는 CRD의 version과 API type을 지정할 수 있다. 이를 기반으로 golang code로 CRD struct를 만들고, 상응하는 YAML 파일을 만들어준다. 물론, 수정하는 것에는 어떠한 제약이 없다.

다음은 operator-sdk를 통해서 operator를 만드는 하나의 예제이다.

$ mkdir sample-app
$ cd sample-app/
$ operator-sdk init --domain mysite.com --repo github.com/sample/simple-app
$ operator-sdk create api --group myapp --version v1alpha1 --kind WebApp --resource –controller
$ ls
total 112K
drwxr-xr-x   15 mdame staff  480 Nov 15 17:00 .
drwxr-xr-x+ 270 mdame staff 8.5K Nov 15 16:48 ..
drwx------    3 mdame staff   96 Nov 15 17:00 api
drwxr-xr-x    3 mdame staff   96 Nov 15 17:00 bin
drwx------   10 mdame staff  320 Nov 15 17:00 config
drwx------    4 mdame staff  128 Nov 15 17:00 controllers
drwx------    3 mdame staff   96 Nov 15 16:50 hack
-rw-------    1 mdame staff  129 Nov 15 16:50 .dockerignore
-rw-------    1 mdame staff  367 Nov 15 16:50 .gitignore
-rw-------    1 mdame staff  776 Nov 15 16:50 Dockerfile
-rw-------    1 mdame staff 8.7K Nov 15 16:51 Makefile
-rw-------    1 mdame staff  422 Nov 15 17:00 PROJECT
-rw-------    1 mdame staff  218 Nov 15 17:00 go.mod
-rw-r--r--    1 mdame staff  76K Nov 15 16:51 go.sum
-rw-------    1 mdame staff 3.1K Nov 15 17:00 main.go

이후 해당 directory에서 operator 개발 작업을 진행하면 된다.

operator SDK는 또한 OLM과 상호작용하는 몇 가지 명령어들을 제공하는데, 이는 동작중인 cluster에 OLM을 설치하는 기능과 OLM안에서 특정 operator들을 설치하고 관리하는 기능을 제공해준다.

OLM을 통한 Operator들 관리

OLM은 kubernetes cluster 내에서 동작하는 component로 operator의 배포, 업그레이드를 편리하게 해준다. 또한, operator뿐만 아니라 operator에 있는 dependency들에 대해서도 설치와 패치를 도와준다. user들은 OLM을 operator command를 통해 상호작용할 수 있는데, 다음의 명령어를 통해서 OLM을 cluster에 초기화할 수 있다.

operator-sdk olm install

OLM은 operator를 설치하는 것 뿐만 아니라, cluster에 설치된 operator를 user가 찾을 수 있도록 일종의 catalog를 제공해준다. 또한, cluster의 operator를 제어함으로서 OLM은 operator API의 충돌과 cluster를 불안정하게 할 수 있는 것들 감시한다.

물론 OLM이 operator 구동에 반드시 필요한 것은 아니다. 단지, operator 관리를 용이하게해주고 security 측면에서의 이점이 있기 때문에, 많이들 추천되는 방법인 것이다.

operator를 개발할 때, operator image은 bundle로 컴파일된다. 그리고 bundleOLM이 통해 설치되는 것이다. bundle에는 operator를 설명하는 몇 가지 YAML file, CRD, 의존성들이 있다. OLM은 이 bundle의 내용물들을 통해 어떻게 처리하고 적절하게 cluster에서 operator를 관리할 지 알고있는 것이다.

operator의 code를 컴파일하고 operator를 배포하는 것은 아래의 명령어를 통해서 가능하다. 첫번째 명령어는 operator에 관한 YTAML manifest의 bundle을 빌드한다. 그 다음 이 bundle을 OLM에 전달하여 cluster에 operator를 동작시키는 것이다.

$ make bundle ...
$ operator-sdk run bundle ...

go code를 image와 OLM에 의해 해석 가능하고 배포 가능한 format으로 바꾸어 준다. 그러나 OLM을 통해서는 operator에 관한 정보를 제공하고 공유할 수는 없다. 이 기능은 OperatorHub가 해주는 것이다. OperatorHub는 platform으로서 image들을 다른 사용자들에게 전달하고 공유하는 기능을 하는 것이다.

Operator를 OperatorHub.io에 배포하기

OperatorHub를 통해서 Operator들을 공유하고 배포할 수 있다. 이는 공개된 sw로서 operator를 부담없이 설치하고 자유롭게 사용이 가능한 것이다.

https://operatorhub.io/

operator를 OperatorHub에 올릴 때는 standard format을 지켜서 올려야한다. 즉, 이는 operatorOLM과의 일관성과 compatibility를 보장해야한다는 것이다. 실제로 새로운 operator들은 OperatorHub에서 제공하는 github repository tool을 통해서 standard형식을 잘 지켰는 지 자동으로 검사받게된다.

operator를 OperatorHub로 등록할 때는 operator의 배포 정보가 들어있는 bundle을 만들고, operator에 대한 manifests를 만들어야 한다. 이러한 제출 과정은 Operator의 Cluster Service Version(CSV)에 의존한다. 이 CSV는 하나의 yaml file로 operator에 관한 metadata들을 제공한다. 가령 operator의 이름, version, keywords와 설치에 필요한 요구사항인 RBAC, CRDs API 등 operator가 소유한 cluster resource object들이 존재하는 것이다.

operator의 CSV에 포함된 내용은 다음과 같다.

  1. operator의 이름, version number, description, image format
  2. operator에 대한 annotations
  3. operator관련 opensource와 maintainer 연락처 정보
  4. 어떻게 operator가 cluster에 설치되는 지
  5. operator의 CRD에 대한 configuration 예제
  6. operator가 동작하는데 필요한 CRD와 또 다른 resources, 의존성들

Capability Model을 통한 Operator function 설계

operator framework는 capability model을 정의하는데 capability model은 operator의 기능과 설계에 기반하여 operator를 카테고리화 시킨다. 즉 capability model은 하나의 설계서이며 operator가 어떠한 기능을 제공하고 있는 지에 따라 성숙도를 범주화하는 것이다.

capability model은 5개의 계층적 구조로 나눌 수 있고, level이 올라갈수록 더욱 성숙해진 operator라고 평가할 수 있는 것이다.

  1. Level 1 - Basic Install: operator가 단순히 operand를 cluster에 설치만 하는 기능을 제공하고, 해당 operand에 의해 실행되는 workload의 status를 관리자에게 보고만해주는 정도이다.

level1 단계에서 operator는 Operator의 Custom Resource를 통해서 설치될 operand의 configuration에 도움을 준다. 즉, operator가 operand를 설치하고, 동작중인 operand의 workload에 대해서 configuration 사양을 조정(reconciling)해주는 것이다. 그러나, 만약 operand가 잘못된 설정이나 외부의 영향으로 인해 failed state에 빠지게 되면, operator는 더 이상 configuration 조정에 도움을 주지 못한다.

  1. Level 2 - Seamless Upgrades: 기본적인 설치 기능뿐만 아니라 upgrade에 대한 추가적인 기능을 제공한다. operand에 대한 upgrade 뿐만 아니라 operator 자체에 대한 upgrade도 제공하는 것이다.

자기자신에 대한 upgrade를 할 수 있는 operator는 operator가 upgrade될 때 oprand도 upgrade하거나, 수동으로 Operator의 Custom Resource를 수정함으로서 operator의 Operand를 upgrade할 수 있다.

seamless upgrade에서 operator는 old version operand를 upgrade할 수 있어야만 한다. 이러한 하위호환성은 새로운 version으로 upgrade시키는 것과 rollback 기능에 있어서 필수적이다.

  1. Level 3 - Full Lifecycle: level3에서는 operand lifecycle management feature 중 최소한 하나는 제공해야할 때 달성된다. level3부터는 operator가 더이상은 operand의 workload에 대해서 수동적으로 동작하지 않고, 적극적으로 operand의 동작에 관여하고 도움을 준다. 즉, 기존의 설치, 설정, 업그레이트 자동화는 set and forget 방식이었지만, 이제는 set후에도 operand를 관리해주는 것이다.

operand의 lifecycle 관리 요소들은 다음과 같다.

  1. operand의 backup을 생성 또는 backup을 통해 복구시키는 기능
  2. 더욱 복잡한 configuration과 multistep workflow들을 지원
  3. disaster recovery(DR) - failover와 failback 매커니즘을 제공. operator가 error를 만나게될 때 backup process(failover)로 동작하거나, 이전에 system 상태로 돌아가는(failback)을 제공해야한다.
  4. 군집화된 operand들을 관리하는 기능. 구체적으로 operand들의 member를 추가하고 삭제하는 기능이다. operator는 여러 replicas들을 실행하는 operands의 정족수(quorum)를 고려할 수 있어야 한다.
  5. read-only 기능으로 동작하는 worker instance로 Operand를 스케일링하는 기능을 지원

위의 feature중 하나 또는 그 이상을 구현하는 operator는 최소한 level 3 operator라고 할 수 있다. 이러한 operator는 DR과 scaling에 대한 기능을 제공할 수있는데, user가 증가함에 따라 자원 소모량이 증가하고 관리자는 operator를 통해서 추가적인 replica pod를 만들어 application을 scale up할 수 있도록 할 수 있다.

만약 pod 중 일부가 실패하면 operator는 fail over를 실행하는데, 아예 새로운 pod를 만들어버릴 수도 있고, 새로운 version으로 update하여 진행할 수도 있다.

  1. Level 4 - Deep Insights: 위에서는 operator의 operand workload에 대한 기능적인 상호작용을 집중했다면, level 4부터는 모니터링과 metric들에 집중한다. 이는 operator가 operator자체와 operand에 대해서 측정 가능한 insight를 제공할 수 있다는 것이다.

operator는 대부분 자신의 insight를 metrics 형식으로 제공하는데, 이 metrics형식은 prometheus와 같은 모니터링 서버와 호환이 가능하다. 물론 metrics 말고도 다른 방식으로 insight를 제공할 수 있는데, 이는 alert나 kubernetes event들이 있다. kubernetes event들은 cluster resource object들로 core kubernetes object와 controller에 의해 사용되는 것들이다.

  1. Level 5 - Auto pilot: 가장 고도화된 단계로, 이전 단계의 기능들과 가장 뛰어난 기능들을 제공한다. 이 단계에서는 operand의 workload가 영원히 안전하게, 자율적으로 동작하도록 하는데 집중한다. 이 단계에서는 auto scaling, auto healing, auto tuning, 이상검출 기능을 담당한다.

auto scaling은 operator가 application을 scale up할지 down할지 수요에 맞게 결정하는 기능이다. 현재의 performance load를 분석하여 operator는 더 또는 덜 resource가 필요할 지 결정한다.

auto healing은 operator가 operand의 비정상적인 상황에 대해서 보고하고, 적절한 조치를 취하는 것이다. operand가 error를 보고하면 operator는 error를 바로잡는 step들을 실행하는 것이다. 추가적으로 operator는 operand의 현재 metrics를 사용하여 operand가 비정상적인 상황에 빠지지 않도록 막을 수 있다.

auto tuning은 operator가 operand의 최고 성능을 끌어올리기 위해서 동적으로 operand를 변경하는 것이다. 이는 operand의 설정값들을 자동으로 변경하거나 복잡한 연산들을 할 수 있는데, 가령 workload들을 다른 node들에 전달하여 현재 node에 더 잘맞게 최적화하는 것이다.

이상검출 기능(abnormality detection)은 operator가 operand의 최적이 아니거나, 비정상적인 행동에 대해서 식별한다. 성능을 측정하여 operator는 application의 현재 그리고 그 동안의 기능 단계에 대한 청사진을 가진다. 이 데이터는 이전에 직접 설정한 하한값(성능 최소값)과 비교하기 위해 사용된다.

level1, 2에 대한 기능은 단순한 설치와 upgrade, 설정 파일 제공 정도이기 때문에 go, helm, ansible 모두 가능하다. 그러나 level3부터는 go와 ansible 이외에는 불가능하다.

Operator 기능 적용

            ----------    -----
            |Operator|----|CRD|----User!
            ----------    -----
                |
                |
---------------------------------------------
| ----------     ---------                  |
| |Frontend|-----|Backend|                  |
| ----------     ---------                  |
|    \            /                         |
|     \          /                          |
|      ----------      ------------------   |
|      |Database|------|PersistentVolume|   |
|      ----------      ------------------   |
---------------------------------------------

다음의 그림을 보면 하나의 Operator를 통해서 Frontend, Backend, Database, Persistent Volume(PV) 4가지를 Operand로 관리하고 있는 것을 볼 수 있다. 하나의 단일 지점인 Operator에 CRD를 제공함으로서, 여러 가지 setting들을 제어하고, 고도화된 기능들을 제공할 수 있는 것이다.

그림에서 보듯이 cluster administrator는 오직 Operator에 CRD를 제공함으로서 workload들을 관리하는 것을 볼 수 있다. 가령, application의 database 접근 정보를 변경하거나 application 동작을 변경, log level 등을 변경하는 기능들을 operator에게 명령을 내림으로서 동작할 수 있는 것이다.

0개의 댓글