Helm チャート: Kubernetes パッケージ管理

Helm を使用した Kubernetes のデプロイメント

Helm は Kubernetes のアプリケーションのデプロイを革命的に変えてきました。伝統的なオペレーティングシステムでよく使われるパッケージ管理の概念を導入し、複雑なアプリケーションの管理を簡略化しました。

Kubernetes の採用が増えるにつれて、数十の YAML ファイルを管理する作業は困難になります。Helm Charts はこの問題を解決し、すべてのリソースをバージョン管理された、設定可能なパッケージにまとめます。

software-developer in the nature この素晴らしい画像は AI モデル Flux 1 dev によって生成されました。

Helm: Kubernetes のパッケージマネージャーの理解

Helm は Kubernetes にとって apt が Debian にとって、yum が RedHat にとって、Homebrew が macOS にとってのものです。Kubernetes アプリケーションを Charts にパッケージ化します。Charts は関連する Kubernetes リソースを記述するファイルのコレクションです。1つの Chart は、ウェブサーバー、データベース、キャッシュレイヤー、イングレスルール、モニタリングコンポーネントを含む、完全なアプリケーションスタックをデプロイできます。Kubernetes に初めて触れる方には、Kubernetes Cheatsheet が、開始に必要な基本的なコマンドと概念を提供します。

現代の DevOps において Helm が重要な理由

複雑性の削減: 20以上の YAML ファイルを管理する代わりに、カスタマイズ可能な値を持つ1つの Chart を管理します。

再現性: 開発、ステージング、プロダクション環境で環境固有の値の上書きにより、同じ構成をデプロイできます。これは、一貫性が重要となる複雑なマイクロサービスアーキテクチャのデプロイにおいて特に価値があります。

バージョン管理: Charts はバージョン管理され、ロールバックやアップグレードの追跡が容易になります。

コミュニティエコシステム: PostgreSQL、Redis、NGINX、Prometheus など、人気のあるアプリケーションの数千のプリビルドされた Charts が Artifact Hub(以前は Helm Hub)で利用可能です。

テンプレートの力: Go テンプレートにより、入力値に基づいて動的なリソース生成が可能となり、重複を減らします。

Helm のアーキテクチャとコアコンセプト

Helm 3 のアーキテクチャ

Helm 3 は、Helm 2 にあった問題のあるサーバーサイドコンポーネント Tiller を削除し、アーキテクチャを簡略化しました:

  • Helm クライアント: Kubernetes API と直接やり取りする CLI ツール
  • Chart: テンプレートとメタデータを含むパッケージ形式
  • リリース: Kubernetes クラスター内で実行されている Chart のインスタンス
  • リポジトリ: Charts の保存場所(HTTP サーバーまたは OCI レジストリ)

Helm Chart の主要なコンポーネント

my-app-chart/
├── Chart.yaml          # Chart のメタデータとバージョン
├── values.yaml         # デフォルトの設定値
├── charts/             # 依存する Charts
├── templates/          # Kubernetes リソーステンプレート
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── _helpers.tpl    # テンプレートヘルパー
│   └── NOTES.txt       # インストール後のノート
├── .helmignore         # パッケージング時に無視するファイル
├── README.md
└── LICENSE

あなたの最初の Helm Chart の作成

新しい Chart の初期化

helm create my-application
cd my-application

これは、デプロイメント、サービス、イングレスのテンプレートの例が含まれたスターターチャートを生成します。

Chart.yaml: メタデータの定義

apiVersion: v2
name: my-application
description: プロダクション用のアプリケーションチャート
type: application
version: 1.0.0        # Chart バージョン
appVersion: "2.4.1"   # アプリケーションのバージョン

maintainers:
  - name: あなたのチーム
    email: team@company.com

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

values.yaml: 設定管理

values.yaml ファイルは、ユーザーが上書きできるデフォルトの設定を定義します。このアプローチにより、テンプレートから設定を分離し、開発、ステージング、プロダクション環境を管理し、テンプレートファイルを変更せずにデプロイをカスタマイズできます。

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

テンプレート: 動的な Kubernetes マニフェスト

テンプレートは Go テンプレート構文を使用して、Kubernetes リソースを動的に生成します。これらのテンプレートは、単純なデプロイメントから、永続ストレージが必要なステートフルなアプリケーションの複雑なステートフルセットまで、あらゆる Kubernetes リソースタイプを生成できます。永続ストレージが必要な安定したアイデンティティを持つアプリケーションでは、ステートフルセットを使用する必要があります。これは、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 }}

テンプレートヘルパー (_helpers.tpl)

繰り返し使用するテンプレート関数を作成して、繰り返しを避けてください:

{{/*
チャートの名前を拡張します。
*/}}
{{- define "my-application.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
デフォルトの完全なアプリケーション名を作成します。
*/}}
{{- 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 }}

{{/*
共通ラベル
*/}}
{{- 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 }}

Helm Chart の管理: インストールと運用

Chart のインストール

# リポジトリからインストール
helm install my-release bitnami/postgresql

# ローカルディレクトリからインストール
helm install my-app ./my-application

# カスタム値でインストール
helm install my-app ./my-application -f values-production.yaml

# インライン値の上書きでインストール
helm install my-app ./my-application \
  --set replicaCount=5 \
  --set image.tag=2.0.0

リリースのアップグレード

# 新しい値でアップグレード
helm upgrade my-app ./my-application -f values-production.yaml

# 失敗時に自動ロールバック
helm upgrade my-app ./my-application --atomic --timeout 5m

# リソースの強制更新
helm upgrade my-app ./my-application --force

ロールバックと履歴

# リリース履歴の表示
helm history my-app

# 以前のバージョンへのロールバック
helm rollback my-app

# 特定のリビジョンへのロールバック
helm rollback my-app 3

テストとデバッグ

# 生成されるマニフェストを確認するドライラン
helm install my-app ./my-application --dry-run --debug

# インストールせずにテンプレートのレンダリング
helm template my-app ./my-application

# チャートの問題をチェック
helm lint ./my-application

# テストハックでリリースをテスト
helm test my-app

Helm の高度な機能

チャートの依存関係

Helm Charts は他の Charts に依存でき、再利用可能なコンポーネントから複雑なアプリケーションを構成できます。これは、データベース、メッセージキュー、またはその他のサポートサービスが必要なマイクロサービスをデプロイする際に特に役立ちます。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

依存関係を更新します:

helm dependency update ./my-application

Helm フックによるライフサイクル管理

フックはリリースライフサイクルの特定の時点で実行されます:

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

フックの種類には以下があります:

  • pre-install: リソースがインストールされる前
  • post-install: すべてのリソースがインストールされた後
  • pre-upgrade: アップグレードの前
  • post-upgrade: アップグレードの後
  • pre-delete: 削除の前
  • post-delete: 削除の後
  • pre-rollback: ロールバックの前
  • post-rollback: ロールバックの後

条件付き論理とフロー制御

{{- 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 }}

OCI レジストリのサポート: 現代的なチャート配布

Helm 3.8 以降、OCI(Open Container Initiative)レジストリのサポートが安定しており、チャートをコンテナイメージと一緒に保存できるようになりました。

OCI レジストリへの公開

# レジストリにログイン
helm registry login registry.example.com

# チャートをパッケージ化
helm package ./my-application

# OCI レジストリにプッシュ
helm push my-application-1.0.0.tgz oci://registry.example.com/charts

# OCI レジストリからインストール
helm install my-app oci://registry.example.com/charts/my-application --version 1.0.0

OCI レジストリの利点

  • 統一されたストレージ: チャートとイメージを1か所に保存
  • 標準ツール: 既存のレジストリインフラを活用
  • より良いセキュリティ: レジストリ認証とスキャンを活用
  • シンプルな管理: 別のチャートリポジトリサーバーが不要

本番環境用 Helm Chart のベストプラクティス

1. 値構造とドキュメント化

すべての値をコメント付きでドキュメント化します:

# -- アプリケーションのレプリカ数
replicaCount: 3

# -- イメージ構成
image:
  # -- イメージリポジトリ
  repository: myapp/backend
  # -- イメージプルポリシー
  pullPolicy: IfNotPresent
  # -- イメージタグ(デフォルトはチャートの appVersion)
  tag: ""

2. リソース管理

常にリソースのリクエストと制限を設定します:

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

3. セキュリティコンテキスト

コンテナのセキュリティコンテキストを定義します:

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

4. ヘルスチェック

リビネスとレディネスプローブを含めます:

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

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

5. ConfigMap と Secret 管理

本番環境のデプロイでは、Secret の適切な管理が重要です。値ファイルにSecretを保存する代わりに、外部のSecretマネージャー(Sealed Secrets、External Secrets Operator、またはVault)を使用してください。これにより、データベースパスワード、APIキー、証明書などの機密情報が安全に処理されます:

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

6. スキーマ検証

values.schema.json を作成してユーザー入力を検証します:

{
  "$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 によるユーザーへのガイド

インストール後の指示を提供します:

1. アプリケーションのURLを取得するには、以下のコマンドを実行してください:
{{- 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. デプロイメントの監視:
  kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ include "my-application.name" . }}"

Helm Chart のテストと CI/CD の統合

chart-testing (ct) によるチャートテスト

# chart-testing をインストール
brew install chart-testing

# チャートをリント
ct lint --config ct.yaml

# チャートをインストールしてテスト
ct install --config ct.yaml

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: Helm をセットアップ
        uses: azure/setup-helm@v3
        with:
          version: 3.12.0

      - name: chart-testing をセットアップ
        uses: helm/chart-testing-action@v2

      - name: チャートをリント
        run: ct lint --config ct.yaml

      - name: kind クラスターを作成
        uses: helm/kind-action@v1

      - name: チャートをインストール
        run: ct install --config ct.yaml

Helm と GitOps: ArgoCD と Flux

ArgoCD と Flux のような GitOps ツールは Helm Charts とシームレスに統合され、宣言型で自動化されたデプロイを可能にします。これらのツールは、Git リポジトリの変更を監視し、Helm リリースを自動的に同期します。これにより、継続的なデプロイが簡単になります。複雑なマイクロサービスアーキテクチャでは、Saga パターン などの分散トランザクションパターンが、Helm でデプロイされたサービス間の整合性を管理するために役立ちます。

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

Flux HelmRelease

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"

Helm の一般的な問題のトラブルシューティング

問題: 失敗したアップグレードが保留されている

# リリースのステータスを確認
helm list --all-namespaces

# リリースの詳細を取得
helm status my-app -n namespace

# 必要に応じて強制削除(注意が必要)
kubectl delete secret -n namespace -l owner=helm,name=my-app

問題: テンプレートレンダリングエラー

# テンプレートレンダリングをデバッグ
helm template my-app ./my-application --debug

# Kubernetes に対して検証
helm template my-app ./my-application | kubectl apply --dry-run=client -f -

問題: 値が適用されていない

# 合併された値を確認
helm get values my-app

# すべての計算済み値を表示
helm get values my-app --all

Helm エコシステムとツール

Helm エコシステムには、Kubernetes 技術と統合するための多くのツールが含まれています。サービス間通信、トラフィック管理、セキュリティポリシーなどの高度なネットワーキング機能が必要なアプリケーションをデプロイする際には、Istio と Linkerd によるサービスメッシュ を検討してください。これは Helm Charts を通じてデプロイおよび管理できます。

必須ツール

  • Helmfile: Helm Charts をデプロイするための宣言型仕様
  • Helm Diff: アップグレード前の変更をプレビュー
  • Helm Secrets: SOPS で秘密を管理
  • Nova: 過去の Helm Charts を見つける
  • Pluto: 過去の Kubernetes API を検出

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

Helm の未来

Helm エコシステムは継続的に進化しています:

  • OCIネイティブ: OCIレジストリが標準となる完全な移行
  • 改善されたセキュリティ: より良い秘密管理と署名機能
  • パフォーマンス: 大規模なChartsのより高速なレンダリングとインストール
  • WASMサポート: Chartプラグインと拡張のためのWebAssembly
  • より良い検証: 検証とポリシー強制の強化

結論

Helm は Kubernetes パッケージ管理の事実上の標準となり、現代の DevOps プラクティスにおいて習得することが不可欠です。Chart の構造、テンプレート、値管理、ベストプラクティスを理解することで、保守性が高く、安全で、拡張性のある Kubernetes デプロイを実現できます。

シンプルな Charts から始め、ハックや依存関係などの高度な機能を徐々に導入し、GitOps ツールと統合して本番環境用のインフラを構築してください。Helm コミュニティは数千のプリビルドされた Charts を提供していますが、本当の力は、あなたの組織のニーズに合わせたカスタム Charts の作成にあります。ステートレスなアプリケーションや永続ストレージが必要なステートフルなワークロードをデプロイする際、Helm は Kubernetes リソース管理の複雑さを簡略化します。新しい Kubernetes クラスターを設定するチームは、Kubespray で Kubernetes をインストール または Kubernetes ディストリビューション である k3s または MicroK8s を開発環境に使用して検討してください。家庭用ラボや小規模なクラスターのニーズに合ったディストリビューションを評価する際には、Kubernetes ディストリビューションの包括的な比較 を参照してください。

有用なリンク