282 lines
7.5 KiB
Markdown
282 lines
7.5 KiB
Markdown
# Helm Diff Engine 설계
|
|
|
|
## 1. 개요
|
|
|
|
두 버전의 Helm Chart를 비교하여 **Structured Diff JSON**을 생성하는 컴포넌트.
|
|
모든 출력은 deterministic하며 LLM을 사용하지 않는다.
|
|
|
|
---
|
|
|
|
## 2. Chart Version Detector
|
|
|
|
### 역할
|
|
새로운 Helm Chart 버전 출시를 감지한다.
|
|
|
|
### 감지 방법
|
|
|
|
| 방법 | 설명 | 적합 대상 |
|
|
|------|------|---------|
|
|
| **Repo 디렉토리 스캔** | `manifests/helm/<chart>/` 하위 버전 디렉토리 변화를 감지 | dip-catalog 구조 |
|
|
| Git diff 기반 감지 | 최신 커밋에서 추가된 `<version>/` 디렉토리 파악 | dip-catalog 구조 |
|
|
| Helm repo `index.yaml` 주기 스캔 | 등록된 repo의 index 파일 직접 파싱 | 외부/사내 Helm repo |
|
|
| ArtifactHub API 조회 | `https://artifacthub.io/api/v1/packages/helm/{org}/{chart}` | 공개 chart |
|
|
| GitHub Release Webhook | 차트 소스 저장소의 release 이벤트 구독 | GitHub 기반 차트 |
|
|
| Cron 기반 스케줄링 | 위 방법들을 주기적으로 실행 | 공통 |
|
|
|
|
### 출력
|
|
|
|
```json
|
|
{
|
|
"chart": "airflow",
|
|
"repo": "apache",
|
|
"current_version": "1.2.3",
|
|
"latest_version": "1.3.0",
|
|
"detected_at": "2025-01-01T00:00:00Z"
|
|
}
|
|
```
|
|
|
|
### dip-catalog 차트 업데이트 흐름 (버전 디렉토리 유지)
|
|
|
|
신규 버전이 감지되면 dip-catalog 구조에 맞춰 **버전 디렉토리를 추가**한다.
|
|
기존 버전 디렉토리는 유지한다.
|
|
|
|
```
|
|
1) helm pull <repo>/<chart> --version <new> # 최신 차트 다운로드
|
|
2) tar xzf <chart>-<new>.tgz # 압축 해제
|
|
3) manifests/helm/<chart>/<new>/ 로 이동 # 버전 디렉토리 생성
|
|
4) chart_updater: 이전 버전 디렉토리에서 파일 복사
|
|
- custom-values.yaml → 그대로 복사
|
|
- CUSTOM-README.md → 그대로 복사 (배포 관련 내용 유지)
|
|
- BUILD-README.md → 복사 + 버전 번호 치환 (from_version → to_version)
|
|
5) generate_upgrade_doc → CUSTOM-README.md에 업그레이드 주의사항 섹션 추가 (항상 실행)
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Helm Diff Engine
|
|
|
|
### 입력
|
|
|
|
```json
|
|
{
|
|
"chart": "airflow",
|
|
"from_version": "1.2.3",
|
|
"to_version": "1.3.0",
|
|
"values_override": {},
|
|
"chart_path": "manifests/helm/airflow/1.3.0"
|
|
}
|
|
```
|
|
|
|
> dip-catalog 구조에서는 `chart_path`를 우선 사용한다.
|
|
|
|
### 처리 단계
|
|
|
|
```
|
|
1. (repo 구조) helm pull <repo>/<chart> --version <from> → chart_old/
|
|
2. (repo 구조) helm pull <repo>/<chart> --version <to> → chart_new/
|
|
1'. (dip-catalog) manifests/helm/<chart>/<from>/ 복사 → chart_old/
|
|
2'. (dip-catalog) manifests/helm/<chart>/<to>/ 복사 → chart_new/
|
|
3. values.yaml 비교 → Values Diff
|
|
4. helm template 결과 비교 → Template Diff
|
|
5. CRD schema 비교 → CRD Diff
|
|
6. Chart.yaml 비교 → Dependency Diff
|
|
7. 결과 병합 → Structured Diff JSON
|
|
```
|
|
|
|
### helm template 표준 옵션
|
|
|
|
재현성을 위해 아래 옵션을 고정한다.
|
|
|
|
```
|
|
helm template <chart> \
|
|
--values values_override.yaml \
|
|
--include-crds \
|
|
--kube-version <target_k8s_version> \
|
|
--api-versions <explicit_api_versions>
|
|
```
|
|
|
|
> `target_k8s_version`과 `api-versions`는 환경별 설정값으로 관리한다.
|
|
> dip-catalog의 경우 `custom-values.yaml`이 존재하면 `values_override` 기본값으로 적용한다.
|
|
|
|
### 에러 처리
|
|
|
|
| 상황 | 대응 |
|
|
|------|------|
|
|
| helm pull 실패 | 재시도 3회 → 실패 시 알림 후 중단 |
|
|
| chart 미존재 | 로그 기록 + 스킵 |
|
|
| helm template 렌더링 오류 | 오류 내용 JSON에 포함, partial diff 생성 |
|
|
| 네트워크 타임아웃 | 60s timeout 설정, 재시도 |
|
|
|
|
---
|
|
|
|
## 4. Values Diff 설계
|
|
|
|
### 비교 항목
|
|
|
|
- `added`: 신규 버전에서 추가된 key
|
|
- `removed`: 신규 버전에서 삭제된 key
|
|
- `changed`: default 값이 변경된 key
|
|
- `type_changed`: 값의 타입이 변경된 key (string → int 등)
|
|
|
|
### 처리 방식
|
|
|
|
values.yaml을 **flat key** 형태로 변환 후 비교한다.
|
|
|
|
- dip-catalog에서는 `custom-values.yaml`을 기본 values_override로 사용한다.
|
|
|
|
```yaml
|
|
# 중첩 구조 예시
|
|
image:
|
|
tag: 1.2.3
|
|
pullPolicy: IfNotPresent
|
|
|
|
# flat key 변환 결과
|
|
image.tag: 1.2.3
|
|
image.pullPolicy: IfNotPresent
|
|
```
|
|
|
|
> **주의**: key 이동(rename)은 `removed` + `added`로 표현된다. 의미적 rename 감지는 기본 비활성화하며, 필요한 경우 heuristic(유사도 기반) 옵션으로 제공한다.
|
|
|
|
### 출력
|
|
|
|
```json
|
|
{
|
|
"values": {
|
|
"added": ["resources.limits.cpu", "resources.limits.memory"],
|
|
"removed": ["ingress.enabled"],
|
|
"changed": {
|
|
"image.tag": { "old": "1.2.3", "new": "1.3.0" },
|
|
"replicaCount": { "old": 1, "new": 2 }
|
|
},
|
|
"type_changed": [
|
|
{ "key": "workers.replicas", "old_type": "string", "new_type": "integer" }
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Template Diff 설계
|
|
|
|
### 처리 방식
|
|
|
|
```bash
|
|
helm template <chart_old> --values values_override.yaml > old.yaml
|
|
helm template <chart_new> --values values_override.yaml > new.yaml
|
|
```
|
|
|
|
YAML을 **리소스 단위**로 분리 후 비교한다 (`kind` + `metadata.name` 기준).
|
|
- `generateName`만 존재하는 리소스는 템플릿 파일명 + 순번으로 안정적 ID를 생성한다.
|
|
- Cluster-scoped 리소스는 namespace를 무시한다.
|
|
|
|
### 비교 리소스 타입
|
|
|
|
| 리소스 | 분석 항목 |
|
|
|--------|---------|
|
|
| Deployment / StatefulSet | container image, env, resource limits, replicas |
|
|
| Service | port, targetPort, type |
|
|
| Ingress | rules, TLS, annotations |
|
|
| ConfigMap | data key 추가/삭제/변경 |
|
|
| CRD | 별도 CRD Diff로 처리 |
|
|
| ServiceAccount | annotations |
|
|
|
|
### 출력
|
|
|
|
```json
|
|
{
|
|
"templates": {
|
|
"Deployment/airflow-scheduler": {
|
|
"image_changed": true,
|
|
"image": { "old": "apache/airflow:1.2.3", "new": "apache/airflow:1.3.0" },
|
|
"env_added": ["AIRFLOW__CORE__NEW_SETTING"],
|
|
"env_removed": [],
|
|
"resource_limits_changed": true
|
|
},
|
|
"Service/airflow-webserver": {
|
|
"port_changed": false
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. CRD Diff 설계
|
|
|
|
### 비교 항목
|
|
|
|
| 항목 | 설명 |
|
|
|------|------|
|
|
| schema 변경 | OpenAPI v3 schema 필드 변경 |
|
|
| required 필드 추가 | 기존 CR에 영향 |
|
|
| field 제거 | 기존 CR의 해당 필드 무시됨 |
|
|
| version 변경 | storage version 변경 시 migration 필요 |
|
|
| webhook 변경 | conversion webhook 추가/제거 |
|
|
|
|
### 출력
|
|
|
|
```json
|
|
{
|
|
"crd": {
|
|
"AirflowCluster": {
|
|
"changed": true,
|
|
"breaking": true,
|
|
"breaking_reasons": ["required field added: spec.executor"],
|
|
"schema_changed": true,
|
|
"version_changed": false,
|
|
"fields_removed": [],
|
|
"fields_added": ["spec.executor"],
|
|
"required_fields_added": ["spec.executor"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Dependency Diff 설계
|
|
|
|
Chart.yaml의 `dependencies` 블록 비교.
|
|
|
|
```json
|
|
{
|
|
"dependencies": {
|
|
"added": ["redis"],
|
|
"removed": [],
|
|
"version_changed": {
|
|
"postgresql": { "old": "12.1.0", "new": "13.0.0" }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 8. 최종 Structured Diff JSON
|
|
|
|
LLM Summarizer에 전달되는 통합 출력:
|
|
|
|
```json
|
|
{
|
|
"chart": "airflow",
|
|
"from_version": "1.2.3",
|
|
"to_version": "1.3.0",
|
|
"generated_at": "2025-01-01T00:00:00Z",
|
|
"values": { ... },
|
|
"templates": { ... },
|
|
"crd": { ... },
|
|
"dependencies": { ... },
|
|
"errors": []
|
|
}
|
|
```
|
|
|
|
`errors` 필드에는 렌더링 실패 등의 부분적 오류를 포함한다. LLM은 이를 참고하여 분석 범위를 명시해야 한다.
|
|
|
|
---
|
|
|
|
## 9. 관련 문서
|
|
|
|
- [02-breaking-change-rules.md](02-breaking-change-rules.md) — Breaking Change 판단 로직
|
|
- [04-skill-interface.md](04-skill-interface.md) — `helm_diff` Skill 인터페이스
|