Difyコミュニティエディション を Docker 環境へ導入

Docker (on Ubuntu) 環境に、Dify コミュニティエディションを導入します。

## 全体構成図（構想）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/d0ec9a94-3f1a-467a-8edb-35309836ce88.png)

自宅PC の Dify で専用のチャットボットやエージェントを作成し、外出先から24時間いつでも利用できる環境を構築する予定です。
今回は一番右側、「Home Network」での作業となります。

::: note info
[Dify公式サイト](https://dify.ai/jp) のクラウドサービスや、AWS・XServer のサーバーレンタルでも実現は可能ですが、さすがに24時間稼働だと運用コストが跳ね上がってしまいます。
ミニPCでどこまでできるのか、実験を兼ねて自前で用意することにします。
:::

### Docker コンテナ 構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/2bffa3b5-5c51-484a-b285-5617256fa6bf.png)

#### HTTP/HTTPS 接続先ポート番号
通常、Dify コンテナはホストOSの ```80,443```番ポート を使用します。
しかしホストOSでこれらを利用するケースもあり、別のポート番号に変えておいた方が良いでしょう。
```.env```というファイルを編集して、```20080,20443```番ポートへ接続するようにします。

#### Difyを構成するコンテナ群
前述の図では省略していますが、実際の Docker は多数のコンテナから構成されています。
```docker-compose.yaml```というファイルから拾い上げたコンテナ一覧を列挙しておきます。（説明欄は結構いい加減なので注意してください）
|名称|説明|
|:-|:-|
|api|DifyのバックエンドAPIサーバーです。ユーザーインターフェースからのリクエストを受け付け、ビジネスロジックを実行し、データベースや他のサービスと連携します。|
|worker|バックグラウンドタスクを実行するワーカープロセスです。大規模なデータ処理、モデルのトレーニング、非同期処理などを担当します。APIサーバーからの指示を受けて動作します。|
|web|DifyのフロントエンドWebアプリケーションを提供するサーバーです。ユーザーがDifyを操作するためのインターフェースを提供します。|
|db|Difyが利用するデータベースサーバーです。アプリケーションの設定、ユーザー情報、会話履歴、データソース情報などを永続的に保存します。|
|redis|インメモリのデータ構造ストアであり、キャッシュ、メッセージブローカー、セッション管理などに利用されます。Difyでは、APIサーバーとワーカー間の通信や、頻繁にアクセスされるデータの高速な読み書きなどに使用される可能性があります。|
|sandbox|コードの実行環境を隔離するためのサンドボックス環境を提供するサービスです。ユーザーがアップロードしたコードや、Difyの機能内で動的に生成されたコードを安全に実行するために利用されます。|
|plugin_daemon|Difyのプラグイン機能を管理するデーモンプロセスです。外部のサービスやツールと連携するためのプラグインのロード、アンロード、実行などを担当します。|
|ssrf_proxy|Server-Side Request Forgery（SSRF）攻撃を防ぐためのプロキシサーバーです。Difyのバックエンドからの外部へのリクエストを仲介し、許可されたホストへのアクセスのみを許可することでセキュリティを強化します。|
|certbot|SSL/TLS証明書を自動的に取得・更新するためのツールです。DifyのWebインターフェースやAPIエンドポイントへのHTTPSアクセスを有効にするために使用されます。|
|nginx|高性能なWebサーバーおよびリバースプロキシサーバーです。DifyのWebアプリケーションへのリクエストを処理したり、APIサーバーへのリクエストをルーティングしたり、SSL/TLS終端処理を行ったりします。|
|weaviate|オープンソースのベクトル検索エンジンです。Difyのデータソースや埋め込み表現された情報を格納し、類似検索やセマンティック検索などの機能を提供するために利用される可能性があります。|
|qdrant|オープンソースのベクトル類似性検索エンジンです。Weaviateと同様に、Difyのデータや埋め込みベクトルを格納し、高速な類似検索を実現するために利用される可能性があります。|
|pgvector|PostgreSQLの拡張機能であり、ベクトル類似性検索を可能にします。DifyがPostgreSQLをデータベースとして利用している場合、この拡張機能を使ってベクトル検索機能を実現する可能性があります。|
|pgvecto-rs|PostgreSQLのベクトル類似性検索を行うための別の拡張機能です（Rust実装）。pgvectorと同様の目的で使用される可能性があります。|
|chroma|埋め込みのためのオープンソースAIネイティブベクトルデータベースです。Difyのデータや埋め込みベクトルを格納し、簡単にベクトル検索機能を利用できるようにするために使用される可能性があります。|
|oceanbase|アリババクラウドが提供する分散型リレーショナルデータベースです。Difyのデータベースとして利用される可能性があります。|
|oracle|オラクル社が提供する商用リレーショナルデータベースです。Difyのデータベースとして利用される可能性があります。|
|etcd|分散型のキーバリューストアであり、設定情報やサービスのディスカバリーなどに利用されます。Difyの内部コンポーネントの設定管理や連携に利用される可能性があります。|
|minio|Amazon S3互換のオブジェクトストレージサーバーです。Difyが扱うファイルやアセットなどの非構造化データを保存するために利用される可能性があります。|
|milvus-standalone|オープンソースのベクトルデータベースです。大規模なベクトルデータの保存と高速な類似検索に特化しており、Difyの高度な検索機能やAI機能の実現に利用される可能性があります。|
|opensearch|Apache Luceneをベースとしたオープンソースの検索・分析エンジンです。ログ分析、全文検索、データ可視化などの機能を提供し、Difyのログ収集や検索機能の基盤として利用される可能性があります。|
|opensearch-dashboards|OpenSearchのデータを可視化するためのオープンソースのダッシュボードツールです。Difyのログやパフォーマンスデータなどを視覚的に分析するために利用される可能性があります。|
|opengauss|Huaweiが開発したオープンソースのリレーショナルデータベースです。Difyのデータベースとして利用される可能性があります。|
|myscale|MySQLをベースとしたオープンソースのデータベースです。Difyのデータベースとして利用される可能性があります。|
|elasticsearch|分散型の検索・分析エンジンです。OpenSearchと同様の目的で、Difyのログ収集、全文検索、データ分析などに利用される可能性があります。|
|kibana|Elasticsearchのデータを可視化するためのオープンソースのダッシュボードツールです。Difyのログやパフォーマンスデータなどを視覚的に分析するために利用される可能性があります。|
|unstructured|非構造化データを構造化データに変換するためのツールやライブラリを提供するサービスである可能性があります。Difyが様々な形式のドキュメントやデータを処理する際に、前処理として利用されることが考えられます。|

## Dify のインストール
[公式ドキュメント](https://docs.dify.ai/) によれば、[Dify コミュニティエディション](https://docs.dify.ai/getting-started/install-self-hosted) の導入方法は「Docker Compose でデプロイ」もしくは「ソースコードで実行」のどちらかです。
当然、「1. Docker Compose でデプロイ」を実施します。

### Docker Compose でデプロイ
* OS は Linux / macOS / Windows (with WSL2)
* CPU は 2コア以上
* メモリは 4GB 以上（macOS 10.14以降なら 8GB 以上）

上記は、[Deploy with Docker Compose](https://docs.dify.ai/getting-started/install-self-hosted/docker-compose) に記載されている前提条件です。
「**以上**」であることから、同時接続ユーザー数やアプリ/ナレッジベースの登録数が増えていけば、リソースの消費量も増えていくと考えられます。

### ① Dify ソースクローンの取得
GitHub から Dify ソースのクローンを入手します。
任意のフォルダを作成し、その中で```git clone```コマンドを実行します。
（```dify```というフォルダが作成されます）
```bash
git clone https://github.com/langgenius/dify.git
```

### ② 環境変数ファイルの設定
```dify/docker```フォルダ下に環境変数ファイルを作成し、ポート番号などのカスタマイズを実施します。

#### ②-1 環境変数ファイルの作成
サンプルファイルが損じあするので、これを```.env```にリネームします。
```bash
cd dify/docker
cp .env.example .env
```

#### ②-2 ポート番号の変更
```.env```ファイルをエディターで開き、次の２行を変更します。

```conf
■ 変更前
# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=80
EXPOSE_NGINX_SSL_PORT=443
```

```conf
■ 変更後
# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=20080
EXPOSE_NGINX_SSL_PORT=20443
```
## Dify の実行
### Docker Compose からの実行
dify/docker フォルダの上で、```docker compose up -d```を実行します。
コンテナイメージの「Pull」が実施されるので、各コンテナが「Started」になるまで３～５分ほどかかります。
```bash
$ docker compose up -d
[+] Running 80/80
 ✔ api Pulled                                         167.7s 
 ✔ nginx Pulled                                       158.6s 
 ✔ weaviate Pulled                                    103.7s 
 ✔ db Pulled                                          60.0s 
 ✔ worker Pulled                                      167.7s 
 ✔ redis Pulled                                       112.5s 
 ✔ web Pulled                                         111.6s 
 ✔ plugin_daemon Pulled                               195.2s 
 ✔ sandbox Pulled                                     38.2s 
 ✔ ssrf_proxy Pulled                                  34.4s 
[+] Running 12/12
 ✔ Network docker_ssrf_proxy_network  Created         0.0s 
 ✔ Network docker_default             Created         0.1s 
 ✔ Container docker-web-1             Started         1.8s 
 ✔ Container docker-sandbox-1         Started         1.8s 
 ✔ Container docker-weaviate-1        Started         1.9s 
 ✔ Container docker-db-1              Started         1.8s 
 ✔ Container docker-ssrf_proxy-1      Started         1.9s 
 ✔ Container docker-redis-1           Started         1.8s 
 ✔ Container docker-plugin_daemon-1   Started         1.4s 
 ✔ Container docker-worker-1          Started         1.2s 
 ✔ Container docker-api-1             Started         1.2s 
 ✔ Container docker-nginx-1           Started         1.9s 
$ 
```
この時点で、各コンテナが起動状態です。
正常動作していることを確認してみます。
```bash
$ docker compose ps
NAME                     IMAGE                                       COMMAND                   SERVICE         CREATED         STATUS                   PORTS
docker-api-1             langgenius/dify-api:1.1.3                   "/bin/bash /entrypoi…"   api             4 minutes ago   Up 4 minutes             5001/tcp
docker-db-1              postgres:15-alpine                          "docker-entrypoint.s…"   db              4 minutes ago   Up 4 minutes (healthy)   5432/tcp
docker-nginx-1           nginx:latest                                "sh -c 'cp /docker-e…"   nginx           4 minutes ago   Up 4 minutes             0.0.0.0:20080->80/tcp, [::]:20080->80/tcp, 0.0.0.0:20443->443/tcp, [::]:20443->443/tcp
docker-plugin_daemon-1   langgenius/dify-plugin-daemon:0.0.6-local   "/bin/bash -c /app/e…"   plugin_daemon   4 minutes ago   Up 4 minutes             0.0.0.0:5003->5003/tcp, [::]:5003->5003/tcp
docker-redis-1           redis:6-alpine                              "docker-entrypoint.s…"   redis           4 minutes ago   Up 4 minutes (healthy)   6379/tcp
docker-sandbox-1         langgenius/dify-sandbox:0.2.11              "/main"                   sandbox         4 minutes ago   Up 4 minutes (healthy)   
docker-ssrf_proxy-1      ubuntu/squid:latest                         "sh -c 'cp /docker-e…"   ssrf_proxy      4 minutes ago   Up 4 minutes             3128/tcp
docker-weaviate-1        semitechnologies/weaviate:1.19.0            "/bin/weaviate --hos…"   weaviate        4 minutes ago   Up 4 minutes             
docker-web-1             langgenius/dify-web:1.1.3                   "/bin/sh ./entrypoin…"   web             4 minutes ago   Up 4 minutes             3000/tcp
docker-worker-1          langgenius/dify-api:1.1.3                   "/bin/bash /entrypoi…"   worker          4 minutes ago   Up 4 minutes             5001/tcp
$
```
「STATUS」欄がすべて「Up ** minutes」です。
いずれのコンテナも 正常に動作しているようです。

### ブラウザからの接続確認
ブラウザを開き、次のURLを入力します。
　URL:　**http://{Dify Server の IPアドレス}/install**

次の画面が表示されれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/71e4f809-84ab-49ee-98e5-07b316fb3387.png)

## その他の操作
### すべての Compose リソースを完全に削除する方法
Dify に限らず、Docker Compose で作成したリソース群を完全に削除したいときは、次のコマンドを実行します。
```bash
docker-compose down --rmi all --volumes --remove-orphans
```
別名、《滅びの呪文》と言うそうです(汗)
[《滅びの呪文》Docker Composeで作ったコンテナ、イメージ、ボリューム、ネットワークを一括完全消去する便利コマンド](https://qiita.com/suin/items/19d65e191b96a0079417)

### 環境変数の修正
```dify/docker```フォルダ下の環境変数ファイル```.env```を修正した後は、次のコマンドを実行して Dify を再起動します。
```bash
docker compose down
docker compose up -d
```

### Dify の停止
```dify/docker```フォルダへ移動後、次のコマンドを実行します。
```bash
docker compose down
```

### Dify の更新
Dify を最新版に更新するときは、次のコマンドを順に実行します。
```bash
cd dify/docker
git pull origin main
docker compose down
docker compose pull
docker compose up -d
```

## 終わりに
これで Dify が動く状態までたどり着けました。
次回は初期設定を行い、アプリ作成が可能な状態にしていきます。

どの LLM を利用するのか迷っていますが、コスト面を考えて 最初は Gemini にするかもしれません。（応答も早いので、ストレスも少なそうです）