helm을 배워보자 7일차 - Advance chart features

0

helm

목록 보기
7/8

Advanced Chart Features

Chart Dependencies

dependencies는 package의 하나의 요소로서, helm chart에 다른 helm chart를 포함할 수 있는 기능을 한다.

가령, wordpress helm chart에서 데이터를 저장하기 위한 database로 mysql을 사용해야 한다고 하자. wordpress helm chart에 dependency로 mysql chart를 넣어주는 방법에 대해서 알아보도록 하자.

dependencies는 Chart.yaml file안에 정의된다. 아래의 dependencies section을 주목하도록 하자.

  • Chart.yaml
dependencies:
  - name: booster
    version: ^1.0.0
    repository: https://raw.githubusercontent.com/Masterminds/learning-helm/main/
      chapter6/repository/

dependencies에 chart를 정의해주면 된다. repository에서 해당 chart를 다운받아 의존성 설치하게 되는 것이다.

helm chart는 semantic version을 사용하기 때문에 version field에 version range를 사용해주어 설치할 dependencies를 특정할 수 있다. 가령 ^1.2.3의 경우는 1.2.3 <= x < 2.0.0까지라는 말이다. 즉, major version만 올리지 말라는 것이다. 이외에도 =, !=, <, <=, >, >=, ^, ~, -의 연산을 지원한다. 또한 wildcard 연산자인 *도 지원한다.

version range에 관해서는 다음을 참고해보면 된다.

  1. ^1.2.3: 1.2.3 <= x < 2.0.0
  2. ^1.2.x: 1.2.0 <= x < 2.0.0
  3. ^2.3: 2.3 <= x < 3
  4. ^2.x: 2.0.0 <= x < 3
  5. ^0.2.3: 0.2.3 <= x < 0.3.0
  6. ^0.2: 0.2.0 <= x < 0.3.0
  7. ^0.0.3: 0.0.3 <= x < 0.0.4
  8. ^0.0: 0.0.0 <= x < 0.1.0
  9. ^0: 0.0.0 <= x < 1.0.0
  10. ~1.2.3: 1.2.3 <= x < 1.3.0
  11. ~1: 1 <= x < 2
  12. ~2.3: 2.3 <= x < 2.4
  13. ~1.2.x: 1.2.0 <= x < 1.3.0
  14. ~1.x: 1 <= x < 2

repository field는 dependency를 어디서부터 다운받을 것인 chart repository location을 지정하는 곳이다. 다음의 두 가지 방식으로 지정이 가능하다.

  1. helm repository에 대한 URL
  2. helm repo add 명령어를 사용하여 설정한 repository name 이름으로, 이 이름은 @로 wrapping되어야한다. 가령 ""@myrepo 이런 식으로 감싸야한다.

이런식으로 Chart.yaml에 dependency를 지정할 수 있는데, 문제는 운영 상에서 고정된 version의 dependency를 쓰도록 고정하는 것이 좋다는 것이다. 즉, 가장 최신 버전의 helm chart를 다운로드하여 version을 fix하는 방식인 것이다. helm에서는 helm dependency update를 통해 이를 가능하게 해준다.

helm dependency update .

해당 명령어를 사용하면 다음의 결과가 나온다.

Saving 1 charts
Downloading booster from repo https://raw.githubusercontent.com/Masterminds/
  learning-helm/main/chapter6/repository/
Deleting outdated charts

해당 명령어를 사용함으로서 몇몇 단계가 실행되었는데, 다음과 같다.

  1. helm은 dependency인 booster를 version range에 맞게 가장 최신 version이 무엇인지 결정한다. 결정된 dependency 정보들은 Chart.lock file에 쓰여진다. Chart.lock file은 dependency의 특정 version을 포함하여 사용된다.
  2. helm을 통해서 dependency의 특정 version이 지정되면, helm은 해당 version에 맞게 dependency를 charts directory아래에 다운받아 저장한다. 즉 dependency chart를 charts directory 안에 저장하는 것이다. 이때 저장하시는 방식은 archive file이거나 chart directory로 저장하는데, helm에서는 archive form으로 dependency를 저장한다.

만약, charts directory는 비어있는데, Chart.lock은 있다면 Chart.lock 파일을 통해서 다시 dependency chart를 설치할 수 있다. helm dependency build를 사용하면 된다.

dependency chart가 charts안에만 있다면 helm install, helm upgrade 실행 시에 문제없이 설치가 가능하다.

그런데, dependency chart에 value를 설정하고 싶을 수도 있다. 기본적으로 dependency 각각이 default values.yaml을 갖고 있기 때문에, 이 값을 기준으로 렌더링되지만, 만약 사용자가 값을 전달하고 싶다면 Chart.yaml에 적은 이름으로 values.yaml을 설정해주면 된다.

가령 위의 경우 wordpress chart의 Chart.yamldependenciesbooster를 설치했는데, 다음과 같이 wordpressvalues.yaml을 수정하면 해당 값이 booster에 반영된다.

  • values.yaml
booster:
  image:
    tag: 9.17.49

booster 아래에 있는 value들은 booster dependency chart에 그대로 들어간다.

dependency on/off flag

helm은 configuration을 통해서 dependencies를 enable하는 기능을 두 가지 방식으로 제공한다.

먼저, Chart.yamldependenciescondition을 통해 제공하는 방법이 있다.

  • Chart.yaml
dependencies:
  - name: booster
    version: ^1.0.0
    condition: booster.enabled
    repository: https://raw.githubusercontent.com/Masterminds/learning-helm/main/
      chapter6/repository/

condition을 보면 booster.enabled에 대한 값을 받고 있는 것을 알 수 있다. 이 값은 values.yaml file에 설정해주면 된다.

  • values.yaml
booster:
  enabled: false

booster.enabledfalse이기 때문에 해당 dependency가 설치되지 않는 것이다.

condition말고도 비슷하게 tags를 사용할 수 있는데, condition은 각 dependency에 대한 enable/disable을 관리하다면 tagstag로 묶인 dependency들의 enable/disable을 관리할 수 있다. 아래의 예제를 보도록 하자.

  • Chart.yaml
dependencies:
  - name: booster
    tags:
      - faster
    version: ^1.0.0
    repository: https://raw.githubusercontent.com/Masterminds/learning-helm/main/
      chapter6/repository/
  - name: rocket
    tags:
      - faster
    version: ^1.0.0
    repository: https://raw.githubusercontent.com/Masterminds/learning-helm/main/
      chapter6/repository/

tags부분이 array인 것에 집중하도록 하자. array이기 때문에 여러 tag들을 연결하여 enable/disable을 시킬 수 있다. 여러 tag 중 하나라도 true라면 enable되는 것이다.

  • values.yaml
tags:
  faster: false

tags.fasterfalse이기 때문에 booster와 rocket`은 disable된다.

child에서 parent chart로 value 포함하기

helm으로 개발을 하다보면 child chart(dependecies)에 있는 values.yaml 정보를 parent chart에 넘겨주어야 할 때가 있다. 이때 두 가지 방법이 있는데, 하나는 child chart의 values.yaml에 export property를 넣어서 parent chart에서 직접 import하는 방법이다.

가령, 다음과 같이 child chart의 values.yaml을 만들 수 있다.

exports:
  types:
    foghorn: rooster

exports는 special method로 이 아래에 쓰여있는 key들은 parent에 import될 수 있다.

parent chart에서 child chart의 value를 import하기 위해서는 다음과 같이 쓸 수 있다.

dependencies:
  - name: example-child
    version: ^1.0.0
    repository: https://charts.example.com/
    import-values:
      - types

import-values에 child chart에서 import할 value의 key를 써주면 parent chart에서 다음과 같이 import가 된 것으로 볼 수 있다.

foghorn: rooster

두번째 방법으로는 child에서 명시적으로 export하지 않은 values를 가져오는 방법이다. child의 values.yaml이 다음과 같다고 하자.

types:
  foghorn: rooster

이 값들은 export되지 않았지만, 강제적으로 import할 수 있다. 다음과 같이 parent chart의 Chart.yaml에서 import-values를 통해서 가져오면 된다.

  • Chart.yaml
dependencies:
  - name: example-child
    version: ^1.0.0
    repository: https://charts.example.com/
    import-values:
      - child: types
        parent: characters

child chart의 types 아래의 부분들을 parent chart의 charaters value로 넣어주는 것이다. 다음과 같다.

characters:
  foghorn: rooster

Library Charts

helm chart의 template의 많은 부분들은 common하게 사용할 수 있다. 따라서 library처럼 사용할 수 있는데, 이를 가능하게 해주는 것이 바로 library chart이다. 이 libray chart는 실제 설치되는 chart가 아니라 template를 공용으로 사용하기 위해서 존재한다.

한번 chart library를 만들어보도록 하자. helm create로 chart를 하나만들고, templates directory의 모든 file들을 삭제해주고, values.yaml 파일을 삭제하도록 하자. 이 다음 Chart.yaml file의 type을 type에서 library로 변경해주면 된다.

apiVersion: v2
name: mylib
type: library
description: an example library chart
version: 0.1.0

type의 default value는 application이므로 library로 바꾸어주어야 한다.

또한, templates안에 만드는 file들은 _로 시작해야하는데, 이렇게 써야 kubernetes cluster에 전달되지 않기 때문이다. 관례적으로 helper template가 딱 그렇다. 보통 _*.tpl 이나 _*.yaml 과 같은 방식의 file을 만든다.

template library로 mylib chart를 만들고 _configmap.yaml 파일에 다음의 code를 입력하도록 하자.

  • _configmap.yaml
{{- define "mylib.configmap.tpl" -}}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "mylib.fullname" . }}
  labels:
    {{- include "mylib.labels" . | nindent 4 }}
data: {}
{{- end -}}
{{- define "mylib.configmap" -}}
{{- template "mylib.util.merge" (append . "mylib.configmap.tpl") -}}
{{- end -}}

mylib.fullname 함수는 helm create에 의해 만들어진 chart 이름과 동일하다. labels 함수는 helm에서 추천하는 common한 label을 만들어준다. 마지막 부분에 mylib.configmap template를 정의하여 다른 template와 merge하도록 한다.

참고로 mylib.util.merge도 다른 곳에서 정의한 template 함수이다. 여기서는 그냥 다른 configmap template를 서로 concat시켜준다고 생각하면 된다.

이제 mylib.configmap을 사용해보도록 하자.

{{- include "mylib.configmap" (list . "mychart.configmap") -}}
{{- define "mychart.configmap" -}}
data:
  myvalue: "Hello Bosko"
{{- end -}}

mychart.configmap을 넘기면 mylib.configmap에서 concat을 할 때, 같은 key값을 가진 부분에 대해서 override하여 concat을 진행한다. 따라서, data부분이 override되며 다음과 같은 결과가 나온다.

apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/instance: example
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: mychart
    helm.sh/chart: mychart-0.1.0
  name: example-mychart
data:
  myvalue: Hello Bosko

잘보면 data위의 부분은 _configmap.yamlmylib.configmap.tpl이고 data부분은 mychart.configmap의 부분이다. data부분만 딱 key값으로 하여 override된 것을 볼 수 있다.

value file 스키마

각 chart마다 values.yaml에 대한 정의가 다르므로 values.yaml에 대한 스키마가 필요하다. 이를 정리해놓은 곳이 바로 values.schema.json 파일인데, 따로 개발자가 만들어야 한다. 이 파일을 만들면 helmhelm install, helm upgrade, helm lint, helm template 명령어를 사용할 때마다 values.yamlvalues.schema.json을 만족하는 지 안하는 지 검사한다.

values.schema.yaml이 아니라 values.schema.json이라면 yaml과 json이 서로 호환가능하고 json을 통한 검증이 더 쉽기 때문이다.

다음의 values.yaml file이 있다고 하자.

  • values.yaml
image:
  repository: ghcr.io/masterminds/learning-helm/anvil-app
  pullPolicy: IfNotPresent
  tag: ""

해당 values.yaml 파일에 대한 JSON schema는 다음과 같다.

  • values.schema.json
{
    "$schema": "http://json-schema.org/schema#",
    "type": "object",
    "properties": {
        "image": {
            "type": "object",
            "properties": {
                "pullPolicy": {
                    "type": "string",
                    "enum": ["Always", "IfNotPresent"]
                },
                "repository": {
                    "type": "string"
                },
                "tag": {
                    "type": "string"
                }
            }
        }
    }
}

image의 경우 object type이어야 한다. 만약 list나 string이 오게된다면 error가 발생한다. image object의 property인 pullPolicystring이지만 AlwaysIfNotPresent가 아니면 error가 발생한다.

다음의 명령어를 통해서 잘 동작하는 지 확인해보도록 하자.

helm lint . --set image.pullPolicy=foo

다음의 error가 발생한다.

==> Linting .
[ERROR] templates/: values don't meet the specifications of the schema(s) in the
following chart(s):
booster:
- image.pullPolicy: image.pullPolicy must be one of the following: "Always",
  "IfNotPresent"


Error: 1 chart(s) linted, 1 chart(s) failed

사실 json schema에서 property들을 설명하는 여러가지 방법들이 있다. 가장 대표적인 방법이 정규표현식을 사용하는 것으로 enumpattern이 그 예이다. 가령, 위의 예제에서 ["Always", "IfNotPresent"] 부분을 ^(Always|IfNotPresent)$와 같이 변경할 수 있다.

0개의 댓글