티스토리 뷰
서론
안녕하세요. 지마켓의 원활한 서비스 운영을 위해 쿠버네티스 인프라를 운영 업무를 하고 있는 Platform Technology 팀 김지형입니다.
Red Hat Openshift 기반의 쿠버네티스 클러스터를 운영하게 되면서 자연스럽게 적용하게 된 쿠버네티스 오퍼레이터에 대한 사례와 경험을 기술하고자 합니다. 오퍼레이터에 대한 간단한 설명과 쿠버네티스 오퍼레이터에 대해서 설명하고, 현재의 오퍼레이터 패턴이 가져다주는 이점과 한계에 대한 내용을 포함합니다.
오퍼레이터 디자인 패턴
오퍼레이터(Operator)는 2016년 CoreOS 블로그 포스트에서 공개된 디자인 패턴으로, 단어 그대로 운영자의 역할을 소프트웨어에 새긴 개념이라고 할 수 있습니다. SRE 엔지니어는 소프트웨어를 개발해 애플리케이션을 운영하는 엔지니어로서 그의 운영 노하우와 도메인 지식이 수반되어야만 그 소프트웨어를 개발하고 운영할 수 있을 것입니다. 그들의 수동적인 관리 노하우는 데이터베이스, 캐시, 모니터링 시스템과 같은 스테이트풀(Stateful) 애플리케이션 운용에 있어서 여전히 유효한데, 스테이트리스(Stateless) 애플리케이션의 작동을 위해 설계된 쿠버네티스 및 다른 컨테이너 오케스트레이터의 근본적인 한계를 잘 지탱해주고 있었습니다. 스테이트리스 시스템에서 데이터의 손실이 일어나지 않게 유지하고, 가용성이 유지되게 하기 위해서 엔지니어는 쿠버네티스 등의 오케스트레이터의 나사 볼트 하나하나를 수동적으로 교체해주고 있었던 셈이죠.
클라우드 네이티브 컴퓨팅 재단(CNCF)에서 소개한 CNCF Operator White Paper에서는 상태를 수동적으로 관리해주어야 하는 한계를 극복하기 위해 고안된 오퍼레이터 패턴의 역할과 기능에 대해 자세히 서술해 두었습니다.
오퍼레이터의 패턴은 다음과 같은 세 가지로 요약되는데:
- 우리가 관리하고자 하는 애플리케이션이나 인프라
- 사용자가 선언적인 방법으로 이상적인 상태를 지정할 수 있는 도메인별 언어
- 지속적으로 실행되는 컨트롤러
- 상태를 인지하고 읽을 수 있는 컨트롤러
- 자동적인 방법으로 액션을 하는 컨트롤러
- 선언적인 방법으로 상태를 보고하는 컨트롤러
그리고 오퍼레이터는 다음과 같은 성격을 지녀야 할 것입니다:
- 동적으로 설정이 가능하고
- 운영 자동화를 추구해야 하며
- 도메인 지식이 담겨있어야 할 것
이제 쿠버네티스에서 적용할 수 있는 오퍼레이터를 보면서 어떻게 이 세 가지가 적용되었는지 확인해 보겠습니다.
쿠버네티스의 오퍼레이터 컴포넌트
조금은 다른 그림이 CNCF Operator White Paper: Operator components in Kubernetes에 담겨 있습니다.
쿠버네티스 컨트롤러
쿠버네티스 컨트롤러(Kubernetes Controller)는 이상적인 상태를 유지하기 위한 반복적인 작업을 담당합니다. 예를 들어 배포(Deployment) 컨트롤러는 이상적인 파드 복제본의 수가 실행될 수 있도록 실패하거나 삭제된 파드를 인지해 새로운 파드가 돌게 하죠. 기존의 컨트롤러와 오퍼레이터 간 차이는 없습니다. 그래서 단순한 컨트롤러를 쿠버네티스 내 선언만 해주면 이 부분이 구현되는데, 오퍼레이터 패턴을 적용한 컨트롤러라 하면 이 파드들이 어떻게 업그레이드가 되어야 하고 에러 발생 시 어떻게 해결되어야 하는지 등의 운영 노하우가 더 담겨있는 컨트롤러라 할 수 있습니다.
커스텀 리소스 및 커스텀 리소스 정의
커스텀 리소스(Custom resource)는 기본 쿠버네티스 API의 확장형 엔드포인트로서 구조화된 데이터를 저장하고 내뱉는 형태를 띠고 있습니다. 오퍼레이터 패턴에서는 이상적인 리소스 상태를 표시할 뿐 구현 로직을 포함하지 않습니다. 다음과 같은 예시처럼요:
apiVersion: example-app.appdelivery.cncf.io/v1alpha1
kind: ExampleApp
metadata:
name: appdelivery-example-app
spec:
appVersion: 0.0.1
features:
exampleFeature1: true
exampleFeature2: false
backup:
enabled: true
storageType: “s3”
host: “my-backup.example.com”
bucketName: “example-backup”
status:
currentVersion: 0.0.1
url: https://myloadbalancer/exampleapp/
authSecretName: appdelivery-example-app-auth
backup:
lastBackupTime: 12:00
컨트롤 루프
이상적인 상태와 현재 상태를 이어주는 역할을 하는 컨트롤 루프는 현재 상태가 이상적인 상태와 다를 때 의도한 상태값으로 전환해 줍니다. 또한 애플리케이션을 업그레이드할 때 데이터베이스 마이그레이션을 하거나, 특정 이벤트에 대한 트리거가 되어주거나, 특정 시간에 데이터 백업 같은 역할을 해줍니다.
오퍼레이터의 기능
오퍼레이터 패턴을 구성하게 되면 다음과 같은 부분을 자동화할 수 있습니다:
- 애플리케이션 설치 및 권한 설정
- 애플리케이션 업그레이드
- 백업
- 백업 데이터를 통한 복구
- 자가복구
- 모니터링 및 지표 설정
- 스케일링
- 오토 스케일링
- 자동 설정 튜닝
- 어플리케이션 삭제 및 연결 해제
실 적용 사례
Red Hat Openshift 기반의 쿠버네티스 클러스터를 운영하는 것이 필자의 업무이기 때문에 Openshift 기반에서 설치 및 실행할 수 있었던 오퍼레이터들, 또는 시도했으나 실패했던 사례에 대해 공유합니다.
케이스 1: Red Hat Single Sign-on Operator
지마켓 고유의 서비스 제공을 위해 사내 다양한 애플리케이션에서 사용할 수 있는 Single Sign-on 인증 서비스를 Operator를 이용해 구성하였습니다. Openshift를 이용하게 되면 Red Hat OperatorHub에서 공식적으로 제공하는 Operator 패키지를 이용할 수 있습니다.
설치 과정
- Operator 패키지 설치
- 인터넷이 연결된 환경이라면 웹 콘솔 내 Administrator > Operators > OperatorHub에서 검색 및 설치를 손쉽게 할 수 있습니다.
- Disconnected 환경에서는
opm
CLI 툴을 이용해 Operator 카탈로그를 생성합니다. CatalogSource 오브젝트에서 제공된 인덱스 이미지를 통해 웹 콘솔에서 설치할 수 있게 이미지 카탈로그를 생성할 수 있습니다.
- Keycloak 설정
- Keycloak 커스텀 리소스를 이용해 SSO 인증을 자동화합니다. Keycload 데이터베이스의 시크릿 값과 라우트, 인스턴스의 개수, 오토스케일링 등을 설정해 줍니다.
- Keycloak Realm, Client, User 설정
- Keycloak 내부에서 사용하는 KeycloakRealm, KeycloakClient, KeyCloakUser 등의 커스텀 리소스가 존재하고, yaml 파일을 통해 설정 값을 정의할 수 있습니다.
- 만약 처음 설정한다면, Keycload 커스텀 리소스에서 정의된 Route 엔드포인트를 통해서 웹 콘솔에 접속해 설정하는 방법이 편리합니다. 웹 콘솔에서 새로운 Realm을 생성하고, 사내 SSO 설정을 User에 집어넣고, 사용하고자 하는 애플리케이션 별로 Client를 생성한 뒤, CORS 여부, 로그인을 위한 토큰 설정 및 레코드 호출 범위 등을 설정합니다.
- 데이터베이스 백업 스케줄링
- 설정된 값을 주기적으로 백업할 수 있습니다. 필자의 시스템에서는 SSO 인증 데이터베이스를 읽기 전용으로만 참조하고 있기 때문에 별도의 백업 로직을 구현할 필요가 없었습니다.
결과
기존에는 Keycloak과 기타 커스텀 리소스를 일일이 yaml 파일로 생성해주어야 했고, 버전이 업그레이드될 때마다 각각의 리소스 정의 검토해주어야 하는 부분에서 많은 관리 포인트들이 생깁니다. 마이너 업그레이드를 한차례 시도해 본 결과, 비교적 적은 스펙 항목을 검토해 간편하게 업그레이드할 수 있었던 점에서 상기 Operator 기능 중 하나인 '간편한 업그레이드'의 장점을 맛볼 수 있었습니다.
그러나 Keycloak Operator에서 설정하지 않고 Keycloak 웹 콘솔에서 생성한 Realm, Client, User 등이 Openshift 클러스터 내 CRD로서 구현되어 있는 인스턴스 목록과 일치하지 않는 현상이 있었습니다. 실 서비스에 이용되고 있는 데이터베이스의 내용을 주기적으로 Operator에서 읽고 동기화를 해주어야 하는데 아직 그런 로직이 구현되어있지 않아 보였습니다.
케이스 2: Red Hat 3Scale Operator
SaaS형 API 관리 서비스인 3Scale 역시 오퍼레이터 형태로 설치할 수 있었고, Openshift 3버전 대에서 4버전 대로 판올림하면서 오퍼레이터 형식으로 본 서비스를 구성하였습니다. 케이스 1번과 마찬가지로 Red Hat OperatorHub 카탈로그를 통한 설치를 진행했습니다.
설치 과정
- Operator 패키지 설치
- 인터넷이 연결된 환경이라면 웹 콘솔 내 Administrator > Operators > OperatorHub에서 검색 및 설치를 손쉽게 할 수 있습니다.
- Disconnected 환경에서는
opm
CLI 툴을 이용해 Operator 카탈로그를 생성합니다. CatalogSource 오브젝트에서 제공된 인덱스 이미지를 통해 웹 콘솔에서 설치할 수 있게 이미지 카탈로그를 생성할 수 있습니다.
- HA 설정
- 높은 가용성을 위한
redis
,memcached
,sphinx
,zync
설정을 정의할 수 있습니다. 필자는 APIManager 오퍼레이터 컨트롤러 내 각 컴포넌트의 인스턴스 개수를 늘려주었고, 3scale-managed가 아닌 self-managed API를 이용해zync
가 라우트를 관리하는 것이 아닌 셀프서비스형으로 관리할 수 있게 구성하였습니다. 이를 위해서는APICast Gateway Operator
를 추가 설정해야 합니다.
- 높은 가용성을 위한
- Multitenancy 설정
- 각 팀별로 별도의 API 서비스를 운용할 수 있게 웹 콘솔 및 관리 영역을 분리할 수 있습니다.
- 각 팀별로 별도의 관리자, 관리자 웹 콘솔, 개발자 웹 콘솔, Product, Backend 등을 분리할 수 있습니다.
- SSO 연동
- 케이스 1에서 구성한 Red Hat Single Sign-On 서비스와 본 서비스를 연동히였습니다.
- SSO 연동 또한 3. Multitenancy 설정에서 구성한 테넌트 별로 각각 설정해주어야 합니다. 마스터 콘솔에서 Impersonated 계정을 얻어 각각의 관리자 콘솔 내 SSO 설정을 해주고, 접근된 팀 관리자 계정을 관리자로 승격시켜 주었습니다.
- Product 등의 커스텀 리소스 마이그레이션
- 기존 Openshift 3 도메인에서 설정한 템플릿 기반 리소스들을 오퍼레이터 기반 리소스로 변경 해주기 위해서는 각각의 커스텀리소스 정의들을 새로 생성해주어야 한다고 가이드되어 있었습니다. 기존 서비스 Product의 metric 등의 운영지표를 마이그레이션 하지 않기로 결정했기 때문에 CRD yaml파일을 새로 만들어주는 대신 웹 콘솔에서 수동으로 다시 설정하는 방향으로 진행했습니다.
결과
3Scale을 Operator 형식으로 설치하는 것 역시 Single Sign-On Operator 설치하는 것만큼 간편했습니다. 그러나 Operator 패턴으로 인한 문제보다는 3Scale 서비스의 가이드라인 부족이 운영 배포까지 이어지는데 어려움을 겪게 했습니다. 3Scale이 설치된 이후 세부 항목들을 일일이 CRD yaml 리소스로 구성해야 하는데, 생성 가이드라인 및 공식 문서가 부족하거나 다르다는 점, 케이스 1과 마찬가지로 웹 콘솔을 통해 생성한 인스턴스들이 CRD와 동기화되지 않는다는 점 등이 아쉬운 부분이었습니다.
케이스 3: Jenkins Operator
CI/CD 자동화에 있어서 애용되고 있는 Jenkins를 템플릿 기반으로 운영해오고 있는데, Jenkins Operator 문서에서 쿠버네티스 네이티브 오퍼레이터를 지원한다는 문서를 확인하여 적용해보고자 하였습니다.
결과
공식문서의 가이드를 따라 최신버전인 v0.7.x을 설치 시도해 보았는데, 몇 단계 지나지 않아 포기해야 했습니다.
v0.5.x까지는 지원했으나 v0.6.x부터 Openshift를 지원하지 않는 것이었습니다. GitHub에 관련 이슈를 살펴보니 SCC(SecurityContext) 설정 문제, Openshift만 존재하는 Operator 번들 설정에 대한 이슈를 본 Maintainer가 감당하기에는 힘들었나 봅니다. Red Hat에서 공식 지원하지 않는 Community 버전에 대한 Operator를 Production 레벨로 적용하는 것은 다소 무리가 있어 보였습니다.
OLM을 통해 Red Hat에서 공식으로 지원하는 Jenkins Operator가 있으나, 이 역시 지원하는 버전이 낮았고 관련 문서가 없는 상태입니다.
3가지 사례에 대한 총평
Operator 패턴을 적용해 볼까 검토하고 있으시다면, 위 3가지 Operator 설치 과정을 시도해 본 필자의 총평은 '아직은 이르다'입니다. 쿠버네티스 네이티브 기반에서는 보다 확장성 있는 오퍼레이터를 적용해 볼 수도 있겠지만, 커뮤니티 버전을 운영용으로까지 가져가기에는 아직 어려움이 많아 보입니다.
Operator가 엔지니어의 리소스 관리 포인트를 줄이려는 목적에서 Red Hat Openshift 컴포넌트 전반에서 적용이 되고, OperatorHub를 통해 많은 Operator를 지원하고는 있지만 다음과 같은 단점들이 이용을 어렵게 하고 있습니다:
- Operator를 통한 리소스 관리 포인트가 아직까지는 많이 줄지 않았다.
- 기존의 많은 템플릿 기반 인스턴스들을 CRD 파일로 일일이 생성해주어야 한다. (마이그레이션이 어렵다)
- 애플리케이션의 메이저 버전 업데이트 시 Operator가 온전히 문제없는 업그레이드를 해줄지 미지수
- Operator 리소스 내 지원 스펙 API가 없다면 Operator-maanged 하위 리소스 또는 워크로드를 커스터마이징 할 수 없다는 점
이 외에도, Red Hat OperatorHub에서 제공하는 공식 Operator 번들을 적용함에 있어서, 인터넷과 연결되어있지 않은 Disconnected 시스템에서 적용하기에 부족한 설명이 있었고, 무엇보다 하위 리소스에 대한 커스터마이징을 못하게 강제하고 있다는 점에서 문제 해결을 어렵게 합니다.
일례로, 3Scale Operator에서 Product 내 Custom Policy 적용을 위해 Deployment 리소스들을 수동으로 빌드하고 배포하는 과정들이 있었는데, 이를 APICast Operator에서 APICast Production DeploymentConfig rolling update를 트리거해주어야 했습니다. 이를 감지하지 못해 ImageStreamTag가 업데이트되지 않는 문제가 있었습니다. 수동으로 ImageStream 해시를 직접 입력해주어야 하는 사례가 있었습니다.
그러나...
그러나, 그럼에도 불구하고, 헬름 차트(Helm chart)와 비교해 보면 쿠버네티스 오퍼레이터는 많은 이점을 가지고 있습니다. yaml 명세 파일을 템플릿 화하는 데 헬름(Helm)은 많은 문제를 해결했지만 아직 실제 애플리케이션 설정과 요구사항을 yaml 파일에 작성하는데 꽤나 복잡한 점이 있습니다. 많은 애플리케이션이 이러한 복잡한 설정을 요구하지 않는데도 말이지요.
쿠버네티스 오퍼레이터의 운영 노하우와 프로세스, 하위 커스텀 리소스 등을 잘 관리할 수 있는 조직이라면, 개발자가 굳이 이러한 복잡한 설정을 하지 않아도 애플리케이션을 배포할 수 있게 할 것입니다. IT Ops 팀과 Dev 팀을 분리할 수 있는 최적의 도구로서 쿠버네티스 오퍼레이터는 발전하고 있고, 상기 많은 어려움이 있음에도 불구하고 적용해 볼 만한 가치는 있습니다.
'Infra' 카테고리의 다른 글
경력 입사자의 스크럼 스프린트 적응기 (with Jira software) (14) | 2024.06.28 |
---|---|
Jenkins 성능 개선 part1 - 캐싱 적용 (0) | 2023.07.27 |
API Management PaaS에서 Multi-tenancy 구현하기 (0) | 2023.02.08 |
Sharded MySQL Cluster 도입 배경과 개발기 (부제: 우당탕탕 좌충우돌 개발기) (2) | 2022.12.30 |
Gmarket Hadoop Platform Baikal 소개 (0) | 2022.12.27 |