helmを使って、minikubeでDifyをデプロイしてみた

# はじめに
最近、オープンソースのLLMアプリケーション開発プラットフォームであるDifyが注目されています。ローカル環境で手軽に試してみたいと思い、今回はMinikube上にHelmを使ってDifyをデプロイする手順を試してみました。

この記事では、その際の手順や確認した点についてまとめています。ローカルでの検証目的なので、本番環境とは異なる点があることにご注意ください。
# helmとは
1. Helmとは
Helmは、Kubernetesのパッケージマネージャーとよく呼ばれます。Kubernetesアプリケーションの定義、インストール、アップグレードといったライフサイクル管理を、「Chart」というパッケージ形式で簡単に行えるようにするツールです。https://artifacthub.io/ からチャートを検索・利用できます。

2. Helmを使うメリット
アプリケーションの配布者にとっては、アプリケーションのパッケージ化、依存関係管理、バージョン管理、リポジトリに公開する手段となります。一方、利用者は Helm を利用することで、Kubernetes の YAML 構文を理解する必要がなく、簡単で Kubernetes 環境上でアプリケーションをデプロイできます。加えて、Helm はアプリケーションの削除、アップグレード、ロールバックといった強力な機能を提供します。

複雑なアプリケーションも、依存関係を含めてChartとしてまとめることで、再現性のあるデプロイが可能になります。今回は Helm を利用して Dify をデプロイしてみます。
# 環境
今回検証を行った環境は以下の通りです。

- OS: Ubuntu 22.04
- Minikube: v1.35.0
- kubectl: v1.32.3
- Helm: v3.17.1
# 前期準備
デプロイを始める前に、以下のツールがインストールされている必要があります。

- Minikube: ローカルマシンでKubernetesクラスタを簡単に実行するためのツール
    - [Installing Minikube](https://minikube.sigs.k8s.io/docs/start/?arch=%2Fwindows%2Fx86-64%2Fstable%2F.exe+download)
- kubectl: Kubernetesクラスタを操作するためのコマンドラインツール
    - [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/)
- Helm: Kubernetesのパッケージマネージャー
    - [Installing Helm](https://helm.sh/docs/intro/install/)

各ツールのインストール方法は公式サイト等を参照してください。 

インストール後、Minikubeクラスタを起動します。Difyは複数のコンポーネントを実行するため、ある程度のメモリやCPUを割り当てておくと良いでしょう。
~~~bash
# メモリ4GB、CPU2コアでMinikubeを起動（メモリとCPUの指定はオプションです）
$ minikube start --memory 4g --cpus 2

# Minikubeクラスタが正常に起動したか確認
$ kubectl cluster-info

Kubernetes control plane is running at https://127.0.0.1:32769
CoreDNS is running at https://127.0.0.1:32769/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
~~~
# デプロイ

## 新しいネームスペースを作成
Difyは多くのサービスを必要とするため、管理を容易にするために、まず新しいnamespaceを作成します。
~~~bash
# Difyというネームスペースを作成
$ kubectl create namespace dify

namespace/dify created

# 結果を確認
$ kubectl get namespaces

NAME              STATUS   AGE
default           Active   101s
dify              Active   6s
kube-node-lease   Active   100s
kube-public       Active   101s
kube-system       Active   101s
~~~

:::note info
コンテクストとネームスペースの確認と切り替えはkubectxでやるとやや面倒なので、調べたら `kubectx` & `kubens` という二つのツールで上記の操作を簡単かつ迅速に行えるようになるため、個人的にはおすすめしたいです。  
:::
||kubectl|kubectx&kubens|
|---|---|---|
|contextsを列挙する|kubectl config get-contexts|kubectx|
|contextsを切り替える|kubectl config use-context <コンテキスト名>|kubectx <コンテキスト名>|
|namespacesを列挙する|kubectl get namespaces|kubens|
|namespacesを列挙する|kubectl config set-context --current --namespace=<ネームスペース名>|kubens <ネームスペース名>|

以上のように、かなり使いやすいツールだと思うので、是非使用してみてください。  
[kubectx + kubens: Power tools for kubectl](https://github.com/ahmetb/kubectx)  

## Chart で Dify をデプロイ
### 1. ArtifactHubで使用したいChartを検索する  
ArtifactHubは、クラウドネイティブなアプリケーションのためのウェブベースのリポジトリです。Kubernetesのパッケージやその他のクラウドネイティブなアーティファクトを見つけて共有するためのプラットフォームとして機能しています。  
実際にDifyを検索してみたら、以下のように関連するChartが列挙されます。今回はスターが一番多いdoubanというchartを使用したいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850641/d402641b-dcf3-4bb5-8422-7d521fb946d4.png)


:::note info  
ちなみに、箱の左側にはChart名とその提供者が表示され、右上にはこのChartの更新日時とChartのバージョン（これはデプロイされるソフトウェアのバージョンではありません）が表示されます。右下にある4つのアイコンは、このChartが署名されているか、公式に認証されているか、valuesのスキーマが提供されているか、オフィシャルであるかを示しています。
:::  
Chartの右側には、Chartを管理・使用するための様々な情報がまとめられています。インストールコマンド、Chartに含まれるKubernetesリソースのテンプレートファイル（例：configmap.yaml、deployment.yaml）、Chartのデフォルト設定値を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850641/0a6e4f11-da32-4cd8-92b8-c1b171ab9531.png)

### 2. 該当Chartをレポジトリに追加する
インストールするために、先にChartをhelmのレポジトリに追加する必要があります。
~~~bash
# レポジトリに追加する
$ helm repo add douban https://douban.github.io/charts/

"douban" has been added to your repositories

# 確認してみる 
$ helm repo list

NAME    URL
douban  https://douban.github.io/charts/
...
~~~
以上、見つけたChartをリポジトリに追加済です。

### 3. カスタマイズしたいvaluesを設定する  
多くの場合、Chartの提供者が設定したデフォルト値をそのまま使ってデプロイすることが可能です。
しかし、特定の要望に合わせて設定箇所を変更したい場合は、変更したい項目を記載した YAML ファイル（`values.yaml`）を用意して `-f` オプションで指定するか、`--set` オプションで値を個別に指定します。  
例として、今回使用するChartでは、以下の `values.yaml` のテンプレートが提供されています。
このファイルを見ると、`global > image > tag` の部分でバージョンを指定できることが分かります。
~~~yaml
global:
    # ↓ここを実際のホストドメインを変更する。ingressを使用しない場合はValueを変更しなくでもいい
    host: "mydify.example.com"
    enableTLS: false

    image:
        # ↓ここを変更して、違うバージョンのDifyをデプロイ可能です
        tag: "0.6.3"
    extraBackendEnvs:
    - name: SECRET_KEY
      value: "mysecret"
    - name: LOG_LEVEL
      value: "DEBUG"
    - name: VECTOR_STORE
      value: "milvus"

# ↓今回はnodePortで接続するので、falseにします
ingress:
    enabled: false

# デフォルト値はClusterIPなので、クラスター内しかサービスにアクセスできません。
# ↓ブラウザから動作確認するために、明示的にservice.typeをNodePortを指定する
frontend:
  service:
    type: NodePort
api:
  service:
    type: NodePort
~~~  

当然、上記以外の箇所も変更可能です。例として、`global.enableTLS`ー＞「HTTPS暗号化通信の有効化」、`VECTOR_STORE`ー＞「ベクトルデータベースの使用」などの箇所を設定することもできます。また、ここに列挙されている values だけでなく、DB、ボリュームの設定など他にも変更できます。本記事では、これ以上の詳細な説明は割愛します。
### 4. values.yamlでDifyをインストール  
`values.yaml`を作成し、ローカルに保存します。`-f`でファイルを指定して、`--install`します。
~~~bash
$ helm upgrade dify douban/dify -f values.yaml --install --debug
~~~
ログには、ユーザーがカスタマイズした values `USER-SUPPLIED VALUES` と、デフォルトの values `COMPUTED VALUES` が表示されます。`USER-SUPPLIED VALUES`がこの前に定義した`values.yaml`であることを確認できます。

### 5. インストール結果の確認
まず、`kubectl get pods`でデプロイの状況を確認します。
~~~bash
$ kubectl get pods

NAME                                  READY   STATUS    RESTARTS      AGE
dify-api-5bd8fbbcf5-xkdl7             1/1     Running   0             3m50s
dify-frontend-78f5845789-7x6bp        1/1     Running   0             3m50s
dify-plugin-daemon-56d44878f9-nqmz5   1/1     Running   3 (57s ago)   3m50s
dify-postgresql-0                     1/1     Running   0             3m50s
dify-redis-master-0                   1/1     Running   0             3m50s
dify-sandbox-76bfbbddbc-smrcg         1/1     Running   0             3m50s
dify-worker-54c4d947b7-77d4q          1/1     Running   0             3m50s
~~~
しばらく待つと、全部のpodsがRunningになって、準備完了であることが確認できます。これで、アプリケーションが minikube 上で動作しているように見えます。
続いて、マニュアルに従ってDBのマイグレーションを行います。
~~~bash
$ kubectl exec -it <dify-pod-name> -- flask db upgrade
~~~
### 6. Difyをアクセスしてみます
NodePortを指定すると、30000-32767でランダムなポートがサービスに配分されるので、`kubectl get svc`でサービスのポートを確認します。  
~~~bash
$ kubectl get svc

dify-api-svc          NodePort    10.104.8.86      <none>        80:32169/TCP   6m10s
dify-frontend         NodePort    10.100.22.170    <none>        80:30192/TCP   6m10s
dify-plugin-daemon    ClusterIP   10.106.26.114    <none>        5002/TCP       6m10s
dify-postgresql       ClusterIP   10.98.255.66     <none>        5432/TCP       6m10s
dify-postgresql-hl    ClusterIP   None             <none>        5432/TCP       6m10s
dify-redis-headless   ClusterIP   None             <none>        6379/TCP       6m10s
dify-redis-master     ClusterIP   10.106.164.5     <none>        6379/TCP       6m10s
dify-sandbox          ClusterIP   10.109.137.140   <none>        80/TCP         6m10s
~~~

frontendサービスのポートが30192であることを確認できました。続いて、ブラウザで`http://<minikubeのIP>:<port>`でDifyをアクセスしてみます。minikubeのIPは、`minikube ip`コマンドで見れます。
~~~bash
$ minikube ip
192.168.49.2
~~~
したがって、アクセスURLは以下になります。
~~~TEXT
http://192.168.49.2:30192
~~~
![スクリーンショット 2025-04-24 035451.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3850641/00912cac-6b70-4ccb-973f-5aa25e346ba2.png)

アクセス成功であることを確認できました。他にも`minikube service <difyのサービス名> -n <namespace>`で、Difyのサービスに対して、ローカルマシンから簡単にアクセスするためのURLを提供できます。

# 終わりに
この記事では、Helmを利用してMinikube上にDifyをデプロイする手順について解説しました。Helm Chartを使うことで、複雑なKubernetesアプリケーションのデプロイを効率的に行うことができます。

今回ご紹介した手順が、ローカル環境でDifyを試してみたい方や、Helmを使ったアプリケーションデプロイに関心のある方にとって、少しでもお役に立てれば幸いです。