LabHub
学习 学习路径 课程

Helm Chart 的制作与发布

这个集群有那个 API 吗——Capabilities 与 crds

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

.Capabilities 로 클러스터의 버전과 API 목록을 읽어 분기하고, 그 값이 명령마다 어디서 오는지 직접 비교한다. crds/ 디렉터리가 릴리스 바깥에 산다는 것을 설치·업그레이드로 확인한다.

왜 중요한가

차트 하나를 여러 클러스터에 배포하는 순간 '이 클러스터에 그 API 가 있나' 라는 질문이 생긴다. 헬름은 .Capabilities 로 그 답을 템플릿 안에 들여놓지만, 이 값이 어디서 오는지는 명령마다 다르다. helm template 은 클러스터를 보지 않고 내장 기본값을 쓰고, helm install 은 dry-run 이어도 실제 클러스터에 물어본다. 그래서 '로컬에서는 안 나오는데 배포하면 나온다' 가 생기고, 반대로 CI 의 렌더 검사만 믿다가 운영에서 처음 보는 오브젝트가 튀어나오기도 한다. crds/ 는 여기에 한 겹을 더한다 — 템플릿이 아니고, 릴리스 매니페스트에도 없고, 설치 때 먼저 들어가고, 업그레이드에서는 손대지 않고, 릴리스를 지워도 남는다. 이 다섯 가지를 한 번씩 확인해 두면 CRD 를 담은 차트를 운영할 때 무엇을 사람이 해야 하는지가 분명해진다.

단계

  1. /root/hc-cap/sensor 차트(이름 sensor, 버전 0.1.0, values 에 widgetSize: large)를 만들고 templates/cap.yaml<릴리스이름>-cap ConfigMap 을 두세요. data 는 여섯 줄입니다 — kubeVersion·major·minor(모두 .Capabilities.KubeVersion 에서), helmVersion, hasIngress(networking.k8s.io/v1/Ingress 가 있는지), hasWidget(demo.labhub.io/v1/Widget 가 있는지). 여섯 값 모두 따옴표로 감쌉니다. helm template sense /root/hc-cap/sensor 결과를 /root/hc-cap/out/offline.yaml 에 저장하세요.
  2. 같은 차트를 쿠버네티스 1.21.0 인 것처럼 렌더해 /root/hc-cap/out/kube121.yaml 에 저장하세요. 결과의 kubeVersionv1.21.0, minor21 이어야 합니다.
  3. demo.labhub.io/v1/Widget있는 것처럼 렌더해 /root/hc-cap/out/apiversions.yaml 에 저장하세요. 결과의 hasWidgettrue 가 되고 hasIngress 는 여전히 false 여야 합니다 — 이 옵션이 기본 목록을 대체하는지 더하는지를 그 결과로 판단하세요.
  4. /root/hc-cap/sensor/templates/widget.yaml 을 만드세요. demo.labhub.io/v1/Widget 가 있을 때만 apiVersion: demo.labhub.io/v1, kind: Widget, 이름 <릴리스이름>-widget, spec.size.Values.widgetSize 인 오브젝트를 냅니다. 옵션 없이 렌더한 결과를 /root/hc-cap/out/branch-off.yaml 에, 그 API 가 있는 것처럼 렌더한 결과를 /root/hc-cap/out/branch-on.yaml 에 저장하세요.
  5. /root/hc-cap/sensor/crds/widget.yamlwidgets.demo.labhub.io CRD 를 두세요 (그룹 demo.labhub.io, 종류 Widget, 복수형 widgets, 네임스페이스 범위, 버전 v1 하나, spec.size 가 문자열인 스키마). 그다음 옵션 없이 렌더한 결과를 /root/hc-cap/out/tpl-no-crd.yaml 에, CRD 까지 함께 내보내는 옵션을 준 결과를 /root/hc-cap/out/tpl-with-crd.yaml 에 저장하세요.
  6. helm install sense /root/hc-cap/sensor 로 실제로 설치하세요. 그다음 세 가지를 저장합니다 — 릴리스 매니페스트를 /root/hc-cap/out/manifest.yaml 에, 클러스터에 만들어진 CRD 를 /root/hc-cap/out/crd-live.yaml 에, 설치된 cap ConfigMap 의 data 를 JSON 으로 /root/hc-cap/out/cap-live.json 에 저장하세요. 매니페스트에 CRD 가 들어 있는지, Widget 오브젝트는 들어 있는지 확인하세요.
  7. /root/hc-cap/sensor/crds/widget.yaml 의 스키마에 color(문자열) 필드를 더하고 helm upgrade sense /root/hc-cap/sensor 를 돌리세요. 그다음 클러스터에 지금 있는 CRD 의 spec 아래 속성 이름들을 쉼표로 이어 /root/hc-cap/out/crd-after-upgrade.txt 에 한 줄로 저장하세요. 차트에는 두 필드가 있는데 클러스터에는 몇 개가 있는지가 이 단계의 답입니다.
  8. helm template sense /root/hc-cap/sensor --validate 결과를 /root/hc-cap/out/validate.yaml 에, helm install probe /root/hc-cap/sensor --dry-run=server 결과를 /root/hc-cap/out/server-dryrun.yaml 에 저장하세요. 그리고 /root/hc-cap/out/cap-compare.jsonoffline_has_widget·validate_has_widget·dryrun_has_widget 세 키를 불리언으로 적으세요. 값은 1단계와 방금 만든 두 파일의 hasWidget 에서 읽습니다.

참고

클러스터 없이 렌더하면 무엇이 보이나

/root/hc-cap/sensor 차트(이름 sensor, 버전 0.1.0, values 에 widgetSize: large)를 만들고 templates/cap.yaml<릴리스이름>-cap ConfigMap 을 두세요. data 는 여섯 줄입니다 — kubeVersion·major·minor(모두 .Capabilities.KubeVersion 에서), helmVersion, hasIngress(networking.k8s.io/v1/Ingress 가 있는지), hasWidget(demo.labhub.io/v1/Widget 가 있는지). 여섯 값 모두 따옴표로 감쌉니다. helm template sense /root/hc-cap/sensor 결과를 /root/hc-cap/out/offline.yaml 에 저장하세요.

helm template 은 클러스터에 묻지 않습니다. 헬름 안에 박혀 있는 기본 능력 목록을 쓰므로, 실제로는 있는 Ingress 도 여기서는 없다고 나옵니다. 이 사실을 먼저 눈으로 확인해 두면 뒤 단계에서 값이 달라지는 이유가 분명해집니다. 릴리스 이름은 이 실습 내내 sense 입니다.

클러스터 없이 다른 버전인 척 렌더한다

같은 차트를 쿠버네티스 1.21.0 인 것처럼 렌더해 /root/hc-cap/out/kube121.yaml 에 저장하세요. 결과의 kubeVersionv1.21.0, minor21 이어야 합니다.

helm template 에는 버전을 직접 주는 옵션이 있습니다(helm template --help 에서 kube 로 시작하는 것). 옛 클러스터를 아직 쓰는 고객이 있을 때, 그 클러스터를 만들지 않고도 분기가 제대로 도는지 시험할 수 있다는 것이 이 옵션의 값어치입니다.

없는 API 가 있는 척 렌더한다

demo.labhub.io/v1/Widget있는 것처럼 렌더해 /root/hc-cap/out/apiversions.yaml 에 저장하세요. 결과의 hasWidgettrue 가 되고 hasIngress 는 여전히 false 여야 합니다 — 이 옵션이 기본 목록을 대체하는지 더하는지를 그 결과로 판단하세요.

API 목록을 직접 주는 옵션이 따로 있습니다. 여러 개를 주려면 옵션을 여러 번 쓰거나 쉼표로 잇습니다. 형식은 <그룹>/<버전>/<종류> 입니다. CRD 로 들어오는 자원에 의존하는 차트를 클러스터 없이 시험할 때 쓰는 방법입니다.

능력에 따라 오브젝트를 넣고 뺀다

/root/hc-cap/sensor/templates/widget.yaml 을 만드세요. demo.labhub.io/v1/Widget 가 있을 때만 apiVersion: demo.labhub.io/v1, kind: Widget, 이름 <릴리스이름>-widget, spec.size.Values.widgetSize 인 오브젝트를 냅니다. 옵션 없이 렌더한 결과를 /root/hc-cap/out/branch-off.yaml 에, 그 API 가 있는 것처럼 렌더한 결과를 /root/hc-cap/out/branch-on.yaml 에 저장하세요.

if 블록 전체를 {{- ... }} 로 감싸면 조건이 거짓일 때 빈 줄조차 남지 않습니다. 조건이 거짓이면 이 파일은 아무것도 내지 않으므로 렌더 결과에서 문서 하나가 통째로 사라집니다. 차트 하나로 CRD 가 있는 클러스터와 없는 클러스터를 함께 지원하는 표준적인 방법입니다.

crds 디렉터리는 템플릿이 아니다

/root/hc-cap/sensor/crds/widget.yamlwidgets.demo.labhub.io CRD 를 두세요 (그룹 demo.labhub.io, 종류 Widget, 복수형 widgets, 네임스페이스 범위, 버전 v1 하나, spec.size 가 문자열인 스키마). 그다음 옵션 없이 렌더한 결과를 /root/hc-cap/out/tpl-no-crd.yaml 에, CRD 까지 함께 내보내는 옵션을 준 결과를 /root/hc-cap/out/tpl-with-crd.yaml 에 저장하세요.

crds/ 안의 파일은 템플릿 엔진을 거치지 않습니다 — 중괄호를 써도 그냥 글자입니다. 그래서 기본 렌더 결과에도 나오지 않습니다. 내보내려면 옵션을 따로 줘야 합니다(helm template --help 에서 crds 가 든 옵션). 이 디렉터리가 특별 대접을 받는 이유는 CRD 가 그것을 쓰는 오브젝트보다 먼저 들어가야 하기 때문입니다.

진짜 클러스터에 넣으면 능력이 달라진다

helm install sense /root/hc-cap/sensor 로 실제로 설치하세요. 그다음 세 가지를 저장합니다 — 릴리스 매니페스트를 /root/hc-cap/out/manifest.yaml 에, 클러스터에 만들어진 CRD 를 /root/hc-cap/out/crd-live.yaml 에, 설치된 cap ConfigMap 의 data 를 JSON 으로 /root/hc-cap/out/cap-live.json 에 저장하세요. 매니페스트에 CRD 가 들어 있는지, Widget 오브젝트는 들어 있는지 확인하세요.

helm get manifest <릴리스> 가 그 릴리스에 기록된 매니페스트를 냅니다. kubectl get cm sense-cap -o jsonpath='{.data}' 로 data 를 JSON 으로 꺼낼 수 있습니다. 설치는 클러스터에 물어보므로 hasIngress 가 로컬 렌더와 달라집니다. CRD 는 템플릿보다 먼저 들어가기 때문에, 첫 설치에서도 Widget 조건이 참이 됩니다 — 직접 확인하세요.

crds 를 고치고 업그레이드해도 클러스터는 그대로다

/root/hc-cap/sensor/crds/widget.yaml 의 스키마에 color(문자열) 필드를 더하고 helm upgrade sense /root/hc-cap/sensor 를 돌리세요. 그다음 클러스터에 지금 있는 CRD 의 spec 아래 속성 이름들을 쉼표로 이어 /root/hc-cap/out/crd-after-upgrade.txt 에 한 줄로 저장하세요. 차트에는 두 필드가 있는데 클러스터에는 몇 개가 있는지가 이 단계의 답입니다.

헬름은 crds/설치 때만 넣고 업그레이드에서는 손대지 않습니다. 공식 문서가 이것을 제한으로 명시하고 있고, CRD 갱신은 사람이 kubectl apply 로 하라고 안내합니다. 속성 이름은 kubectl get crd <이름> -o json 에서 .spec.versions[0].schema.openAPIV3Schema.properties.spec.properties 의 키로 꺼냅니다.

같은 차트, 세 가지 답 — 정리한다

helm template sense /root/hc-cap/sensor --validate 결과를 /root/hc-cap/out/validate.yaml 에, helm install probe /root/hc-cap/sensor --dry-run=server 결과를 /root/hc-cap/out/server-dryrun.yaml 에 저장하세요. 그리고 /root/hc-cap/out/cap-compare.jsonoffline_has_widget·validate_has_widget·dryrun_has_widget 세 키를 불리언으로 적으세요. 값은 1단계와 방금 만든 두 파일의 hasWidget 에서 읽습니다.

--validate 는 렌더 결과를 API 서버에 보내 검증하므로 능력도 클러스터에서 가져옵니다. --dry-run=server 도 마찬가지입니다. 클러스터를 보지 않는 것은 옵션 없는 helm template 뿐입니다. 따옴표 없는 true/false 여야 합니다 — 문자열로 적으면 안 됩니다.