스타일 가이드

이 문서는 GitLab Helm 차트 개발에 대한 다양한 지침과 모범 사례를 설명합니다.

네이밍 규칙

함수 이름 및 values.yaml에서 사용될 속성에 대해 camelCase를 사용하고 있습니다.

예: gitlab.assembleHost

템플릿 함수는 해당하는 populized 값과 일치하도록 차트와 관련된 네임스페이스에 배치됩니다. 차트 전역(global) 함수는 일반적으로 gitlab.* 네임스페이스에 속합니다.

예시:

  • gitlab.redis.host: gitlab 차트의 일부로 Redis 서버의 호스트 이름을 제공합니다.
  • registry.minio.url: registry 차트의 일부로 MinIO 호스트의 URL을 제공합니다.

values.yaml의 일반 구조

여러 차트에서 동일한 정보를 제공해야 하는 경우, 예를 들어 Redis 및 PostgreSQL 연결 설정을 여러 차트에 제공해야 하는 경우처럼 표준 네이밍과 구조를 개요화합니다.

다른 서비스에 연결

redis:
  host: redis.example.com
  serviceName: redis
  port: 8080
    sentinels:
    - host: sentinel1.example.com
      port: 26379
  password:
    secret: gitlab-redis
    key: redis-password
  • redis - 현재 차트가 연결해야 하는 항목의 이름
  • host - 기본적으로 serviceName의 사용을 무시하고 values.yaml에서 host를 사용합니다. 기본적으로 예시로 0.0.0.0을 사용합니다. Redis Sentinel을 사용하는 경우, host 속성은 sentinel.conf에 지정된 클러스터 이름으로 설정되어야 합니다.
  • serviceName - 기본적으로 사용하기 위해 호스트 대신 사용됩니다. 쿠버네티스 서비스 이름을 사용하여 연결합니다.
  • port - 연결할 포트입니다. 기본적으로 주석 처리하여 사용하지 않으며, 예시로 기본 포트를 사용합니다.
  • password - 암호를 포함하는 쿠버네티스 시크릿을 정의합니다.
  • sentinels.[].host - Redis HA 설정에 대한 Redis Sentinel 서버의 호스트 이름을 정의합니다.
  • sentinels.[].port - Redis Sentinel 서버에 연결할 포트를 정의합니다. 기본값은 26379입니다.

참고: 현재 Redis Sentinel 지원은 일반적으로 GitLab 차트에서 별도로 배포된 Sentinels만 지원합니다. 결과적으로, GitLab 차트를 통해 Redis 배포는 redis.install=false로 비활성화되어야 합니다. Redis 암호를 포함하는 시크릿은 GitLab 차트를 배포하기 전에 수동으로 생성해야 합니다.

비밀 정보 공유

비밀 정보(예: 암호)를 저장하고 차트/팟 간에 공유하기 위해 시크릿을 사용합니다.

일반적으로 사용하는 필드는 다음과 같습니다:

  • TLS/SSL 인증서 - TLS/SSL 인증서 공유
  • 암호 - Redis 암호 공유
  • 인증 토큰 - 서비스 간 인증 토큰 공유
  • 기타 시크릿 - JWT 인증서 및 서명 키와 같은 기타 시크릿 공유

TLS/SSL 인증서

TLS/SSL 인증서는 유효한 쿠버네티스 TLS 시크릿으로 예상됩니다.

예를 들어, 레지스트리를 설정하는 경우:

registry:
  tls:
    secretName: <TLS 시크릿 이름>

차트 간에 TLS 인증서를 공유할 때, 글로벌 값으로 정의해야 합니다.

global:
  ingress:
    tls:
      secretName: <TLS 시크릿 이름>

암호

예를 들어, redis가 소유한 차트에서 다른 차트가 redis 암호를 참조해야 하는 경우입니다.

소유 차트는 다음과 같이 암호 시크릿을 정의해야 합니다:

password:
  secret: <시크릿 이름>
  key: <검색할 시크릿 내부의 키 이름>

다른 차트는 다음과 같이 동일한 암호 시크릿을 공유해야 합니다:

redis:
  password:
    secret: <시크릿 이름>
    key: <시크릿 내부의 키 이름을 가져오기 위해>

인증 토큰

소유 차트는 다음과 같이 인증 토큰 시크릿을 정의해야 합니다:

authToken:
  secret: <시크릿 이름>
  key: <검색할 시크릿 내부의 키 이름>

다른 차트는 다음과 같이 동일한 인증 토큰 시크릿을 공유해야 합니다:

gitaly:
  authToken:
    secret: <시크릿 이름>
    key: <시크릿 내부의 키 이름을 가져오기 위해>

예를 들어, gitaly가 소유한 차트에서 다른 차트가 gitaly의 authToken을 참조해야 하는 경우입니다.

기타 시크릿

registry 또는 gitaly의 JWT 서명 인증서와 같은 기타 시크릿은 authTokenpassword 시크릿과 동일한 형식을 사용합니다.

한 차트에서 다른 차트로 이러한 시크릿을 공유하려면, 다음과 같이 registry JWT 서명 인증서를 다른 차트와 공유하는 예제와 유사한 구성을 제공하십시오.

소유 차트는 다음과 같이 시크릿을 정의해야 합니다:

certificate:
  secret: <시크릿 이름>
  key: <검색할 시크릿 내부의 키 이름>

다른 차트는 다음과 같이 동일한 시크릿을 공유해야 합니다:

registry:
  certificate:
    secret: <시크릿 이름>
    key: <시크릿 내부의 키 이름을 가져오기 위해>

함수 사용을 위한 기본 설정

우리는 gotmpl, Sprig 및 Helm에서 사용 가능한 다양한 기능에 대한 차트 개발 환경을 발전시켰으며, 관련하여 선호하는 기본 설정을 정립했습니다. 아래 섹션에서는 그 중 일부와 이에 대한 이유를 설명합니다.

indent 대신 nindent 사용

가능한 경우, indent 함수 대신 nindent 함수를 사용하십시오. 이 선호 사항은 가독성을 기반으로 하며, 특히 우리의 Helm 차트와 같이 복잡할 수 있는 것에 대해 적용됩니다. nindent 함수의 선호 사용은 커뮤니티 전체에 퍼져 있으며, 또한 이제는 helm create 명령으로 생성된 템플릿 내에서 기본 설정으로 사용됩니다.

다음은 그 이유를 쉽게 설명하는 두 가지 코드 스니펫입니다:

가독성이 좋음

  gitlab.yml.erb: |
    production: &base
      gitlab:
        host: {{ template "gitlab.gitlab.hostname" . }}
        https: {{ hasPrefix "https://" (include "gitlab.gitlab.url" .) }}
        {{- with .Values.global.hosts.ssh }}
        ssh_host: {{ . | quote }}
        {{- end }}
        {{- with .Values.global.appConfig }}
        max_request_duration_seconds: {{ default (include "gitlab.appConfig.maxRequestDurationSeconds" $) .maxRequestDurationSeconds }}
        impersonation_enabled: {{ .enableImpersonation }}
        application_settings_cache_seconds: {{ .applicationSettingsCacheSeconds | int }}
        usage_ping_enabled: {{ eq .enableUsagePing true }}
        username_changing_enabled: {{ eq .usernameChangingEnabled true }}
        issue_closing_pattern: {{ .issueClosingPattern | quote }}
        default_theme: {{ .defaultTheme }}
        {{- include "gitlab.appConfig.defaultProjectsFeatures.configuration" $ | nindent 8 }}
        webhook_timeout: {{ .webhookTimeout }}
        {{- end }}
        trusted_proxies:
        {{- if .Values.trusted_proxies }}
          {{- toYaml .Values.trusted_proxies | nindent 10 }}
        {{- end }}
        time_zone: {{ .Values.global.time_zone | quote }}
        {{- include "gitlab.outgoing_email_settings" . | nindent 8 }}
      {{- with .Values.global.appConfig }}
      {{- if .incomingEmail.enabled }}
      {{- include "gitlab.appConfig.incoming_email" . | nindent 6 }}
      {{- end }}
      {{- include "gitlab.appConfig.cronJobs" . | nindent 6 }}
      gravatar:

가독성이 낮음

  gitlab.yml.erb: |
    production: &base
      gitlab:
        host: {{ template "gitlab.gitlab.hostname" . }}
        https: {{ hasPrefix "https://" (include "gitlab.gitlab.url" .) }}
{{- with .Values.global.hosts.ssh }}
        ssh_host: {{ . | quote }}
{{- end }}
{{- with .Values.global.appConfig }}
        max_request_duration_seconds: {{ default (include "gitlab.appConfig.maxRequestDurationSeconds" $) .maxRequestDurationSeconds }}
        impersonation_enabled: {{ .enableImpersonation }}
        usage_ping_enabled: {{ eq .enableUsagePing true }}
        username_changing_enabled: {{ eq .usernameChangingEnabled true }}
        issue_closing_pattern: {{ .issueClosingPattern | quote }}
        default_theme: {{ .defaultTheme }}
{{- include "gitlab.appConfig.defaultProjectsFeatures.configuration" $ | indent 8 }}
        webhook_timeout: {{ .webhookTimeout }}
{{- end }}
        trusted_proxies:
{{- if .Values.trusted_proxies }}
{{- toYaml .Values.trusted_proxies | indent 10 }}
{{- end }}
        time_zone: {{ .Values.global.time_zone | quote }}
{{- include "gitlab.outgoing_email_settings" . | indent 8 }}
{{- with .Values.global.appConfig }}
{{- if .incomingEmail.enabled }}
{{- include "gitlab.appConfig.incoming_email" . | indent 6 }}
{{- end }}
{{- include "gitlab.appConfig.cronJobs" . | indent 6 }}
      gravatar:

관련 이슈: #729 Refactoring: Helm templates

템플릿에서 toYaml을 활용할 때

템플릿 파일에서 toYaml을 사용하는 것을 삼가며, 이는 Kubernetes 및 원하는 커뮤니티 구성의 모든 기능을 지원하는 부담을 줄 수 있습니다. 우리의 주요 초점은 최소한의 구성을 사용하여 합리적인 기본 설정을 제공하는 데 있으며, Kubernetes의 더 고급 사용자를 위해 기본 설정을 재정의하는 능력을 제공하는 데에 기본 초점을 두고 있습니다. 이는 경우에 따라 처리되어야 하며, 물론 두 옵션 중 어느 것이 지원하기에 너무 번거롭거나 유지 관리하기 복잡한 템플릿을 제공하는지를 고려해야 합니다.

이와 같은 합리적인 기본 설정과 재정의 가능한 능력의 좋은 예시는 레지스트리 서브차트의 수평 팟 오토스케일러 구성에서 찾을 수 있습니다. 우리는 지원하기 쉬운 최소한의 구성을 기본 제공하는 것을 기본으로 삼으며, CPU 활용률을 통해 HPA를 제어하는 특정 구성을 커뮤니티에 노출시킴으로써, 보다 고급 사용자가 HPA의 다양한 메트릭을 대상으로 설정할 수 있게 하고, 따라서 사용자가 보다 복잡한 HPA 구성을 제공할 수 있는 경우에 대비해 if문을 활용할 수 있는 완벽한 예입니다.

위의 예시에서 최소한의 구성은 values.yaml의 간단한 변경으로 이루어지며, 보다 고급 사용자는 이 지나치게 간단한 HPA 구성을 넘어서, .customMetrics를 설정하여 HPA 메트릭 배열에 대한 적합한 Kubernetes API 호환 구성을 포함하는 배열로 override할 수 있습니다.

더 고급 사용자가 자신의 구성 파일을 불편해하지 않으면서도 가능한 한 쉽게 유지할 수 있도록 하는 것이 중요합니다.

템플릿 도우미 개발

차트 템플릿 도우미는 templates/_helpers.tpl에 위치합니다. 여기에는 차트 내에서 사용되는 명명된 템플릿이 포함되어 있습니다.

이러한 템플릿을 사용할 때 Go 템플릿 구문에 관한 몇 가지 사항을 염두에 두어야 합니다.

작업에서 인쇄되지 않는 값 포착

Go 템플릿 구문에서 모든 작업( {{ }}로 표시)은 문자열을 인쇄하는 것으로 예상됩니다. 제외한 경우는 제어 구조(정의, if, with, range) 및 변수 할당입니다.

이는 때로 인쇄되지 않을 것으로 의도된 출력을 포착하기 위해 변수 할당을 사용해야 할 수 있음을 의미합니다.

예를 들어:

{{- $details := .Values.details -}}
{{- $_ := set $details "serviceName" "example" -}}
{{ template "serviceHost" $details }}

위의 예에서는 출력에 몇 가지 추가 데이터를 추가한 후 템플릿 기능에 전달하기 위해 Map에 대한 몇 가지 포착합니다. 이를 통해$ _ 변수에 할당하여set 함수의 출력을 포착했습니다. 이 할당이 없으면 템플릿은set의 결과(수정된 Map을 반환함)를 문자열로 출력하려고 시도할 것입니다.

제어 구조 간 변수 전달

Go 템플릿 구문은 초기화( :=)와 할당( =)을 명확히 구분하며, 이는 범위에 영향을 받습니다.

결과적으로 제어 구조(if/with/range) 외부에 존재한 변수를 다시 초기화할 수 있지만, 제어 구조 내에서 선언된 변수는 외부에서 사용할 수 없음을 인식해야 합니다.

예를 들어:

{{- define "exampleTemplate" -}}
{{- $someVar := "default" -}}
{{- if true -}}
{{-   $someVar := "desired" -}}
{{- end -}}
{{- $someVar -}}
{{- end -}}

위의 예에서exampleTemplate를 호출하면 항상default를 반환합니다. 왜냐하면desired를 포함하던 변수는if 제어 구조 내에서만 접근할 수 있었기 때문입니다.

이 문제를 해결하기 위해 우리는 값이 다양한 범위에서 변경될 값을 보관할 Dictionary를 사용하거나 명시적으로 할당 연산자(=:=)를 사용하여 문제를 피하려고 노력합니다.

이 문제를 피하는 예제:

{{- define "exampleTemplate" -}}
{{- if true -}}
{{-   "desired" -}}
{{- else -}}
{{-   "default" -}}
{{- end -}}

Dictionary 사용 예제:

{{- define "exampleTemplate" -}}
{{- $result := dict "value" "default" -}}
{{- if true -}}
{{-   $_ := set $result "value" "desired" -}}
{{- end -}}
{{- $result.value -}}
{{- end -}}

초기화 대 할당의 예제 (주의깊게 살펴보세요!)

{{- define "exampleTemplate" -}}
{{- $someVar := "default" -}}
{{- if true -}}
{{-   $someVar = "desired" -}}
{{- end -}}
{{- $someVar -}}
{{- end -}}

템플릿 사용 예제:

{{- define "exampleTemplate" -}}
foo:
  bar:
   baz: bat
{{- end -}}

그리고 상기 내용을 변수 및 구성으로 가져오기:

{{- $fooVar := include "exampleTemplate" . | fromYaml -}}
{{- $barVar := merge $.Values.global.some.config $fooVar -}}
config:
{{ $barVar }}

템플릿 구성 파일

이 차트들은 클라우드 네이티브 GitLab 컨테이너를 사용합니다. 이러한 컨테이너는 ERB 또는 gomplate을 지원합니다.

지침:

  1. ConfigMap 내에서 템플릿 파일을 사용하십시오 (예: gitlab.yml.erb, config.toml.tpl)
    • 항목은 템플릿으로 처리하려면 예상된 확장자를 반드시 사용해야 합니다.
  2. 템플릿을 사용하여 마운트된 파일 위치에서 비밀 내용을 채우십시오. (예: GitLab Pages config)
  3. ERB (.erb)는 런타임 실행 중에 Ruby를 사용하는 모든 컨테이너에 사용할 수 있습니다.
  4. gomplate (.tpl)은 모든 컨테이너에 사용할 수 있습니다.

ERB 사용:

표준 ERB를 사용하며, jsonyaml 모듈이 미리로드되었음을 예상할 수 있습니다.

gomplate 사용:

컨테이너 내의 Ruby의 크기와 표면을 줄이기 위해 gomplate을 사용합니다. 우리는 Helm의{{ }} 사용과 충돌하지 않도록 gomplate 구문을 대체 구분 기호로 구성합니다. {% %}.

민감한 콘텐츠 템플릿화

시크릿은 올바르게 인코딩되거나 따옴표로 묶이지 않는 경우 유효하지 않은 YAML을 유발할 수 있는 문자를 포함할 수 있습니다. 특히 복잡한 암호의 경우, 이러한 문자열이 다양한 구성 형식에 추가되는 방법에 주의해야 합니다.

가이드라인:

  1. ERB / Gomplate 출력에서 인용 부호를 사용하세요.
  2. 가능한 경우 형식별 네이티브 인코더를 사용하세요.
    • 렌더링된 YAML에는 YAML의 슈퍼셋인 JSON 문자열을 사용하세요.
    • 렌더링된 TOML에는 TOML 문자열이 유사하게 이스케이핑되므로 JSON 문자열을 사용하세요.
  3. 따옴표로 묶인 문자열 내부와 같이 복잡성에 주의하세요. (예: 데이터베이스 연결 문자열 내부에 따옴표로 둘러싸인 문자열 등)

암호 인코딩 예시

Gitaly의 클라이언트 시크릿 토큰을 예로 들어보겠습니다. 이 값인 gitaly_token은 YAML과 TOML에 템플릿으로 사용됩니다.

예시로 my"$pec!@l"p#assword%'를 사용해 보겠습니다:

# YAML
gitaly:
  token: "<%= File.read('gitaly_token').strip =>"

# TOML
[auth]
token = "<%= File.read('gitaly_token').strip %>"

렌더링된 결과는 유효하지 않은 YAML과 유효하지 않은 TOML입니다.

# YAML
gitaly:
  token: "my"$pec!@l"p#assword%'"

(<unknown>): did not find expected key while parsing a block mapping at line 3 column 3

[auth]
token = "my"$pec!@l"p#assword%'"

Error on line 2: Expected Comment, Newline, Whitespace, or end of input but "$" found.

<%= File.read('gitaly_token').strip.to_json %>로 변경하면 YAML과 TOML의 유효한 콘텐츠 형식이됩니다. <% %> 외부의 "가 제거되었음을 주목하세요.

gitaly:
  token: "my\"$pec!@l\"p#assword%'"

gomplate로도 동일한 작업을 수행할 수 있습니다: {% file.Read "gitaly_token" | strings.TrimSpace | data.ToJSON %}

gitaly:
  # gomplate
  token: {% file.Read "./token" | strings.TrimSpace | data.ToJSON %}
  # ERB
  token: <%= File.read('gitaly_token').strip.to_json %>

템플릿 차트 노트 (NOTES.txt)

Helm의 차트 노트 기능은 차트 설치 및 업그레이드 후에 유용한 정보와 후속 지침을 제공합니다.

이러한 차트 노트는 templates/NOTES.txt에 배치됩니다.

이러한 차트 노트를 작업할 때, 출력이 가독성 있고 실행 가능하도록 스타일을 유지해야 하는 몇 가지 사항이 있습니다.

노트 범주 선택

WARNINGNOTICE 두 가지 범주는 노트 출력에서 각 유형의 항목을 나타냅니다.

  • WARNING은 설치를 최적화하기 위해 추가 조치가 필요함을 나타냅니다.
  • NOTICE는 추가 조치가 필요하지 않은 중요한 알림을 강조합니다.

NOTES.txt의 각 항목은 이 두 범주 중 하나로 시작해야 합니다. 예를 들어:

{{- if eq true .Values.some.setting }}
{{ $WARNING }}
This message is a warning.
{{- end }}

{{- if eq true .Values.some.other.setting }}
{{ $NOTICE }}
This message is a notice.
{{- end }}

이러한 예시는 출력의 각 항목 사이의 일관된 제목과 간격을 보장하는 파일 상단에 포함된 미리 정의된 변수 중 하나를 사용합니다.