Commit Graph

4 Commits

Author SHA1 Message Date
wbsong111 d3816a14ca airflow fernet key 를 콘솔이 만든 Secret 으로 넘긴다 (#38)
차트가 fernet key Secret 을 직접 만들면 helm.sh/hook: pre-install +
hook-delete-policy: before-hook-creation 이 붙는다. ArgoCD 는 훅을 "삭제 후 재생성" 하는데,
변경이 없는 sync 에서는 삭제 직후 operation 이 종료되어 재생성되지 않는다. 컨트롤러 로그로
확인했다.

  변경 있는 sync  waiting for deletion ... -> serverside-applied -> Succeeded 'all tasks run'
  no-op sync      waiting for deletion ... -> Succeeded (같은 초)             'no more tasks'

파드는 이미 주입된 env 로 계속 돌아 증상이 즉시 드러나지 않지만, 재시작하는 순간
CreateContainerConfigError 로 기동하지 못한다. refresh·selfHeal 로 흔히 발생하는 상황이다.

fernetKeySecretName 을 주면 차트가 Secret 을 아예 만들지 않으므로
(templates/secrets/fernetkey-secret.yaml:23) 훅 자체가 사라지고, 모든 워크로드가 그 이름을
secretKeyRef 로 참조한다(templates/_helpers.yaml:395-397).

$FERNET_KEY_SECRET 은 placeholder 다. dip-console-api 가 <릴리스명>-fernet-key Secret 을
만들고(없을 때만) 이 자리를 그 이름으로 치환한다. 콘솔이 만든 Secret 은 ArgoCD 추적 대상이
아니라 sync 의 영향을 받지 않는다.

값이 아니라 이름을 넘기는 이유가 하나 더 있다 — fernet key 는 메타DB 의
Connection·Variable 암호화에 쓰이므로 tenant 레포(git)에 평문으로 남기지 않는다.
업스트림도 can only be set during install, not upgrade 라고 못박고 있어, 이미 배포된
테넌트는 재배포 시 현재 Secret 을 그대로 인수한다.

CUSTOM-README 5절은 이 문서의 성격(배포 방법 · custom-values.yaml 키 설명)에 맞게 키
테이블과 배포 절차 중심으로 다시 썼다(69줄 -> 48줄). 상세 근거는 이슈로 넘긴다.

redis 훅 Secret 2종은 CeleryExecutor 전환 예정이 없어 조치하지 않는다. 참조 워크로드가
0개인 것을 클러스터에서 확인했다. 전환 시 처리 방법만 문서에 남긴다.

검증

service-catalog 에 선반영해 테스트 클러스터에서 확인했다. 재배포 후 sync 를 걸었을 때 훅인
redis Secret 2종은 또 삭제됐고 콘솔이 관리하는 fernet Secret 만 살아남았다(resourceVersion
미동, 값 동일). 이 레포 기준으로도 helm template 2회 렌더에서 차트가 fernet Secret 을 만들지
않고 webserver 체크섬이 동일함을 확인했다.

관련: paasup/dip-catalog#38, paasup/dip-console-api#100

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 13:56:36 +09:00
wbsong111 39f4b9778f airflow 가 반복 재배포되는 두 원인을 카탈로그 기본값에서 끊는다 (#29)
`demo01-air` 에서 webserver 가 반복 롤링되고 migrations job 이 5분 주기로 재실행되던
것을 추적한 결과, 원인이 서로 다른 두 개였고 둘 다 카탈로그 기본값에서 비롯됐다 —
모든 airflow 테넌트가 해당된다.

원인 1 — webserverSecretKey 가 렌더할 때마다 바뀐다

값을 주지 않으면 차트가 템플릿에서 직접 난수를 만들고(`randAlphaNum 32`), 그 Secret 이
webserver·worker Deployment 의 `checksum/webserver-secret-key` 애노테이션에 물려 있어
렌더할 때마다 Deployment spec 이 바뀐다. 캐시된 매니페스트를 쓰는 reconcile 로는
일어나지 않지만 일반 refresh 만으로도 일어난다(실측).

차트 안에서는 못 고친다. `lookup` 재사용은 ArgoCD repo-server 가 클러스터 접근 없이
클라이언트 렌더를 하므로 항상 빈 값이다(클러스터에 Secret 이 실재하는데도 빈 값인 것을
확인). 릴리스명·네임스페이스 기반 결정적 파생은 렌더는 안정되지만 파생 입력이 전부 공개
정보라 세션 서명 키를 예측할 수 있어 부적합하다. 값이 차트 바깥에서 와야 한다.

그래서 `$WEBSERVER_SECRET_KEY` placeholder 를 두고, 배포 시점에 dip-console-api 가
난수로 치환한다(`catalogs/catalogtype/catalog_airflow.go` 의 `DeployPreInstall`).
치환된 values 가 tenant 레포에 저장되므로 이후 렌더는 그 고정값을 쓴다. 공용
`catalog_type_base.go` 가 아니라 airflow 전용 훅에 둔다.

원인 2 — migrations job 이 TTL 삭제 ↔ selfHeal 재생성 루프에 빠진다

`useHelmHooks: false`(업스트림이 ArgoCD 환경에 권고) 로 Job 이 ArgoCD 추적 리소스가
됐는데 차트 기본값 `ttlSecondsAfterFinished: 300` 이 그대로 남아 있었다. 완료 300초 뒤
TTL 컨트롤러가 Job 을 지우면 ArgoCD 가 OutOfSync 로 보고 selfHeal 이 다시 만든다.
템플릿에서 TTL 은 `useHelmHooks` 와 무관하게 항상 렌더되고 `kindIs "invalid"` 일 때만
빠지므로, `~` 로 꺼서 필드 자체를 없앤다. 대신 완료된 Job 객체가 남는다.

반영 위치가 2곳이다 — helm 카탈로그와 applicationset(`---` 뒤 두 번째 문서) 양쪽.
한쪽만 고치면 배포 경로에 따라 증상이 남는다.

주의 — dip-console-api 와 짝이다. 한쪽만 머지되면 placeholder 문자열이 그대로 키가
되거나(카탈로그만) 아무 일도 일어나지 않는다(console 만). 이미 배포된 테넌트는
재배포해야 적용된다.

fernet key 는 같은 구조지만 체크섬에 물려 있지 않아 증상·마이그레이션 경로가 다르다 —
별건(#38)으로 둔다.

Refs #29
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 09:20:45 +09:00
wbsong111 a8530d3968 airflow: OIDC 인증 제외 경로 Ingress 추가 (#24)
세션이 없는 상태로 접속하면 Airflow UI 한 페이지가 /static 자원을 수십 개
동시에 요청하고, 각 요청이 저마다 APISIX openid-connect 로그인 플로우를
시작한다. 세션은 state를 하나만 보관하므로 콜백이 동시에 돌아오면 마지막
하나를 뺀 전부가 state 검증에 실패해 500이 난다.

templates/webserver/webserver-ingress-static.yaml 은 업스트림 Apache Airflow
차트에 없는 PaaSup 추가 템플릿이다. dip.unauthenticatedPaths 가 있을 때만
애노테이션 없는 Ingress를 하나 더 렌더해 해당 경로를 인증 없이 통과시킨다.
애노테이션을 전부 비우는 것은 의도된 것으로, plugin-config-name 을 빼는 게
목적이고 cert-manager.io/* 까지 빼는 이유는 웹 Ingress와 같은 TLS Secret 을
두고 Certificate 를 중복 생성하지 않게 하기 위해서다.

값을 ingress.web 아래가 아니라 dip 아래에 두는 이유는 values.schema.json 의
ingress.web 이 additionalProperties: false 라 그 아래 새 키를 넣으면 스키마
검증에서 배포가 실패하기 때문이다. qdrant·litellm 의 dip.mainPath 와 같은
자리를 쓴다.

webserver-ingress.yaml 과 동일한 조건으로 렌더하므로 Airflow 3.0
(webserver → api-server) 전환 시 함께 재작업이 필요하다. 업스트림 파일은
수정하지 않았고 fork 델타는 신규 템플릿 1개뿐이다.

이슈 #24 는 dip-console 이 차트 밖에서 생성하는 방안(B안)을 권고했으나,
실제로 증상이 재현되는 서비스가 airflow 하나로 좁혀져 차트 템플릿(A안)으로
갔다. dip-console 로 옮길 때는 dip.unauthenticatedPaths 를 비우면 된다.

redirect_uri 고정은 여전히 dip-console 몫으로 남는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 11:19:01 +09:00
wbsong111 1084713614 airflow applicationset: dip-values / dip-questions 추가
flowise/6.0.0 의 dip-values.yaml + dip-questions.yaml 스키마를 airflow 에 적용했다.
doc1 은 cnpg-cluster(airflow-db), doc2 는 airflow 본체다.

dip-values.yaml
- bootstrap.initdb 의 database/owner 는 airflow-db-values.yaml 과 맞춘 airflow.
- databases[] 도 airflow/airflow. 차트 기본값인 appdb/appuser 를 쓰면 appuser
  롤이 생성되지 않아 Database CR reconcile 이 실패한다.
- bootstrap.initdb 에는 ensure/reclaimPolicy 를 넣지 않았다. cnpg-cluster 의
  cluster.yaml 이 읽지 않는 databases[] 전용 키다.
- postgresql.enabled: false. 내장 bitnami 대신 syncWave 0 의 cnpg 를 쓴다.
- metadataConnection.host 는 "{{ .Name }}-airflow-db-rw". dip 배포는 cnpg
  릴리스명에 테넌트 접두사를 붙여 나간다(관측: instance=demo01-air-airflow-db).
  flowise 의 externalPostgresql.host 와 같은 규칙이다.

dip-questions.yaml
- git-sync 는 GIT_SYNC_*/GITSYNC_* 네 키를 모두 선언한다. 차트가 네 개를 각각
  secretKeyRef 로 잡아서 하나라도 없으면 파드가 기동되지 않는다.
- connection 기본값 호스트는 $CATALOG_NAME-airflow-db-rw.$CATALOG_NAME.
  차트가 data.metadataSecretName 의 connection 키를
  AIRFLOW__DATABASE__SQL_ALCHEMY_CONN 에 그대로 주입하므로 이 값이 유일한 실효 값이다.

두 파일의 토큰 형식 차이는 의도한 것이다 — dip-questions 는 $CATALOG_NAME,
dip-values 는 {{ .Name }} 가 각 파일의 기존 관례다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 15:38:33 +09:00