Skip to content

Split View: Helm 차트 설계 Best Practices: 네이밍, Values 설계, GitOps 통합

|

Helm 차트 설계 Best Practices: 네이밍, Values 설계, GitOps 통합


1. 네이밍 규칙

1.1 차트 이름

  • 소문자만 사용, 하이픈으로 단어 구분
  • 63자 이내 (DNS 서브도메인 규칙)
  • 예: my-web-app, backend-api, data-pipeline

1.2 리소스 이름

# _helpers.tpl의 fullname은 릴리스 이름 + 차트 이름 조합
# 63자 제한을 반드시 준수
{{- define "my-chart.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}

1.3 표준 레이블

Kubernetes 공식 권장 레이블:

# templates/_helpers.tpl
{{- define "my-chart.labels" -}}
app.kubernetes.io/name: {{ include "my-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "my-platform"
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ include "my-chart.chart" . }}
{{- end }}
레이블용도
app.kubernetes.io/name애플리케이션 이름
app.kubernetes.io/instance릴리스 인스턴스 이름
app.kubernetes.io/version앱 버전
app.kubernetes.io/component컴포넌트 역할 (frontend, backend, database)
app.kubernetes.io/part-of상위 시스템 이름
app.kubernetes.io/managed-by관리 도구 (Helm)
helm.sh/chart차트 이름-버전

2. Values 설계

2.1 Flat vs Nested 구조

# Flat 구조 - 단순하지만 관련 설정 그룹화 어려움
imageRepository: nginx
imageTag: '1.25'
imagePullPolicy: IfNotPresent

# Nested 구조 - 권장
image:
  repository: nginx
  tag: '1.25'
  pullPolicy: IfNotPresent

권장: 논리적으로 관련된 값은 중첩(nested) 구조로 그룹화합니다.

2.2 기본값(Defaults) 전략

# values.yaml - 합리적인 기본값 제공
replicaCount: 1

image:
  repository: nginx
  tag: '' # 비어있으면 Chart.appVersion 사용
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

ingress:
  enabled: false
  className: ''
  annotations: {}
  hosts: []
  tls: []

# 빈 객체/리스트로 확장 포인트 제공
podAnnotations: {}
podLabels: {}
nodeSelector: {}
tolerations: []
affinity: {}
extraEnvVars: []
extraVolumes: []
extraVolumeMounts: []

2.3 required와 기본값

# 필수값은 required 함수로 강제
image: {{ required "image.repository is required" .Values.image.repository }}

# 선택적 값은 default로 안전하게 처리
tag: {{ .Values.image.tag | default .Chart.AppVersion }}

# 복잡한 기본값 로직
{{- if .Values.persistence.existingClaim }}
claimName: {{ .Values.persistence.existingClaim }}
{{- else }}
claimName: {{ include "my-chart.fullname" . }}-data
{{- end }}

3. 멀티 환경 관리

3.1 Values 파일 레이어링

values.yaml              # 기본값 (차트에 포함)
values-common.yaml       # 공통 오버라이드
values-dev.yaml          # 개발 환경
values-staging.yaml      # 스테이징 환경
values-production.yaml   # 프로덕션 환경
# 환경별 배포
helm upgrade --install my-app ./my-chart \
  -f values-common.yaml \
  -f values-production.yaml \
  --set image.tag=v2.1.0

3.2 환경별 values 예시

# values-production.yaml
replicaCount: 3

image:
  pullPolicy: Always

resources:
  limits:
    cpu: '2'
    memory: 2Gi
  requests:
    cpu: 500m
    memory: 512Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: app.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: app-tls
      hosts:
        - app.example.com

podDisruptionBudget:
  enabled: true
  minAvailable: 2

4. 서브차트와 엄브렐라 차트

4.1 서브차트 패턴

개별 컴포넌트를 독립적인 차트로 관리:

my-platform/
  Chart.yaml
  values.yaml
  charts/
    frontend/
    backend-api/
    worker/

4.2 엄브렐라 차트

여러 서브차트를 하나로 묶어 전체 시스템을 배포:

# Chart.yaml
apiVersion: v2
name: my-platform
version: 1.0.0
type: application
dependencies:
  - name: frontend
    version: '2.x.x'
    repository: 'file://charts/frontend'
  - name: backend-api
    version: '3.x.x'
    repository: 'file://charts/backend-api'
  - name: redis
    version: '17.x.x'
    repository: 'https://charts.bitnami.com/bitnami'
    condition: redis.enabled
  - name: postgresql
    version: '12.x.x'
    repository: 'https://charts.bitnami.com/bitnami'
    condition: postgresql.enabled

4.3 서브차트 vs 엄브렐라 선택 기준

기준서브차트엄브렐라 차트
독립 배포가능불가 (전체 배포)
버전 관리컴포넌트별 독립전체 통합
복잡도낮음높음
적합한 경우마이크로서비스 개별 관리전체 플랫폼 일괄 배포

5. GitOps 통합

5.1 ArgoCD + Helm

# ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/helm-charts
    targetRevision: main
    path: charts/my-app
    helm:
      releaseName: my-app
      valueFiles:
        - values.yaml
        - values-production.yaml
      parameters:
        - name: image.tag
          value: 'v2.1.0'
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

5.2 Flux + HelmRelease

# Flux HelmRelease
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: my-app
  namespace: production
spec:
  interval: 10m
  chart:
    spec:
      chart: my-app
      version: '>=1.0.0'
      sourceRef:
        kind: HelmRepository
        name: my-charts
        namespace: flux-system
  values:
    replicaCount: 3
    image:
      repository: myregistry/my-app
      tag: v2.1.0
  valuesFrom:
    - kind: ConfigMap
      name: my-app-values
      valuesKey: production.yaml
  upgrade:
    remediation:
      retries: 3
  rollback:
    timeout: 5m

5.3 GitOps에서의 Values 관리 패턴

gitops-repo/
  apps/
    my-app/
      base/
        kustomization.yaml
        helmrelease.yaml
      overlays/
        dev/
          kustomization.yaml
          values.yaml
        staging/
          kustomization.yaml
          values.yaml
        production/
          kustomization.yaml
          values.yaml

6. 보안 Best Practices

6.1 이미지 태그 관리

# 나쁜 예: latest 태그 사용
image:
  tag: latest

# 좋은 예: 불변(immutable) 태그 또는 다이제스트 사용
image:
  tag: "v2.1.0"
  # 또는 다이제스트
  # digest: sha256:abc123...

6.2 시크릿 관리

# 나쁜 예: values에 시크릿 평문 저장
database:
  password: 'my-secret-password'

# 좋은 예: 외부 시크릿 참조
# helm-secrets, External Secrets Operator, Sealed Secrets 사용
externalSecret:
  enabled: true
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore

6.3 리소스 제한 필수화

# values.schema.json에서 resources 필수화
{
  'required': ['resources'],
  'properties': { 'resources': { 'type': 'object', 'required': ['limits', 'requests'] } },
}

6.4 SecurityContext 기본 적용

# values.yaml 기본값
podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 1000
  seccompProfile:
    type: RuntimeDefault

containerSecurityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL

7. 차트 유지보수

7.1 버전 관리 전략

  • Chart version: 차트 구조/템플릿 변경 시 증가 (SemVer)
  • appVersion: 배포하는 애플리케이션 버전
  • 두 버전은 독립적으로 관리

7.2 CHANGELOG 관리

# Chart.yaml annotations
annotations:
  artifacthub.io/changes: |
    - kind: added
      description: Add HPA support
    - kind: changed
      description: Update default resource limits
    - kind: fixed
      description: Fix ingress TLS configuration

7.3 deprecation 전략

# values.yaml에서 deprecated 값 처리
{{- if .Values.oldConfig }}
  {{- fail "oldConfig is deprecated. Use newConfig instead." }}
{{- end }}

# 또는 경고 메시지 출력
{{- if .Values.oldConfig }}
  {{- printf "WARNING: oldConfig is deprecated and will be removed in v3.0. Use newConfig instead." | fail }}
{{- end }}

8. 정리

Helm 차트 설계 Best Practices 요약:

  1. 네이밍과 레이블: Kubernetes 공식 레이블 표준 준수, 63자 제한
  2. Values 설계: Nested 구조, 합리적 기본값, 확장 포인트 제공
  3. 멀티 환경: Values 파일 레이어링으로 환경별 구성 관리
  4. 서브차트/엄브렐라: 컴포넌트 독립성과 전체 배포 편의성 균형
  5. GitOps 통합: ArgoCD Application 또는 Flux HelmRelease로 선언적 배포
  6. 보안: 불변 태그, 외부 시크릿 관리, SecurityContext 기본 적용
  7. 유지보수: SemVer, CHANGELOG, deprecation 전략

Helm Chart Design Best Practices: Naming, Values Design, GitOps Integration


1. Naming Conventions

1.1 Standard Labels

{{- define "my-chart.labels" -}}
app.kubernetes.io/name: {{ include "my-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/component: "backend"
app.kubernetes.io/part-of: "my-platform"
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ include "my-chart.chart" . }}
{{- end }}

2. Values Design

image:
  repository: nginx
  tag: '1.25'
  pullPolicy: IfNotPresent

2.2 Defaults Strategy

replicaCount: 1
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi
autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 10
ingress:
  enabled: false
podAnnotations: {}
nodeSelector: {}
tolerations: []
affinity: {}
extraEnvVars: []

3. Multi-Environment Management

3.1 Values File Layering

helm upgrade --install my-app ./my-chart \
  -f values-common.yaml \
  -f values-production.yaml \
  --set image.tag=v2.1.0

4. Subcharts and Umbrella Charts

4.1 Umbrella Chart

# Chart.yaml
dependencies:
  - name: frontend
    version: '2.x.x'
    repository: 'file://charts/frontend'
  - name: backend-api
    version: '3.x.x'
    repository: 'file://charts/backend-api'
  - name: redis
    version: '17.x.x'
    repository: 'https://charts.bitnami.com/bitnami'
    condition: redis.enabled

5. GitOps Integration

5.1 ArgoCD + Helm

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  source:
    repoURL: https://github.com/myorg/helm-charts
    targetRevision: main
    path: charts/my-app
    helm:
      releaseName: my-app
      valueFiles:
        - values.yaml
        - values-production.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

5.2 Flux + HelmRelease

apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: my-app
  namespace: production
spec:
  interval: 10m
  chart:
    spec:
      chart: my-app
      version: '>=1.0.0'
      sourceRef:
        kind: HelmRepository
        name: my-charts
  values:
    replicaCount: 3
    image:
      tag: v2.1.0
  upgrade:
    remediation:
      retries: 3

6. Security Best Practices

6.1 Immutable Tags

image:
  tag: 'v2.1.0' # Never use "latest"

6.2 External Secret Management

Use helm-secrets, External Secrets Operator, or Sealed Secrets instead of plaintext secrets in values.

6.3 SecurityContext Defaults

podSecurityContext:
  runAsNonRoot: true
  runAsUser: 1000
  seccompProfile:
    type: RuntimeDefault
containerSecurityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: ['ALL']

7. Summary

  1. Naming and labels: Follow Kubernetes official label standards, 63-char limit
  2. Values design: Nested structure, sensible defaults, extension points
  3. Multi-environment: Values file layering for environment-specific config
  4. Subcharts/umbrella: Balance component independence with deployment convenience
  5. GitOps integration: Declarative deployment via ArgoCD Application or Flux HelmRelease
  6. Security: Immutable tags, external secret management, default SecurityContext
  7. Maintenance: SemVer, CHANGELOG, deprecation strategy