Files
service-catalog/.claude/skills/chart-to-cnpg/SKILL.md
T
wbsong111 3ee1c1ee23 카탈로그 앱 내장 bitnami postgresql → cnpg-cluster 전환 (1차 5개 차트)
이슈 #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>
2026-08-05 15:17:46 +09:00

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.yamlpostgresql: 서브차트 설정이 있는지 본다. Chart.yamldependencies에 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, lakekeeper auth.oauth2 비우기, superset configOverrides.enable_oauth).
  • 왜 끄는지는 fixture 파일 주석에 남긴다 — README에 중복 기술하지 않는다.

5. 배포 테스트

.claude/deploy-test-procedure.md의 "카탈로그 앱 → cnpg-cluster 전환 배포 테스트" 절을 따른다. 절차를 여기 복제하지 않는다.

APP_POD_SELECTORDB에 실제로 연결하는 파드를 가리켜야 한다(미지정 시 무관한 파드가 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 신뢰 금지)