이슈 #9에서 결정된 CloudNativePG 채택을 카탈로그 앱에 확장 적용한다. airflow/lakekeeper/mlflow/superset/flowise 5개 차트가 내장하던 bitnami postgresql 서브차트를 끄고 앱 전용 cnpg-cluster 인스턴스를 외부 DB로 쓰도록 전환했다. 5개 모두 dev 클러스터 격리 네임스페이스에서 배포 테스트로 실측 검증했다. gitea/keycloak/dnsup 는 서브차트가 아니라 공유 postgresql-ha 를 외부 참조하며 paasup/dipup 레포 관리 대상이라 제외했다 — 인수인계 문서만 추가했다. 배포 구조: - ArgoCD ApplicationSet 으로 DB(syncWave 0) → 앱(syncWave 1) 순서를 보장한다. 기존 openmetadata/victoria-metrics 관례를 따랐다. cnpg-cluster 차트는 범용 상태로 유지하고 앱별 값은 manifests/applicationset/<app>/ 에 둔다. 검증 중 발견해 함께 고친 문제: - lakekeeper: cnpg 의 -ro 는 replica 전용이라 instances:1 에서 엔드포인트가 0개다. 읽기 연결을 -r(전체 라운드로빈)로 교체했다. - airflow/superset: ingressClassName 누락 + kong 애노테이션 잔존으로 이 클러스터(apisix 전용)에서 ingress 접근이 아예 불가능했다. apisix + regex path 로 교체했다. - 배포 테스트가 PV 만 지우고 Longhorn Volume CR 을 남겨 storageScheduled 가 누적됐다(orphan 112개 ~1TB 로 배포 차단). 두 스크립트의 정리 로직을 고쳤다. 재사용 구조화: - .claude/skills/chart-to-cnpg/ 신규. 남은 4개 차트(langflow-ide, langfuse, litellm, nemo)에 같은 절차를 재사용한다. flowise 에 실제 적용해 검증했다. - 배포 테스트 공통 절차는 .claude/deploy-test-procedure.md, 환경 함정은 .claude/pitfalls.md 로 단일화하고 앱별 README 는 참조만 남겼다. 관련: #9, #14 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.5 KiB
name, description
| name | description |
|---|---|
| chart-to-cnpg | 카탈로그 차트가 내장한 bitnami postgresql 서브차트를 전용 cnpg-cluster 인스턴스로 전환할 때 사용한다. "postgresql 서브차트를 cnpg로 바꿔줘", "이 차트도 cnpg-cluster 쓰게 해줘", "bitnami postgresql 제거" 같은 요청, 또는 manifests/helm/<chart>/의 custom-values.yaml에서 postgresql 서브차트를 끄고 외부 DB로 돌리는 작업에 해당한다. 남은 대상은 flowise, langflow-ide, langfuse, litellm, nemo다. |
카탈로그 앱 → cnpg-cluster 전환
내장 bitnami postgresql 서브차트를 끄고, 앱 전용 cnpg-cluster 인스턴스를 외부 DB로 쓰도록
바꾼다. airflow/lakekeeper/mlflow/superset 4개에서 실측 검증된 절차다(GitHub 이슈 #14).
helm/kubectl을 직접 실행하지 않는다 — 배포·검증은 scripts/deploy-test/*.sh가 전담한다
(CLAUDE.md 설계 원칙 #1). 이 skill은 파일 편집과 판단만 담당한다.
1. 대상 확인
manifests/helm/<chart>/<ver>/custom-values.yaml에 postgresql: 서브차트 설정이 있는지 본다.
Chart.yaml의 dependencies에 postgresql이 있는지도 확인한다.
범위 밖: gitea·keycloak·dnsup는 서브차트가 아니라 공유 postgresql-ha를 외부 참조하며
paasup/dipup 레포 관리 대상이다 — 건드리지 않는다(doc/migrations/dipup-postgresql-ha-cnpg-handoff.md).
2. 외부 DB 연결 키 찾기
차트마다 키 구조가 다르다. values.yaml에서 externalDatabase / external* / postgresql.enabled
주변을 grep 한다. 이미 해결된 4개 사례:
| 차트 | 외부 DB 키 |
|---|---|
airflow/1.16.0 |
data.metadataConnection.{host,user,pass,db,port,sslmode} |
lakekeeper/0.11.0 |
externalDatabase.{host_read,host_write,port,database,user,password} |
mlflow/2.1.0 |
externalDatabase.{dialectDriver,host,port,user,password,database} |
superset/0.13.5 |
supersetNode.connections.db_{host,port,user,pass,name} |
서비스명 규칙: 쓰기는 <릴리스>-rw, 읽기는 <릴리스>-r.
읽기에 -ro를 쓰면 안 된다 — -ro는 replica 전용이라 권장 기준인 instances: 1에서
엔드포인트가 0개가 되어 앱이 영구 재시도에 빠진다(lakekeeper에서 실측).
3. 파일 작업 (6종)
내용은 여기 복붙하지 말고 기존 4개 사례를 열어 그대로 따른다. 문서 중복은 유지보수 부담만 는다.
| 파일 | 작업 | 레퍼런스 |
|---|---|---|
manifests/helm/<chart>/<ver>/custom-values.yaml |
postgresql.enabled: false + 위 외부 DB 키. 기존 postgresql.auth.*/image.* 등 서브차트 전용 설정은 제거 |
4개 앱 |
manifests/helm/<chart>/<ver>/CUSTOM-README.md |
전환 사실·사전조건(operator)·배포 순서 | 〃 |
manifests/applicationset/<app>/<ver>/applicationset.yaml |
신규 — DB(syncWave 0) → 앱(syncWave 1) | manifests/applicationset/airflow/1.16.0/ |
manifests/applicationset/<app>/<ver>/<app>-db-values.yaml<app>-values.yaml |
신규 — 비밀번호는 $INFISICAL_SECRET 플레이스홀더 |
〃 |
manifests/applicationset/<app>/<ver>/README.md |
신규 — 짧게. 배포 테스트 절차는 복제하지 말고 참조만 | 〃 |
scripts/deploy-test/fixtures/<app>-deploy-test-overrides.yaml |
신규 — 아래 4절 참고 | scripts/deploy-test/fixtures/ 4개 |
doc/define-chart-resources.md |
해당 차트 섹션의 postgres 리소스/볼륨 티어를 cnpg-cluster 참조로 교체 | 기존 4개 섹션 |
4. 배포 테스트 fixture
custom-values.yaml(카탈로그 권장값)은 절대 바꾸지 않고, 배포 테스트에서만 얹는 오버레이다.
격리된 테스트 네임스페이스에서 DB 연결과 무관하게 막히는 의존성만 끈다.
- ingress host 오버라이드는 필수다 — 카탈로그 기본 host가 이 클러스터의 다른 실제 배포와
겹치면 apisix에 동일 host 라우트가 2개 등록되어 운영 트래픽과 충돌한다(lakekeeper에서 실측).
<app>-access-test.example.org같은 별도 host를 쓴다. - 외부 SSO/저장소 등 이 환경에 없는 의존성을 끈다(사례: airflow
dags.gitSync.enabled: false, lakekeeperauth.oauth2비우기, supersetconfigOverrides.enable_oauth). - 왜 끄는지는 fixture 파일 주석에 남긴다 — README에 중복 기술하지 않는다.
5. 배포 테스트
.claude/deploy-test-procedure.md의 "카탈로그 앱 → cnpg-cluster 전환 배포 테스트" 절을 따른다.
절차를 여기 복제하지 않는다.
APP_POD_SELECTOR는 DB에 실제로 연결하는 파드를 가리켜야 한다(미지정 시 무관한 파드가
Running이라는 이유로 통과 오판). 4개 사례: airflow component=webserver,
lakekeeper app.kubernetes.io/component=catalog, mlflow app.kubernetes.io/component=tracking,
superset app=superset.
6. 마무리 체크리스트
helm template으로 postgresql 서브차트 리소스가 더 이상 렌더링되지 않는지 확인- 읽기 엔드포인트가
-ro가 아니라-r인지 확인(해당 차트에 읽기/쓰기 분리가 있을 때) - fixture에 ingress host 오버라이드가 있는지 확인
- 배포 테스트 PASS + 테스트 네임스페이스/PVC/PV/Longhorn 볼륨 잔여 없음
- 운영 중인 네임스페이스(
platform,defense-llm,cnpg-system)에 영향 없음 - 환경 함정은
.claude/pitfalls.md참고 (Longhorn 볼륨 잔여, ingress host 충돌,ingressClassName누락, 선언적 리소스status신뢰 금지)