dependencies는 package의 하나의 요소로서, helm chart에 다른 helm chart를 포함할 수 있는 기능을 한다.
가령, wordpress
helm chart에서 데이터를 저장하기 위한 database로 mysql
을 사용해야 한다고 하자. wordpress
helm chart에 dependency로 mysql chart를 넣어주는 방법에 대해서 알아보도록 하자.
dependencies는 Chart.yaml
file안에 정의된다. 아래의 dependencies
section을 주목하도록 하자.
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.2.3
: 1.2.3 <= x < 2.0.0^1.2.x
: 1.2.0 <= x < 2.0.0^2.3
: 2.3 <= x < 3^2.x
: 2.0.0 <= x < 3^0.2.3
: 0.2.3 <= x < 0.3.0^0.2
: 0.2.0 <= x < 0.3.0^0.0.3
: 0.0.3 <= x < 0.0.4^0.0
: 0.0.0 <= x < 0.1.0^0
: 0.0.0 <= x < 1.0.0~1.2.3
: 1.2.3 <= x < 1.3.0~1
: 1 <= x < 2~2.3
: 2.3 <= x < 2.4~1.2.x
: 1.2.0 <= x < 1.3.0~1.x
: 1 <= x < 2repository
field는 dependency를 어디서부터 다운받을 것인 chart repository location을 지정하는 곳이다. 다음의 두 가지 방식으로 지정이 가능하다.
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
해당 명령어를 사용함으로서 몇몇 단계가 실행되었는데, 다음과 같다.
booster
를 version range에 맞게 가장 최신 version이 무엇인지 결정한다. 결정된 dependency 정보들은 Chart.lock
file에 쓰여진다. Chart.lock
file은 dependency의 특정 version을 포함하여 사용된다. 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.yaml
에 dependencies
로 booster
를 설치했는데, 다음과 같이 wordpress
의 values.yaml
을 수정하면 해당 값이 booster
에 반영된다.
booster:
image:
tag: 9.17.49
booster
아래에 있는 value들은 booster
dependency chart에 그대로 들어간다.
helm은 configuration을 통해서 dependencies를 enable하는 기능을 두 가지 방식으로 제공한다.
먼저, Chart.yaml
의 dependencies
에 condition
을 통해 제공하는 방법이 있다.
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에 설정해주면 된다.
booster:
enabled: false
booster.enabled
가 false
이기 때문에 해당 dependency가 설치되지 않는 것이다.
condition
말고도 비슷하게 tags
를 사용할 수 있는데, condition
은 각 dependency에 대한 enable/disable을 관리하다면 tags
는 tag
로 묶인 dependency들의 enable/disable을 관리할 수 있다. 아래의 예제를 보도록 하자.
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되는 것이다.
tags:
faster: false
tags.faster
가 false
이기 때문에 booster
와 rocket`은 disable된다.
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
를 통해서 가져오면 된다.
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
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.yaml
의 mylib.configmap.tpl
이고 data
부분은 mychart.configmap
의 부분이다. data
부분만 딱 key값으로 하여 override된 것을 볼 수 있다.
각 chart마다 values.yaml
에 대한 정의가 다르므로 values.yaml
에 대한 스키마가 필요하다. 이를 정리해놓은 곳이 바로 values.schema.json
파일인데, 따로 개발자가 만들어야 한다. 이 파일을 만들면 helm
은 helm install
, helm upgrade
, helm lint
, helm template
명령어를 사용할 때마다 values.yaml
이 values.schema.json
을 만족하는 지 안하는 지 검사한다.
왜 values.schema.yaml
이 아니라 values.schema.json
이라면 yaml과 json이 서로 호환가능하고 json을 통한 검증이 더 쉽기 때문이다.
다음의 values.yaml
file이 있다고 하자.
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인 pullPolicy
는 string
이지만 Always
와 IfNotPresent
가 아니면 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들을 설명하는 여러가지 방법들이 있다. 가장 대표적인 방법이 정규표현식을 사용하는 것으로 enum
과 pattern
이 그 예이다. 가령, 위의 예제에서 ["Always", "IfNotPresent"]
부분을 ^(Always|IfNotPresent)$
와 같이 변경할 수 있다.