커스텀 리소스
커스텀 리소스 (Custom Resources)
커스텀 리소스(custom resources) 는 API 확장을 통해 쿠버네티스에 추가된 리소스 유형의 인스턴스입니다. 이 페이지는 언제 쿠버네티스 클러스터에 커스텀 리소스를 추가해야 하고 언제 독립형 서비스를 사용해야 하는지 다룹니다. 두 가지 커스텀 리소스 추가 방법과 둘 사이에서 어떻게 선택하는지 설명합니다.
출처: 문서
본문
커스텀 리소스
리소스는 쿠버네티스 API의 엔드포인트로, 특정 종류의 API 객체 컬렉션을 저장합니다. 예를 들어 내장 pods 리소스는 Pod 객체의 컬렉션을 포함합니다.
커스텀 리소스는 기본 쿠버네티스 설치에서 반드시 사용 가능한 것은 아닌 쿠버네티스 API의 확장입니다. 이는 특정 쿠버네티스 설치의 사용자 정의를 나타냅니다. 그러나 많은 핵심 쿠버네티스 기능이 이제 커스텀 리소스를 사용해 구축되어, 쿠버네티스를 더 모듈화하고 있습니다.
커스텀 리소스는 동적 등록을 통해 실행 중인 클러스터에서 나타나고 사라질 수 있으며, 클러스터 관리자는 클러스터 자체와 독립적으로 커스텀 리소스를 업데이트할 수 있습니다. 커스텀 리소스가 설치되면 사용자는 내장 리소스 Pods처럼 kubectl을 사용해 그 객체를 만들고 접근할 수 있습니다.
커스텀 컨트롤러
커스텀 리소스만으로는 구조화된 데이터를 저장하고 검색할 수 있습니다. 커스텀 리소스를 커스텀 컨트롤러와 결합하면 커스텀 리소스는 진정한 선언형 API 를 제공합니다.
쿠버네티스 선언형 API는 책임의 분리를 강제합니다. 리소스의 원하는 상태를 선언합니다. 쿠버네티스 컨트롤러는 쿠버네티스 객체의 현재 상태를 선언한 원하는 상태와 동기화 상태로 유지합니다. 이는 서버에 무엇을 하라고 지시하는 명령형(imperative) API와 대조됩니다.
실행 중인 클러스터에 커스텀 컨트롤러를 클러스터의 수명과 독립적으로 배포하고 업데이트할 수 있습니다. 커스텀 컨트롤러는 어떤 종류의 리소스와도 작동할 수 있지만, 커스텀 리소스와 결합할 때 특히 효과적입니다. Operator 패턴은 커스텀 리소스와 커스텀 컨트롤러를 결합합니다. 커스텀 컨트롤러를 사용해 특정 애플리케이션에 대한 도메인 지식을 쿠버네티스 API의 확장으로 인코딩할 수 있습니다.
내 쿠버네티스 클러스터에 커스텀 리소스를 추가해야 하나요?
새 API를 만들 때, API를 쿠버네티스 클러스터 API와 통합(aggregate)할지 아니면 API를 독립적으로 둘지 고려하세요.
| 다음 경우 API 통합을 고려하세요: | 다음 경우 독립형 API를 선호하세요: |
|---|---|
| API가 선언형이다. | API가 선언형 모델에 맞지 않는다. |
새 유형을 kubectl로 읽고 쓸 수 있기를 원한다. |
kubectl 지원이 필요하지 않다. |
| 대시보드 같은 쿠버네티스 UI에서 내장 유형과 함께 새 유형을 보기를 원한다. | 쿠버네티스 UI 지원이 필요하지 않다. |
| 새 API를 개발 중이다. | 이미 API를 잘 서빙하는 프로그램이 있고 잘 동작한다. |
| 쿠버네티스가 REST 리소스 경로에 두는 형식 제한(API 그룹, 네임스페이스 등)을 수용할 의향이 있다. (API 개요 참조) | 이미 정의된 REST API와 호환되도록 특정 REST 경로가 필요하다. |
| 리소스가 자연스럽게 클러스터 또는 클러스터의 네임스페이스 범위에 속한다. | 클러스터 또는 네임스페이스 범위 리소스가 맞지 않다. 리소스 경로의 세부 사항을 제어해야 한다. |
| 쿠버네티스 API 지원 기능을 재사용하고 싶다. | 그 기능들이 필요하지 않다. |
선언형 API (Declarative APIs)
선언형 API에서 일반적으로:
- API는 상대적으로 적은 수의 작은 객체(리소스)로 구성된다.
- 객체는 애플리케이션 또는 인프라의 구성을 정의한다.
- 객체는 비교적 드물게 업데이트된다.
- 인간이 종종 객체를 읽고 써야 한다.
- 객체의 주요 작업은 CRUD적이다(생성, 읽기, 업데이트, 삭제).
- 객체 간 트랜잭션은 필요하지 않다: API는 정확한 상태가 아니라 원하는 상태를 나타낸다.
명령형 API는 선언형이 아닙니다. API가 선언형이 아닐 수 있는 신호:
- 클라이언트가 "이것을 해라"라고 말한 뒤, 완료되면 동기 응답을 받는 경우.
- 클라이언트가 "이것을 해라"라고 말한 뒤, 작업 ID를 받고 요청 완료를 결정하기 위해 별도의 Operation 객체를 확인해야 하는 경우.
- 원격 프로시저 호출(RPC)에 대해 이야기하는 경우.
- 대량의 데이터를 직접 저장하는 경우; 예를 들어 객체당 수 kB 초과, 또는 1000개 이상의 객체.
- 높은 대역폭 접근(지속적으로 초당 수십 개 요청)이 필요한 경우.
- 최종 사용자 데이터(이미지, 개인 식별 정보 등) 또는 애플리케이션이 처리하는 기타 대규모 데이터를 저장하는 경우.
- 객체에 대한 자연스러운 작업이 CRUD적이지 않은 경우.
- API가 쉽게 객체로 모델링되지 않는 경우.
- 보류 중인 작업을 작업 ID나 작업 객체로 표현하기로 선택한 경우.
ConfigMap을 사용해야 할까 커스텀 리소스를 사용해야 할까?
다음 중 하나라도 해당하면 ConfigMap을 사용하세요:
mysql.cnf나pom.xml같은 기존의 잘 문서화된 구성 파일 형식이 있는 경우.- 전체 구성을 ConfigMap의 한 키에 넣고 싶은 경우.
- 구성 파일의 주요 용도가 클러스터의 파드에서 실행되는 프로그램이 파일을 소비해 스스로를 구성하는 것인 경우.
- 파일의 소비자가 쿠버네티스 API보다는 파드의 파일이나 환경 변수를 통해 소비하는 것을 선호하는 경우.
- 파일이 업데이트될 때 Deployment 등을 통해 롤링 업데이트를 수행하고 싶은 경우.
민감한 데이터에는 ConfigMap과 유사하지만 더 안전한 Secret을 사용하세요.
다음 중 대부분이 해당하면 커스텀 리소스(CRD 또는 통합 API)를 사용하세요:
- 쿠버네티스 클라이언트 라이브러리와 CLI를 사용해 새 리소스를 생성·업데이트하고 싶은 경우.
kubectl의 최상위 지원을 원하는 경우; 예:kubectl get my-object object-name.- 새 객체의 업데이트를 지켜보고, 그 다음 다른 객체를 CRUD하거나 그 반대로 하는 새 자동화를 구축하고 싶은 경우.
- 객체 업데이트를 처리하는 자동화를 작성하고 싶은 경우.
.spec,.status,.metadata같은 쿠버네티스 API 관례를 사용하고 싶은 경우.- 객체가 제어된 리소스 컬렉션에 대한 추상화이거나 다른 리소스의 요약이기를 원하는 경우.
커스텀 리소스 추가하기
쿠버네티스는 클러스터에 커스텀 리소스를 추가하는 두 가지 방법을 제공합니다:
- CRD는 단순하고 프로그래밍 없이 만들 수 있습니다.
- API Aggregation은 프로그래밍이 필요하지만 데이터가 저장되는 방식과 API 버전 간 변환 같은 API 동작에 대한 더 많은 제어를 허용합니다.
쿠버네티스는 서로 다른 사용자의 요구를 충족하기 위해 이 두 옵션을 제공하므로, 사용 용이성이나 유연성 중 어느 것도 손상되지 않습니다.
통합(aggregated) API는 기본 API 서버 뒤에 있어 프록시 역할을 하는 기본 API 서버의 뒤에 있는 하위 API 서버입니다. 이 구성을 API Aggregation(AA)이라고 합니다. 사용자에게 쿠버네티스 API가 확장된 것처럼 보입니다.
CRD는 사용자가 API 서버를 추가하지 않고 새 유형의 리소스를 만들 수 있게 합니다. CRD를 사용하려면 API Aggregation을 이해할 필요가 없습니다.
설치 방식과 무관하게 새 리소스는 내장 쿠버네티스 리소스(예: pods)와 구분하기 위해 Custom Resources라고 불립니다.
커스텀 리소스를 애플리케이션, 최종 사용자 또는 모니터링 데이터의 데이터 저장소로 사용하는 것은 피하세요: 쿠버네티스 API 안에 애플리케이션 데이터를 저장하는 아키텍처 설계는 보통 너무 밀접하게 결합된 설계를 나타냅니다.
아키텍처적으로 클라우드 네이티브 애플리케이션 아키텍처는 구성 요소 간의 느슨한 결합을 선호합니다. 워크로드의 일부가 일상적인 작동을 위해 백킹 서비스가 필요하다면, 그 백킹 서비스를 구성 요소로 실행하거나 외부 서비스로 소비하세요. 이렇게 하면 워크로드가 정상 작동을 위해 쿠버네티스 API에 의존하지 않습니다.
CustomResourceDefinitions
CustomResourceDefinition API 리소스는 커스텀 리소스를 정의할 수 있게 합니다. CRD 객체를 정의하면 사용자가 지정한 이름과 스키마로 새 커스텀 리소스가 생성됩니다. 쿠버네티스 API가 커스텀 리소스의 저장을 제공하고 처리합니다. CRD 객체 자체의 이름은 정의된 리소스 이름과 그 API 그룹에서 파생된 유효한 DNS 서브도메인 이름이어야 합니다. 자세한 내용은 CRD 만들기를 참조하세요. 또한 kind/resource가 CRD로 정의된 객체의 이름도 유효한 DNS 서브도메인 이름이어야 합니다.
이렇게 하면 커스텀 리소스를 처리할 자체 API 서버를 작성할 필요가 없지만, 구현의 일반적인 특성상 API 서버 통합보다 유연성이 적습니다.
새 커스텀 리소스를 등록하고, 새 리소스 유형의 인스턴스로 작업하고, 컨트롤러를 사용해 이벤트를 처리하는 방법의 예시는 custom controller 예시를 참조하세요.
API 서버 통합
보통 쿠버네티스 API의 각 리소스는 REST 요청을 처리하고 객체의 영구 저장을 관리하는 코드가 필요합니다. 기본 쿠버네티스 API 서버는 pods와 services 같은 내장 리소스를 처리하고, CRD를 통해 커스텀 리소스를 일반적으로 처리할 수도 있습니다.
애그리게이션 레이어는 자신의 API 서버를 작성하고 배포하여 커스텀 리소스에 대한 특수화된 구현을 제공할 수 있게 합니다. 기본 API 서버는 사용자가 처리하는 커스텀 리소스에 대한 요청을 API 서버에 위임해, 모든 클라이언트가 사용할 수 있게 합니다.
커스텀 리소스 추가 방법 선택
CRD는 사용하기 더 쉽습니다. 통합 API는 더 유연합니다. 필요에 가장 잘 맞는 방법을 선택하세요.
일반적으로 CRD는 다음 경우에 잘 맞습니다:
- 필드가 몇 개인 경우
- 회사 안에서 또는 작은 오픈소스 프로젝트의 일부로(상업 제품과 대조적으로) 리소스를 사용하는 경우
사용 용이성 비교
CRD는 통합 API보다 만들기 쉽습니다.
| CRDs | Aggregated API |
|---|---|
| 프로그래밍이 필요하지 않다. 사용자는 CRD 컨트롤러에 어떤 언어든 선택할 수 있다. | 프로그래밍과 바이너리·이미지 빌드가 필요하다. |
| 추가 서비스가 필요 없다. CRD는 API 서버가 처리한다. | 생성해야 하고 실패할 수 있는 추가 서비스가 있다. |
| CRD가 생성되면 지속적인 지원이 필요 없다. 버그 수정은 정상적인 Kubernetes Master 업그레이드의 일부로 반영된다. | 업스트림의 버그 수정을 주기적으로 가져와서 Aggregated API 서버를 재빌드하고 업데이트해야 할 수 있다. |
| API의 여러 버전을 처리할 필요가 없다. 예: 이 리소스의 클라이언트를 제어할 때 API와 동기화해 업그레이드할 수 있다. | API의 여러 버전을 처리해야 한다. 예: 세상과 공유할 확장을 개발할 때. |
고급 기능과 유연성
통합 API는 더 고급 API 기능과 다른 기능(예: 저장 계층)의 사용자 정의를 제공합니다.
| 기능 | 설명 | CRDs | Aggregated API |
|---|---|---|---|
| 검증 | 사용자가 오류를 방지하고 클라이언트와 독립적으로 API를 발전시킬 수 있게 돕는다. 이러한 기능은 모두 동시에 업데이트할 수 없는 클라이언트가 많을 때 가장 유용하다. | 예. 대부분의 검증은 OpenAPI v3.0 검증을 사용해 CRD에서 지정할 수 있다. CRDValidationRatcheting 기능 게이트는 리소스의 실패 부분이 변경되지 않았다면 OpenAPI로 지정된 실패 검증을 무시할 수 있게 한다. 다른 검증은 Validating Webhook 추가로 지원된다. | 예, 임의의 검증 검사 |
| 기본값 설정 | 위 참조 | 예, OpenAPI v3.0 검증 default 키워드(1.17에서 GA) 또는 Mutating Webhook(단, 오래된 객체의 etcd 읽기에는 실행되지 않음) 중 하나로 가능. |
예 |
| 다중 버전 | 같은 객체를 두 API 버전으로 제공할 수 있다. 필드 이름 바꾸기 같은 API 변경을 쉽게 할 수 있다. 클라이언트 버전을 제어한다면 덜 중요하다. | 예 | 예 |
| 커스텀 저장 | 다른 성능 모드(예: 키-값 저장소 대신 시계열 데이터베이스) 또는 보안 격리(예: 민감 정보 암호화)가 필요한 저장이 필요한 경우 | 아니오 | 예 |
| 커스텀 비즈니스 로직 | 객체를 생성, 읽기, 업데이트, 삭제할 때 임의의 검사 또는 작업 수행 | 예, Webhooks 사용. | 예 |
| Scale 서브리소스 | HorizontalPodAutoscaler와 PodDisruptionBudget 같은 시스템이 새 리소스와 상호작용할 수 있게 한다 | 예 | 예 |
| Status 서브리소스 | 사용자가 spec 섹션을 쓰고 컨트롤러가 status 섹션을 쓰는 세밀한 접근 제어를 허용한다. 커스텀 리소스 데이터 변형 시 객체 Generation 증가를 허용한다(리소스에 별도의 spec과 status 섹션이 필요하다) | 예 | 예 |
| 기타 서브리소스 | "logs" 또는 "exec" 같은 CRUD 외의 작업 추가 | 아니오 | 예 |
| strategic-merge-patch | 새 엔드포인트가 Content-Type: application/strategic-merge-patch+json과 함께 PATCH를 지원한다. 로컬과 서버 양쪽에서 수정될 수 있는 객체를 업데이트하는 데 유용하다. 자세한 내용은 "kubectl patch로 API 객체 업데이트" 참조 |
아니오 | 예 |
| Protocol Buffers | 새 리소스가 Protocol Buffers를 사용하려는 클라이언트를 지원한다 | 아니오 | 예 |
| OpenAPI 스키마 | 서버에서 동적으로 가져올 수 있는 유형에 대한 OpenAPI(swagger) 스키마가 있는가? 허용된 필드만 설정됨을 보장해 사용자를 필드 이름 오타에서 보호하는가? 유형이 강제되는가(즉, string 필드에 int를 넣지 못하게)? |
예, OpenAPI v3.0 검증 스키마(1.16에서 GA) 기반 | 예 |
| 인스턴스 이름 | 이 확장 메커니즘이 이런 방식으로 정의된 kind/resource의 객체 이름에 어떤 제약을 부과하는가? | 예, 그러한 객체의 이름은 유효한 DNS 서브도메인 이름이어야 한다. | 아니오 |
공통 기능
커스텀 리소스를 CRD 또는 AA로 만들 때, 쿠버네티스 플랫폼 밖에서 구현하는 것과 비교해 API에 대한 많은 기능을 얻습니다:
| 기능 | 역할 |
|---|---|
| CRUD | 새 엔드포인트가 HTTP와 kubectl을 통해 CRUD 기본 작업을 지원한다 |
| Watch | 새 엔드포인트가 HTTP를 통해 Kubernetes Watch 작업을 지원한다 |
| Discovery | kubectl과 dashboard 같은 클라이언트가 리소스에 대해 목록, 표시, 필드 편집 작업을 자동으로 제공한다 |
| json-patch | 새 엔드포인트가 Content-Type: application/json-patch+json과 함께 PATCH를 지원한다 |
| merge-patch | 새 엔드포인트가 Content-Type: application/merge-patch+json과 함께 PATCH를 지원한다 |
| HTTPS | 새 엔드포인트가 HTTPS를 사용한다 |
| 내장 인증 | 확장에 대한 접근이 인증에 핵심 API 서버(애그리게이션 레이어)를 사용한다 |
| 내장 권한 부여 | 확장에 대한 접근이 핵심 API 서버가 사용하는 권한 부여(예: RBAC)를 재사용할 수 있다. |
| Finalizers | 외부 정리가 일어날 때까지 확장 리소스의 삭제를 차단한다. |
| Admission Webhooks | create/update/delete 작업 중 기본값을 설정하고 확장 리소스를 검증한다. |
| UI/CLI 표시 | Kubectl, dashboard가 확장 리소스를 표시할 수 있다. |
| Unset vs. Empty | 클라이언트가 설정되지 않은 필드와 0값 필드를 구분할 수 있다. |
| 클라이언트 라이브러리 생성 | Kubernetes가 일반 클라이언트 라이브러리와 유형별 클라이언트 라이브러리를 생성하는 도구를 제공한다. |
| 라벨과 어노테이션 | 도구가 핵심 및 커스텀 리소스에 대해 편집하는 방법을 아는 객체 간 공통 메타데이터. |
커스텀 리소스 설치 준비
클러스터에 커스텀 리소스를 추가하기 전에 알아둬야 할 몇 가지 사항이 있습니다.
타사 코드와 새로운 실패 지점
CRD 생성이 자동으로 새로운 실패 지점을 추가하지는 않지만(예: 타사 코드가 API 서버에서 실행되도록 하는 것), 패키지(예: Charts)나 다른 설치 번들은 흔히 CRD와 함께 새 커스텀 리소스의 비즈니스 로직을 구현하는 타사 코드의 Deployment를 포함합니다.
통합 API 서버를 설치하는 것은 항상 새 Deployment의 실행을 포함합니다.
저장
커스텀 리소스는 ConfigMap과 같은 방식으로 저장 공간을 소비합니다. 너무 많은 커스텀 리소스를 만들면 API 서버의 저장 공간이 과부하될 수 있습니다.
커스텀 리소스는 CRD 명세에 정의된 리소스의 현재 저장 버전을 기반으로 저장 공간에 배치됩니다. 커스텀 리소스에 대한 어떤 업데이트도 현재 정의된 저장 버전을 사용해 리소스를 저장합니다. 다른 모든 버전은 해당 버전의 모든 필드를 가지거나 제대로 작동하도록 변환을 정의해야 합니다.
통합 API 서버는 기본 API 서버와 같은 저장소를 사용할 수 있으며, 이 경우 같은 경고가 적용됩니다.
인증, 권한 부여, 오딧
CRD는 항상 API 서버의 내장 리소스와 같은 인증, 권한 부여, 오딧 로깅을 사용합니다.
권한 부여에 RBAC를 사용한다면 대부분의 RBAC 역할은 새 리소스에 대한 접근을 부여하지 않습니다(cluster-admin 역할 또는 와일드카드 규칙으로 만든 역할 제외). 새 리소스에 대한 접근을 명시적으로 부여해야 합니다. CRD와 Aggregated API는 흔히 추가하는 유형에 대한 새 역할 정의와 함께 번들로 제공됩니다.
통합 API 서버는 기본 API 서버와 같은 인증, 권한 부여, 오딧을 사용하거나 사용하지 않을 수 있습니다.
커스텀 리소스 접근
쿠버네티스 클라이언트 라이브러리를 사용해 커스텀 리소스에 접근할 수 있습니다. 모든 클라이언트 라이브러리가 커스텀 리소스를 지원하는 것은 아닙니다. Go 와 Python 클라이언트 라이브러리는 지원합니다.
커스텀 리소스를 추가하면 다음을 사용해 접근할 수 있습니다:
kubectl- 쿠버네티스 동적 클라이언트.
- 직접 작성한 REST 클라이언트.
- Kubernetes 클라이언트 생성 도구로 생성한 클라이언트(하나를 생성하는 것은 고급 작업이지만, 일부 프로젝트는 CRD 또는 AA와 함께 클라이언트를 제공할 수 있습니다).
커스텀 리소스 필드 선택자
필드 선택자는 클라이언트가 하나 이상의 리소스 필드 값에 기반해 커스텀 리소스를 선택할 수 있게 합니다.
모든 커스텀 리소스는 metadata.name과 metadata.namespace 필드 선택자를 지원합니다.
CRD에 선언된 필드는 CRD의 spec.versions[*].selectableFields 필드에 포함될 때 필드 선택자와 함께 사용될 수도 있습니다.
커스텀 리소스의 선택 가능 필드 {#crd-selectable-fields}
CRD의 spec.versions[*].selectableFields 필드는 커스텀 리소스의 어떤 다른 필드가 필드 선택자에서 사용될 수 있는지 선언하는 데 사용될 수 있습니다.
다음 예시는 .spec.color와 .spec.size 필드를 선택 가능한 필드로 추가합니다.
그런 다음 필드 선택자를 사용해 color가 blue인 리소스만 얻을 수 있습니다:
kubectl get shirts.stable.example.com --field-selector spec.color=blue
출력은 다음과 같아야 합니다:
NAME COLOR SIZE
example1 blue S
example2 blue M
더 알아보기 (Learn more)
- 애그리게이션 레이어로 쿠버네티스 API 확장 방법 배우기.
- CustomResourceDefinition으로 쿠버네티스 API 확장 방법 배우기.