devops

Prometheus 헬름 차트 분석하기 본문

DevOps/Opensource

Prometheus 헬름 차트 분석하기

vata500 2023. 7. 9. 21:16
반응형

Helm 차트를 무작정 만드는 것은 쉬우나, 더 적은 코드로 효율적으로 짜는 것은 쉽지않다. 그러기 위해선 이미 잘 만들어진 Helm 차트를 한번 뜯어보고 어떤 흐름제어와 함수들이 사용되었는 지를 확인해보면 좋다고 생각한다.

Prometheus는 웬만한 서비스들이 사용하는 모니터링 툴이자, 차트도 잘 짜여져있어 참고해보면 좋다.

Prometheus Helm chart

# Prometheus helm root path

Chart.yaml
Chart.lock
README.md
values.yaml
templates
  - NOTES.txt
  - _helpers.tpl
  - alertmanager
  - node-exporter
  - server
  - pushgateway
  ...

Chart dependency

Helm 차트에는 여러 차트가 종속되어 있어 단순히 helm install을 통해서 리소스를 생성할 수 없다. Chart.yaml을 살펴보면 아래와 같이 dependencies 섹터에 alertmanager, kube-state-metrics... 등의 차트들이 나열된 것을 볼 수 있다.

apiVersion: v2
name: prometheus
appVersion: v2.45.0
version: 23.0.0
kubeVersion: ">=1.16.0-0"
description: Prometheus is a monitoring system and time series database.
...
dependencies:
  - name: alertmanager
    version: "0.33.*"
    repository: https://prometheus-community.github.io/helm-charts
    condition: alertmanager.enabled
  - name: kube-state-metrics
    version: "5.8.*"
    repository: https://prometheus-community.github.io/helm-charts
    condition: kube-state-metrics.enabled
  - name: prometheus-node-exporter
    version: "4.18.*"
    repository: https://prometheus-community.github.io/helm-charts
    condition: prometheus-node-exporter.enabled
  - name: prometheus-pushgateway
    version: "2.3.*"
    repository: https://prometheus-community.github.io/helm-charts
    condition: prometheus-pushgateway.enabled
...

해당 차트의 version과 repository 위치가 입력되는데, 여기서 version의 경우, patch가 *로 입력되어있다. 이는 해당 major와 minor를 만족하는 버전에서 가장 최신의 patch를 설치하도록 한다. 사용 여부는 condition의 true, false로 결정된다. 당연히 values.yaml에서 지정한다.

prometheus/values.yaml

그래서 prometheus helm chart를 설치하기 위해서는 다음과 같은 순서로 명령어를 진행한다.

  1. helm repo add (prometheus 레포지토리 추가)
  2. helm pull (prometheus 차트 다운로드)
  3. helm dependency update (종속된 패키지 다운로드)
    • charts 라는 디렉토리와 함께 종속 패키지의 tgz 파일이 생성된다.
    • Chart.lock 파일이 생성되어 다운된 종속 패키지의 내용이 담긴다.
    • helm dependency list를 통해서 다운된 종속 패키지의 리스트 확인이 가능하다.
  4. helm install (prometheus와 종속된 패키지 설치)

주요 함수

1) SplitList

<splitList>
 {{- $url := splitList "/" "helm.sh/docs/helm" }}
 host {{ first $url }}

url 배열에 ["helm.sh" "docs" "helm"] 이 추가되고 host 변수에 $url의 첫번째 값인 helm.sh가 저장된다.

2) RegexMatch

<regexMatch>
 regexmatch: {{ regexMatch ".*\\.ya?ml$" "config.yaml" }}

regex는 regular expression의 줄임말로, 첫번째 인자값과 두번째 인자값과 매치가 되면 True, 아니면 False를 출력한다.

3) Index

<index>
 colors: "{{ index.Values.colors 0 }}"
 
 # values.yaml
 # colors:
 #   - "blue"
 #   - "red"
 #   - "green"

Values.yaml을 통해 colors가 위와 같이 선언되어 있다면 index함수에서는 가장 첫번째 값인 blue가 출력된다.

path: /{{ index.Values "server" "path" "prefix" }}/ready

# values.yaml
# server:
#   path:
#     prefix: "prom"

index 함수는 위와 같이 직접 경로를 지정해서 해당 값을 출력할 수 도 있다. 위 함수의 결과는 'prom/ready'가 출력된다.

4) semver

{{- $version := semver "1.2.3-alpha.1+123" -}}

시멘틱 버전을 관리하기 위한 함수로, 위와 같은 입력은 아래와 같이 변수로 지정되어 사용할 수 있다.

$version.Major = 1
$version.Minor = 2
$version.Patch = 3
$version.Prerelease = alpha.1
$version.Metadata = 123
$version.Original = 1.2.3-alpha.1+123

yaml 파일 살펴보기

[cm.yaml]

{{- if (empty .Values.server.configMapOverrideName) -}}
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    {{- include "prometheus.server.labels" . | nindent 4 }}
    {{- with .Values.server.extraConfigmapLabels }}
    {{- toYaml . | nindent 4 }}
    {{- end }}
  name: {{ template "prometheus.server.fullname" . }}
  namespace: {{ include "prometheus.namespace" . }}
data:
  allow-snippet-annotations: "false"
{{- $root := . -}}
{{- range $key, $value := .Values.ruleFiles }}
  {{ $key }}: {{- toYaml $value | indent 2 }}
{{- end }}
{{- range $key, $value := .Values.serverFiles }}
  {{ $key }}: |
{{- if eq $key "prometheus.yml" }}
    global:
{{ $root.Values.server.global | toYaml | trimSuffix "\n" | indent 6 }}
{{- if $root.Values.server.remoteWrite }}
    remote_write:
{{ $root.Values.server.remoteWrite | toYaml | indent 4 }}
{{- end }}

{{- if (empty .Values.server.configMapOverrideName) -}}
- cm.yaml을 보면 처음 Values.yaml 에 server.configMapOverrideName이 입력되지 않았다면 true가 출력되어 cm.yaml의 내용이 적용된다. 

{{- include "prometheus.server.labels" . | nindent 4 }}
- metadata.labels에 include를 통해서 _helpers.tpl의 prometheus.server.labels의 내용들을 가져온다.

{{- range $key, $value := .Values.ruleFiles }}
  {{ $key }}: {{- toYaml $value | indent 2 }}
{{- end }}
- Values.ruleFiles의 key와 value를 불러오는 것으로 아래와 같이 ruleFiles에 선언된 내용이 입력되는데 아쉽게도 선언되어 있진 않다.

prometheus/values.yaml

[ingress.yaml]

{{- if .Values.server.ingress.enabled -}}
{{- $ingressApiIsStable := eq (include "ingress.isStable" .) "true" -}}
{{- $ingressSupportsIngressClassName := eq (include "ingress.supportsIngressClassName" .) "true" -}}
{{- $ingressSupportsPathType := eq (include "ingress.supportsPathType" .) "true" -}}
{{- $releaseName := .Release.Name -}}
{{- $serviceName := include "prometheus.server.fullname" . }}
{{- $servicePort := .Values.server.service.servicePort -}}
{{- $ingressPath := .Values.server.ingress.path -}}
{{- $ingressPathType := .Values.server.ingress.pathType -}}
{{- $extraPaths := .Values.server.ingress.extraPaths -}}
apiVersion: {{ template "ingress.apiVersion" . }}
kind: Ingress
metadata:
{{- if .Values.server.ingress.annotations }}
  annotations:
{{ toYaml .Values.server.ingress.annotations | indent 4 }}
...

spec:
  {{- if and $ingressSupportsIngressClassName .Values.server.ingress.ingressClassName }}
  ingressClassName: {{ .Values.server.ingress.ingressClassName }}
  {{- end }}
  rules:
  {{- range .Values.server.ingress.hosts }}
    {{- $url := splitList "/" . }}
    - host: {{ first $url }}
      http:
        paths:
        
 ...

{{- $releaseName := .Release.Name -}}
{{- $serviceName := include "prometheus.server.fullname" . }}
{{- $servicePort := .Values.server.service.servicePort -}}
{{- $ingressPath := .Values.server.ingress.path -}}
- Release.Name, _helpers.tpl에 선언된 server.fullname 그리고 values.yaml에 선언된 server.service.servicePort와 server.ingress.path가 각각 입된다.

  {{- range .Values.server.ingress.hosts }}
    {{- $url := splitList "/" . }}
    - host: {{ first $url }}
      http:
        paths:
  -  values.yaml에서 server.ingress.hosts 값의 전체 주소가 '/'를 기준으로 나누어져 url 변수에 배열로 할당된다. 만약 hosts의 값이 'prometheus.com/login' 이라고 한다면 first에 할당된 변수는 prometheus.com이 되기 때문에 host에 선언된다.

[sts.yaml]

...
{{- if semverCompare ">=1.13-0" .Capabilities.KubeVersion.GitVersion }}
      {{- if or (.Values.server.enableServiceLinks) (eq (.Values.server.enableServiceLinks | toString) "<nil>") }}
      enableServiceLinks: true
      {{- else }}
      enableServiceLinks: false
      {{- end }}
{{- end }}
...
          {{- range .Values.configmapReload.prometheus.extraVolumeDirs }}
            - --watched-dir={{ . }}
          {{- end }}
...

{{- if semverCompare ">=1.13-0" .Capabilities.KubeVersion.GitVersion }}
- 1.13 버전보다 뒤의 값이 큰지를 판단하는 것으로 kubeversion에서 gitversion이 크다면 true가 된다. 

 {{- if or (.Values.server.enableServiceLinks) (eq (.Values.server.enableServiceLinks | toString) "<nil>") }}
 - values.yaml에서 enbaleServiceLinks가 true면 or 조건이기 때문에 뒤이은 조건에 상관없이 if문은 true가 된다. 이 조건은enableServiceLinks의 값이 null인지 확인하는 것으로 볼 수 있다.

{{- range .Values.configmapReload.prometheus.extraVolumeDirs }}
  - --watched-dir={{ . }}
{{- end }}
- watched-dir={{ . }}는 configmapReload.prometheus.extraVolumeDirs의 watched-dir key에 입력되는 모든 값을 말한다. 

 

반응형
Comments