며칠 전 일이었습니다. 저희 팀은 이전에도 말했던 것처럼 off-the-shelf는 Helm으로 배포하고 있었습니다. 그런데 이번에 Helm과 함께 배포해야만 하는 resource가 생겼습니다. 일종의 extension이라고 생각하시면 좋을 것 같습니다. 이를 해결하기 위해 리드님께서 추가적인 Helm chart를 만드셨고, 값의 유효성을 검증하는 기능을 제게 맡기셨습니다. 저는 template을 아래와 같이 수정하고 기분 좋게 퇴근했습니다.
# 지정한 namespace가 kube-system인 경우 fail하도록 함
{{ if (eq .Values.namespace "kube-system") }}
{{ fail "Invalid namespace" }}
{{ end }}
apiVersion: v1
kind: ConfigMap
...
그리고 다음 날 제 commit은 리드님의 피드백과 함께 역사속으로 사라지게 됩니다. 문제는 무엇이었을까요?
Schema Files
Proposal: chart values schema에서 Helm v3에 들어갈 기능으로 values.schema
가 제안됩니다.
The chart values are pretty free-form, which is nice as it presents a very low barrier to entry. However, it would be nice if chart authors had a means to validate the values against a schema. (...)
이러한 schema는 아래와 같은 형태로 작성됩니다. 여기에서 value의 자료형, 범위 등이 정의됩니다.
{
"$schema": "https://json-schema.org/draft-07/schema#",
"properties": {
"image": {
"description": "Container Image",
"properties": {
"repo": {
"type": "string"
},
"tag": {
"type": "string"
}
},
"type": "object"
},
"name": {
"description": "Service name",
"type": "string"
},
"port": {
"description": "Port",
"minimum": 0,
"type": "integer"
},
"protocol": {
"type": "string"
}
},
"required": [
"protocol",
"port"
],
"title": "Values",
"type": "object"
}
그리고 이러한 schema는
helm install
helm upgrade
helm lint
helm template
와 같은 명령어를 사용할 때 자동으로 이용되며 유효성을 검증해줍니다.
장점
이렇게 schema를 활용하는 것이 template에서 직접 유효성을 검증하는 방법보다 더 좋은 이유는 다음과 같습니다.
- 재사용성이 뛰어납니다. 일반적으로 Helm의 value는 여러 template에서 공유되는 값입니다. 만약 schema를 사용하지 않으면 모든 template에 검증 로직을 넣어야 하고, 수정할 때도 모든 template을 수정해야 할 것입니다.
- context가 분리됩니다. template의 역할은 value를 받아 Kubernetes manifest를 생성하기 위한 틀입니다. template에서 유효성 검증하는 것은 역할을 넘어서는 일입니다. 각각의 단위는 자기가 맡은 부분에만 집중하는 것이 바람직합니다.
- 가독성이 뛰어납니다. schema를 읽는 것과 template에 있는 모든 검증 로직을 읽는 것. 둘 중 어떤 것이 value에 들어갈 값을 짐작하기 쉬울까요? 조건문에 둘러싸인 value를 읽는 것보다 선언적 구조가 보다 명료하게 읽힐 가능성이 높습니다.
정리하면, 명령적으로 구현하는 것과 선언적으로 구현하는 것의 차이로도 볼 수 있겠습니다.
마치며
제가 생각하는 Kubernetes의 가장 큰 장점 중 하나는 바로 '선언적'이라는 것입니다. 창세기처럼 'Pod이 있을지어다'라고 선언하면 그 과정을 구구절절 설명할 필요 없이 Pod이 하나 생깁니다. Helm v3에서 schema가 생긴 이유도 이와 비슷할 것이라고 생각합니다. '필요한 value는 무엇이고, 그 type은 어떠하다'고 schema를 통해 선언하는 것으로 Helm은 value의 존재와 type을 보장합니다.
이번 작업에 앞서 저는 Helm에 schema라는 기능이 있는 지 알지 못하고 있었습니다. 하지만 만약 제가 'validation logic을 작성한다'는 작업의 의미에 대해 깊이 고민해봤더라면, 아마 제 스스로 schema에 대한 니즈가 생겼을 것이고 혹시 이런 기능이 있는 지 검색해보고 찾아 사용했을 것입니다. 관성에 매몰되어 일의 본질을 생각하지 못한 점이 이번 작업에서 가장 아쉽습니다. 다음부터는 같은 실수를 반복하지 않도록 신중하게 일의 의미를 생각해보고자 합니다.