実践的Helm入門：依存関係を含むチャートの作成からデプロイまで

今回は、Kubernetes用パッケージマネージャーであるHelmについて、依存関係を含むチャートの作成から、よく使用されるコマンドの実行、そしてデプロイまでやってみます。

GitHubのリポジトリは[こちら](https://github.com/asami-okina/helm-practice)です。

# 1. Helm
Helmは、Kubernetes用のパッケージマネージャーです。複雑なアプリケーションの定義、インストール、アップグレードを簡単に行えるツールです。

# 2. Helmの主要概念
## 2.1 Helmチャート
Helmチャートは、Kubernetesリソースを記述するファイルの集まりです。
チャートは、Kubernetesアプリケーション、ツール、またはサービスをパッケージ化する標準的な方法です。

チャートの主な特徴：
- 再利用可能：同じチャートを異なる環境やコンテキストで使用できます。
- バージョン管理可能：チャートはバージョン管理され、更新や rollback が容易です。
- 依存関係の管理：他のチャートを依存関係として含めることができます。
- テンプレート化：動的な値を使用してKubernetesマニフェストを生成できます。

## 2.2 Helmリリース
Helmリリースは、Kubernetesクラスタにインストールされたチャートの特定のインスタンスを指します。

リリースの主な特徴：
- 一意性：各リリースは一意の名前を持ちます。
- 状態管理：リリースの状態（インストール済み、アップグレード済み、削除済みなど）を追跡します。
- バージョン履歴：リリースの各バージョンを記録し、ロールバックを可能にします。
- 設定の分離：同じチャートから作成された異なるリリースは、異なる設定を持つことができます。

リリースの例：
- `helm install my-wordpress bitnami/wordpress` を実行すると、`my-wordpress`という名前のリリースが作成されます。
- 同じチャートを使用して`helm install another-wp bitnami/wordpress`を実行すると、`another-wp`という別のリリースが作成されます。

これらは同じ`Wordpress`チャートを使用していますが、別々のリリースとして扱われ、独立して管理できます。

# 3. Helmの主要コンポーネント
Helmチャートの主要コンポーネントには、`Chart.yaml`、`values.yaml`、`charts/`ディレクトリ、`templates/`ディレクトリ、そして`_helpers.tpl`ファイルがあります。それぞれの役割と違いを詳しく見ていきましょう。

## 3.1 Chart.yaml
`Chart.yaml`は、Helmチャートのメタデータを定義するファイルです。

役割：
- チャートの名前、バージョン、説明などの基本情報を提供
- チャートの依存関係を定義
- チャートのタイプやアプリケーションのバージョンを指定

```yaml:例
apiVersion: v2
name: myapp
description: A Helm chart for Kubernetes
version: 0.1.0
dependencies:
  - name: redis
    version: "0.1.0"
    repository: "file://charts/redis"
```

## 3.2 values.yaml
`values.yaml`は、チャートのデフォルト設定値を定義するファイルです。

役割：
- チャート全体で使用される設定値のデフォルトを提供
- ユーザーがカスタマイズ可能な値を定義
- テンプレートファイルで参照される変数の値を設定

```yaml:例
replicaCount: 2
image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "1.21"

redis:
  enabled: true
```

## 3.3 charts/ディレクトリ
`charts/ディレクトリ`は、このチャートが依存する他のチャートを格納する場所です。

役割：
- 依存チャートを保存
- ローカルでの依存関係管理を可能にする
- 複数のチャートを組み合わせた複雑なアプリケーションの構築をサポート

## 3.4 templates/ディレクトリ
`templates/ディレクトリ`は、Kubernetesリソースのテンプレートファイルを格納する場所です。

役割：
- Kubernetesマニフェストのテンプレートを保存
- 動的な値を使用してマニフェストを生成
- Go テンプレート言語を使用して柔軟な設定を可能にする

```yaml:例deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-myapp
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}-myapp
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-myapp
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
```

## 3.5 _helpers.tpl ファイル
このファイルは通常、`templates/`ディレクトリに配置されます。
`.tpl`は`template`の意味です。

主な特徴と役割：
- 再利用可能なテンプレート関数（named templates）を定義します。
- チャート全体で使用される共通のロジックや命名規則を一箇所にまとめます。
- テンプレートの再利用性を高め、メンテナンス性を向上させます。

### _helpers.tpl の構造
`_helpers.tpl`ファイルは、複数の named templates を含みます。各テンプレートは define 関数で定義されます。

```go:例
{{/* Generate basic labels */}}
{{- define "mychart.labels" -}}
app: {{ .Chart.Name }}
chart: {{ .Chart.Name }}-{{ .Chart.Version }}
release: {{ .Release.Name }}
{{- end -}}

{{/* Generate the full name for resources */}}
{{- define "mychart.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
```

```go:イメージ
{{- define "関数名" -}}
  ... 関数の内容 ...
{{- end }}
```

### _helpers.tpl の使用方法
他のテンプレートファイルから、これらの関数を`include`関数を使って呼び出すことができます。

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: {{ include "mychart.fullname" . }}
  labels:
    {{- include "mychart.labels" . | nindent 4 }}
spec:
  containers:
    - name: {{ .Chart.Name }}
      image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
```

### _helpers.tpl の利点
1. コードの重複を減らします。
2. チャート全体で一貫性のある命名や設定を確保します。
3. 複雑なロジックを一箇所にまとめることで、メンテナンスが容易になります。
4. チャートの可読性と再利用性が向上します。

`_helpers.tpl`ファイルを効果的に使用することで、特に大規模なチャートや、複数のチャートで共通のロジックを使用する場合に、Helmチャートの管理が大幅に改善されます。


## 主要コンポーネントの違い
### 1. 目的
- Chart.yaml: チャートの定義とメタデータ
- values.yaml: 設定値の定義
- charts/: 依存チャートの格納
- templates/: Kubernetesリソースのテンプレート定義

### 2. カスタマイズ性
- Chart.yaml: チャート開発者が主に編集
- values.yaml: エンドユーザーが頻繁にカスタマイズ
- charts/: チャート開発者が依存関係を管理
- templates/: チャート開発者がリソース構造を定義

### 3. 使用タイミング
- Chart.yaml: チャートの作成時や更新時
- values.yaml: チャートのインストール時やアップグレード時
- charts/: 依存関係の追加や更新時
- templates/: Kubernetesリソースの定義時やカスタマイズ時

# 4. プロジェクト構造
これらのコンポーネントを使用して、Nginxをメインアプリケーションとし、Redisを依存チャートとして使用する例を作成します。

```txt
myapp/
│
├── Chart.yaml
├── values.yaml
├── charts/
│   └── redis/
│       ├── Chart.yaml
│       ├── values.yaml
│       └── templates/
│           └── deployment.yaml
└── templates/
    ├── deployment.yaml
    └── service.yaml
```

# 5. チャートの作成
まず、メインチャートを作成します。

```sh
helm create myapp
cd myapp
```

![](https://storage.googleapis.com/zenn-user-upload/55d90e71eca8-20241002.png)

次に、Redisの依存チャートを作成します。

```sh
mkdir -p charts/redis
helm create charts/redis
```

# 6. チャートの内容
各ファイルの内容を以下のように編集します。

## myapp/Chart.yaml
```yaml
apiVersion: v2
name: myapp
description: A Helm chart for Kubernetes
version: 0.1.0
dependencies:
  - name: redis
    version: "0.1.0"
    repository: "file://charts/redis"
```

## myapp/values.yaml
```yaml
replicaCount: 2
image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "1.21"

redis:
  enabled: true
```

## myapp/charts/redis/Chart.yaml
```yaml
apiVersion: v2
name: redis
description: A Helm chart for Redis
version: 0.1.0
```

## myapp/charts/redis/values.yaml
```yaml
replicaCount: 1
image:
  repository: redis
  pullPolicy: IfNotPresent
  tag: "6.2"
```

## myapp/charts/redis/templates/deployment.yaml
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-redis
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}-redis
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-redis
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
```

## myapp/templates/deployment.yaml
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-myapp
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}-myapp
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}-myapp
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
```

## myapp/templates/service.yaml
```yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}-myapp
spec:
  selector:
    app: {{ .Release.Name }}-myapp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
```

# 7. Helmコマンドの実行
ここで、よく使用される3つのHelmコマンドを実行してみましょう。

## 7.1 helm dependency update .
このコマンドは、Chart.yamlで定義された依存関係を更新します。

```sh
helm dependency update .
```

## 7.2 helm dependency build .
このコマンドは、依存チャートをビルドし、必要に応じてパッケージ化します。
```sh
helm dependency build .
```

## 7.3 helm template .
このコマンドは、チャート全体（依存チャートを含む）をレンダリングし、生成されるKubernetesマニフェストを表示します。

```sh
helm template .
```

# 8. チャートのデプロイ
最後に、作成したチャートをKubernetesクラスタにデプロイしてみましょう。

```sh
helm install myapp-release .
```

デプロイが成功したら、以下のコマンドでポッドの状態を確認できます。

```sh
kubectl get pods
```

# その他
## Helmのテンプレート機能と変数
Helmのテンプレート機能は、Go言語のテンプレートエンジンを使用しています。これにより、動的にKubernetesマニフェストを生成することができます。

### Release.Name
`.Release.Name`は、Helmのビルトイン変数の一つで、チャートがインストールされる際に指定されるリリース名を表します。

- 値の決定：`helm install`コマンド実行時にユーザーが指定するか、指定がない場合はHelmが自動生成します。
- 使用例：`helm install my-release ./mychart`の場合、`.Release.Name`は`my-release`となります。
- 目的：同じチャートの複数のインスタンスを区別するために使用されます。

```yaml:例deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-myapp
spec:
  # ... 以下省略
```

### その他のよく使用される変数
- `.Values`: `values.yaml`ファイルの内容や`--set`フラグで指定された値にアクセスします。
- `.Chart`: `Chart.yaml`ファイルの内容にアクセスします。
- `.Capabilities`: Kubernetesクラスタの機能に関する情報を提供します。

```yaml:例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-{{ .Chart.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  # ... 以下省略
```