Helm Charts: Zarządzanie pakietami Kubernetes

Wdrożenia Kubernetes z zarządzaniem pakietami Helm

Helm zrewolucjonizował wdrażanie aplikacji w Kubernetes, wprowadzając koncepcje zarządzania pakietami znane z tradycyjnych systemów operacyjnych.

W miarę wzrastającego zastosowania Kubernetes, zarządzanie złożonymi aplikacjami z dziesiątkami plików YAML staje się wyzwaniem. Helm Charts rozwiązują to problem, pakując wszystkie zasoby w wersjonowane, konfigurowalne pakiety.

software-developer w naturze To piękne zdjęcie zostało wygenerowane przez model AI Flux 1 dev.

Zrozumienie Helm: Menedżer pakietów dla Kubernetes

Helm to dla Kubernetes to, co apt jest dla Debian, yum dla RedHat, czy Homebrew dla macOS. Pakuje aplikacje Kubernetes w Charts – kolekcje plików opisujących powiązane zasoby Kubernetes. Jeden Chart może wdrożyć pełny stos aplikacji: serwery sieciowe, bazy danych, warstwy cache, reguły ingressu i komponenty monitoringu. Dla nowych użytkowników Kubernetes, Kubernetes Cheatsheet dostarcza istotnych poleceń i koncepcji, aby rozpocząć pracę.

Dlaczego Helm ma znaczenie w nowoczesnym DevOps

Zmniejszenie złożoności: Zamiast zarządzać 20+ plikami YAML, zarządzasz jednym Chartem z konfigowalnymi wartościami.

Powtarzalność: Wdrażaj identyczne konfiguracje w środowiskach deweloperskich, testowych i produkcyjnych z nadpisaniem wartości specyficznych dla środowiska. To szczególnie wartościowe przy wdrażaniu złożonych architektur mikrousług, gdzie spójność ma znaczenie.

Kontrola wersji: Charts są wersjonowane, umożliwiając łatwe cofanie się i śledzenie aktualizacji.

Eko-system społecznościowy: Tysiące gotowych Charts dostępnych przez Artifact Hub (wcześniej Helm Hub) dla popularnych aplikacji takich jak PostgreSQL, Redis, NGINX, Prometheus i wiele innych.

Moc szablonów: Szablony Go umożliwiają dynamiczne generowanie zasobów na podstawie wartości wejściowych, zmniejszając powtarzalność.

Architektura Helm i kluczowe pojęcia

Architektura Helm 3

Helm 3 uproszczyła architekturę, usuwając Tiller, problematyczny komponent serwerowy z Helm 2:

  • Helm Client: Narzędzie CLI, które bezpośrednio interaguje z API Kubernetes
  • Chart: Format pakietu zawierający szablony i metadane
  • Release: Instancja Chartu działająca w klastrze Kubernetes
  • Repository: Lokalizacja przechowywania Charts (serwer HTTP lub rejestru OCI)

Kluczowe komponenty Helm Chart

my-app-chart/
├── Chart.yaml          # Metadane i wersja Chartu
├── values.yaml         # Domyślne wartości konfiguracji
├── charts/             # Zależne Charty
├── templates/          # Szablony zasobów Kubernetes
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── _helpers.tpl    # Pomocniki szablonów
│   └── NOTES.txt       # Uwagi po instalacji
├── .helmignore         # Pliki do ignorowania przy pakowaniu
├── README.md
└── LICENSE

Tworzenie pierwszego Helm Chart

Inicjalizacja nowego Chartu

helm create my-application
cd my-application

To generuje starter Chart z przykładami szablonów dla wdrożenia, usługi i ingressu.

Chart.yaml: Definiowanie metadanych

apiVersion: v2
name: my-application
description: Chart aplikacji gotowej do produkcji
type: application
version: 1.0.0        # Wersja Chartu
appVersion: "2.4.1"   # Wersja aplikacji

maintainers:
  - name: Twoja drużyna
    email: team@company.com

dependencies:
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

values.yaml: Zarządzanie konfiguracją

Plik values.yaml definiuje domyślne konfiguracje, które użytkownicy mogą nadpisywać. Ten podejście oddziela konfigurację od szablonów, ułatwiając zarządzanie różnymi środowiskami (deweloperskie, testowe, produkcyjne) i dostosowywanie wdrożeń bez modyfikowania plików szablonów.

replicaCount: 3

image:
  repository: myapp/backend
  tag: "1.0.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

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

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

Szablony: dynamiczne manifesty Kubernetes

Szablony korzystają z składni szablonowania Go, aby dynamicznie generować zasoby Kubernetes. Te szablony mogą generować dowolny typ zasobu Kubernetes, od prostych Deployments do złożonych StatefulSets dla aplikacji wymagających trwałego magazynu. Dla aplikacji wymagających stabilnych identyfikatorów i trwałych woluminów, chcesz użyć StatefulSets zamiast Deployments, jak szczegółowo opisano w naszym przewodniku StatefulSets i Trwały Magazyn w Kubernetes.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-application.fullname" . }}
  labels:
    {{- include "my-application.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "my-application.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-application.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: 8080
          protocol: TCP
        resources:
          {{- toYaml .Values.resources | nindent 10 }}

Pomocniki szablonów (_helpers.tpl)

Utwórz ponownieużywalne funkcje szablonów, aby uniknąć powtarzania:

{{/*
Rozszerz nazwę chartu.
*/}}
{{- define "my-application.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Utwórz domyślną pełną, kwalifikowaną nazwę aplikacji.
*/}}
{{- define "my-application.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

{{/*
Zwykłe etykiety
*/}}
{{- define "my-application.labels" -}}
helm.sh/chart: {{ include "my-application.chart" . }}
{{ include "my-application.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

Zarządzanie Helm Chartami: Instalacja i operacje

Instalacja Chartu

# Instalacja z repozytorium
helm install my-release bitnami/postgresql

# Instalacja z lokalnego katalogu
helm install my-app ./my-application

# Instalacja z niestandardowymi wartościami
helm install my-app ./my-application -f values-production.yaml

# Instalacja z nadpisaniem wartości w linii poleceń
helm install my-app ./my-application \
  --set replicaCount=5 \
  --set image.tag=2.0.0

Aktualizacja wersji

# Aktualizacja z nowymi wartościami
helm upgrade my-app ./my-application -f values-production.yaml

# Aktualizacja z automatycznym cofaniem w przypadku błędu
helm upgrade my-app ./my-application --atomic --timeout 5m

# Wymuszenie aktualizacji zasobów
helm upgrade my-app ./my-application --force

Cofanie i historia

# Wyświetlenie historii wersji
helm history my-app

# Cofnięcie do poprzedniej wersji
helm rollback my-app

# Cofnięcie do konkretnej wersji
helm rollback my-app 3

Testowanie i debugowanie

# Przeglądanie generowanych manifestów bez instalacji
helm install my-app ./my-application --dry-run --debug

# Renderowanie szablonów bez instalacji
helm template my-app ./my-application

# Sprawdzanie chartu na problemy
helm lint ./my-application

# Testowanie wersji z testami hooków
helm test my-app

Zaawansowane funkcje Helm

Zależności Chartu

Charty Helm mogą zależeć od innych Chartów, umożliwiając kompozycję złożonych aplikacji z ponownieużywalnych komponentów. Jest to szczególnie przydatne przy wdrażaniu mikrousług wymagających baz danych, kolejek wiadomości lub innych usług wspierających. Zdefiniuj zależności w Chart.yaml:

dependencies:
  - 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

Aktualizacja zależności:

helm dependency update ./my-application

Hooki Helm do zarządzania cyklem życia

Hooki wykonują się w określonych punktach cyklu życia wersji:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "my-application.fullname" . }}-db-migration
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install
    "helm.sh/hook-weight": "5"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      containers:
      - name: db-migrate
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        command: ["python", "manage.py", "migrate"]
      restartPolicy: Never

Typy hooków obejmują:

  • pre-install: Przed instalacją zasobów
  • post-install: Po zainstalowaniu wszystkich zasobów
  • pre-upgrade: Przed aktualizacją
  • post-upgrade: Po aktualizacji
  • pre-delete: Przed usunięciem
  • post-delete: Po usunięciu
  • pre-rollback: Przed cofaniem
  • post-rollback: Po cofaniu

Logika warunkowa i kontrola przepływu

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "my-application.fullname" . }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if .Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
  - host: {{ .host | quote }}
    http:
      paths:
      {{- range .paths }}
      - path: {{ .path }}
        pathType: {{ .pathType }}
        backend:
          service:
            name: {{ include "my-application.fullname" $ }}
            port:
              number: {{ $.Values.service.port }}
      {{- end }}
  {{- end }}
{{- end }}

Obsługa rejestru OCI: nowoczesne dystrybucje Chartów

Od Helm 3.8, stabilna obsługa rejestru OCI (Open Container Initiative) umożliwia przechowywanie Chartów obok obrazów kontenerów.

Publikowanie w rejestrze OCI

# Logowanie do rejestru
helm registry login registry.example.com

# Pakowanie chartu
helm package ./my-application

# Wysyłanie do rejestru OCI
helm push my-application-1.0.0.tgz oci://registry.example.com/charts

# Instalacja z rejestru OCI
helm install my-app oci://registry.example.com/charts/my-application --version 1.0.0

Zalety rejestrów OCI

  • Zjednoczone przechowywanie: Charty i obrazy w jednym miejscu
  • Standardowe narzędzia: Użyj istniejącej infrastruktury rejestru
  • Lepsza zgodność: Wykorzystaj uwierzytelnienie i skanowanie rejestru
  • Prostsze zarządzanie: Nie potrzebny oddzielny serwer repozytorium Chartów

Najlepsze praktyki dla Chartów Helm w produkcji

1. Struktura wartości i dokumentacja

Dokumentuj wszystkie wartości za pomocą komentarzy:

# -- Liczba replik aplikacji
replicaCount: 3

# -- Konfiguracja obrazu
image:
  # -- Repozytorium obrazu
  repository: myapp/backend
  # -- Polityka wyciągania obrazu
  pullPolicy: IfNotPresent
  # -- Tag obrazu (domyślnie chart appVersion)
  tag: ""

2. Zarządzanie zasobami

Zawsze ustaw żądania i limity zasobów:

resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi

3. Konteksty bezpieczeństwa

Zdefiniuj konteksty bezpieczeństwa dla kontenerów:

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 1000
  capabilities:
    drop:
    - ALL
  readOnlyRootFilesystem: true

4. Testy zdrowia

Dodaj testy zdrowia i gotowości:

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

5. Zarządzanie ConfigMap i Secret

Poprawne zarządzanie sekretami jest kluczowe dla wdrożeń w produkcji. Używaj zewnętrznych menedżerów sekretów (Sealed Secrets, External Secrets Operator lub Vault) zamiast przechowywania sekretów w plikach wartości. To zapewnia, że wrażliwe dane takie jak hasła do baz danych, klucze API i certyfikaty są obsługiwane bezpiecznie:

envFrom:
- secretRef:
    name: {{ include "my-application.fullname" . }}-secrets
- configMapRef:
    name: {{ include "my-application.fullname" . }}-config

6. Walidacja schematu

Utwórz values.schema.json, aby walidować wprowadzone przez użytkownika dane:

{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "properties": {
    "replicaCount": {
      "type": "integer",
      "minimum": 1
    },
    "image": {
      "type": "object",
      "properties": {
        "repository": {
          "type": "string"
        },
        "tag": {
          "type": "string"
        }
      },
      "required": ["repository"]
    }
  },
  "required": ["image"]
}

7. NOTES.txt dla instrukcji użytkownika

Dostarcz instrukcje po instalacji:

1. Pobierz adres URL aplikacji, uruchamiając:
{{- if .Values.ingress.enabled }}
  https://{{ (index .Values.ingress.hosts 0).host }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "my-application.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- end }}

2. Monitoruj wdrożenie:
  kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ include "my-application.name" . }}"

Testowanie Chartów Helm i integracja z CI/CD

Testowanie Chartów z chart-testing (ct)

# Instalacja chart-testing
brew install chart-testing

# Sprawdzanie chartów
ct lint --config ct.yaml

# Instalacja i testowanie chartów
ct install --config ct.yaml

Przykład GitHub Actions

name: Helm Chart CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Ustawienie Helm
        uses: azure/setup-helm@v3
        with:
          version: 3.12.0

      - name: Ustawienie chart-testing
        uses: helm/chart-testing-action@v2

      - name: Sprawdzanie chartów
        run: ct lint --config ct.yaml

      - name: Tworzenie klastra kind
        uses: helm/kind-action@v1

      - name: Instalacja chartów
        run: ct install --config ct.yaml

GitOps z Helm: ArgoCD i Flux

Narzędzia GitOps takie jak ArgoCD i Flux integrują się płynnie z Chartami Helm, umożliwiając deklaratywne, automatyczne wdrażanie. Te narzędzia monitorują Twoje repozytorium Git na zmiany i automatycznie synchronizują wersje Helm, czyniąc ciągłe wdrażanie prostym. Dla złożonych architektur mikrousług, rozważ, jak wzorce transakcji rozproszonych takie jak Wzorzec Saga mogą pomóc w zarządzaniu spójnością usług wdrażanych przez Helm.

Aplikacja ArgoCD

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

HelmRelease Flux

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: my-application
  namespace: flux-system
spec:
  interval: 5m
  chart:
    spec:
      chart: my-application
      version: '1.x.x'
      sourceRef:
        kind: HelmRepository
        name: my-charts
  values:
    replicaCount: 5
    image:
      tag: "2.0.0"

Rozwiązywanie typowych problemów z Helm

Problem: Nieudana aktualizacja w stanie oczekiwania

# Sprawdź status wersji
helm list --all-namespaces

# Pobierz szczegóły wersji
helm status my-app -n namespace

# Wymuszone usunięcie, jeśli konieczne (ostrożnie)
kubectl delete secret -n namespace -l owner=helm,name=my-app

Problem: Błędy renderowania szablonów

# Debugowanie renderowania szablonów
helm template my-app ./my-application --debug

# Walidacja względem Kubernetes
helm template my-app ./my-application | kubectl apply --dry-run=client -f -

Problem: Niezastosowane wartości

# Sprawdź połączone wartości
helm get values my-app

# Pokaż wszystkie obliczone wartości
helm get values my-app --all

Eko-system Helm i narzędzia

Eko-system Helm obejmuje wiele narzędzi, które rozszerzają jego możliwości i integrują się z innymi technologiami Kubernetes. Gdy wdrażasz aplikacje wymagające zaawansowanych funkcji sieciowych, takich jak komunikacja serwer-serwer, zarządzanie ruchem i polityki bezpieczeństwa, rozważ integrację z Sieciowym Menedżerem z Istio i Linkerd, które mogą być wdrażane i zarządzane przez Charty Helm.

Kluczowe narzędzia

  • Helmfile: Deklaracyjna specyfikacja wdrażania Chartów Helm
  • Helm Diff: Podgląd zmian przed aktualizacją
  • Helm Secrets: Zarządzanie sekretami z SOPS
  • Nova: Znajdowanie przestarzałych Chartów Helm
  • Pluto: Wykrywanie przestarzałych API Kubernetes

Przykład Helmfile

repositories:
  - name: bitnami
    url: https://charts.bitnami.com/bitnami

releases:
  - name: postgresql
    namespace: database
    chart: bitnami/postgresql
    version: 12.x.x
    values:
      - postgresql:
          auth:
            database: myapp
            username: appuser

  - name: my-app
    namespace: production
    chart: ./charts/my-application
    values:
      - values-production.yaml
    needs:
      - database/postgresql

Przyszłość Helm

Eko-system Helm nadal ewoluuje:

  • Natywny OCI: Pełny przejście na rejestry OCI jako standard
  • Poprawiona zgodność: Lepsze zarządzanie sekretami i możliwości podpisu
  • Wydajność: Szybsze renderowanie i instalacja dla dużych Chartów
  • Wsparcie dla WASM: WebAssembly dla wtyczek i rozszerzeń Chartów
  • Lepsza walidacja: Zwiększone walidacje schematu i wdrażanie zasad

Podsumowanie

Helm stał się standardem de facto dla zarządzania pakietami w Kubernetes, a opanowanie go jest kluczowe dla nowoczesnych praktyk DevOps. Zrozumienie struktury Chartu, szablonów, zarządzania wartościami i najlepszych praktyk pozwala tworzyć utrzymywalne, bezpieczne i skalowalne wdrożenia Kubernetes.

Zaczynaj od prostych Chartów, stopniowo włączaj zaawansowane funkcje takie jak hooki i zależności, a także integruj się z narzędziami GitOps, aby uzyskać infrastrukturę produkcyjną. Społeczność Helm oferuje tysiące gotowych Chartów, ale prawdziwa moc pochodzi z tworzenia niestandardowych Chartów dostosowanych do potrzeb Twojej organizacji. Niezależnie od tego, czy wdrażasz aplikacje bezstanowe, czy obciążenia stanowe wymagające trwałego magazynu, Helm upraszcza złożoność zarządzania zasobami Kubernetes. Dla zespołów ustawiających nowe klastry Kubernetes, rozważ instalację Kubernetes z Kubespray lub eksplorowanie dystrybucji Kubernetes takich jak k3s lub MicroK8s dla środowisk deweloperskich. Jeśli oceniasz, która dystrybucja pasuje do potrzeb Twojej domowej sieci lub małego klastra, zobacz nasz szczegółowy porównanie dystrybucji Kubernetes dla analizy szczegółowej.

Przydatne linki