生成AIアプリ開発ツールDifyをAWS EKSに導入してみた

2024/12/17に公開2

はじめに

この記事は「Atrae Engineers Advent Calendar 2024」の17日目の記事です。
前回はTaichi Nakamuraによる「「適切な英語の選択」が認知負荷の低いシステムを作る」でした。

改めまして、株式会社アトラエで、組織力向上プラットフォーム「Wevox(ウィボックス)」のSREをしている@akiです。主にK8sを中心としたインフラ領域を専門にエンジニアリングをしていて、直近ではKubernetesのアプデと格闘しています。

概要

今回、生成AIアプリケーションの開発をノーコードで実現するプラットフォーム「Dify」を、AWSのマネージドKubernetes(以降、K8s)サービスであるEKS上にHelmを利用せずに構築したので、ご紹介したいと思います。ちなみに調査を開始した2024年8月時点では、dify-kubernetesに関する情報が乏しく、特に以下の点で課題を感じましたし、苦労しました。

  • 公式ドキュメントの不足
    Difyの公式ドキュメントには、kubernetes環境への導入に関する具体的なガイドがほとんど記載されていませんでした。
  • 事例の少なさ
    実際にdify-kubernetesを導入している事例が少なく、コミュニティ内での共有知見がほとんど見つかりませんでした。
  • 設定内容の不透明さ
    Helm Chartsを使用しない場合の詳細な設定方法や、環境ごとの注意点についての記述がほぼなく、自力で試行錯誤する必要がありました。

結果的に、手探りで設定を確立しましたが、構築過程で得られた知見をこの記事で共有しようと思います。同じ課題に直面している方々にとって、この記事が少しでも助けになれば幸いです。

Difyとは何か?

https://docs.dify.ai/ja-jp

Difyの主な機能と特徴

Difyは、ノーコードで生成AIアプリケーションを開発できるオープンソースのプラットフォームで、プログラミングの知識がなくても、ドラッグ&ドロップでAIアプリケーションを構築可能なのが特徴です。
また、多様なLLMとの連携ができたり、RAGという検索拡張機能と呼ばれる仕組みを使って、社内ドキュメントや指定したWebページ、Notionを参照し、LLMに回答させることができる技術で、DifyにはRAGエンジンが標準搭載されています。とても便利で、ここ最近Difyという文字をネット上でもよく目にしますが、AIアプリケーションを簡単に作りたい方には、オススメのプラットフォームです。
詳細が知りたい方は、公式ドキュメントを参照してください。
https://docs.dify.ai/ja-jp

Difyのコラムにも分かりやすく解説されていますので、こちらも参考にしてみてください。
https://dify.tdse.jp/post_column/191/

DifyをAWS EKSで構築する手順

前提

  • AWS EKSクラスターの構築については、一切触れていません。また、AWS, K8sに関する基本的な知識があることを前提に専門的な用語の解説なども省略して書いている点、ご了承ください。
  • コマンドは下記のように表記しています。
    kubectl     = k
    --namespace = -n
    

マニフェストの定義

こちらオープンソースで提供されているdify-kubernetesをHelmを利用せずにK8s上で動作するようyamlファイルをベースに自前の環境で動かすために必要な設定を追加してapplyするという流れです。
https://github.com/Winson-030/dify-kubernetes/tree/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify
※サンプルコードは上記リポジトリの現時点のコミットを元に解説していますので、最新を参照する場合はご注意ください。

ディレクトリ構成

早速ですが、今回試しにデプロイしたDifyのディレクトリ構成は以下の通りです。
※PostgreSQLはAWS RDSを利用して構築したため、postgres.yamlは存在しません。

./
├── config
│   └── sealed-secret.yaml
├── api.yaml
├── kustomization.yaml
├── nginx.yaml
├── redis.yaml
├── sandbox.yaml
├── weaviate.yaml
├── web.yaml
├── worker.yaml
└── README.md

概略図

ingressの設定

  • host:
    • こちらは、Route53などで好きなhostを定義したものと紐付けてあげると良さそうです。
  • port.number
    • デフォルトでは定義されていますが、マルチポートのサービスなどを利用している場合は、port.name: httpなど定義すると良いと思います。

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/network/ingress.yaml#L7-L19

nginxの設定

  • proxy_pass
    • http://api:5001;は、http://[apiのserviceName]:5001/apiとなるように設定すると良さそうで、http://dify-api:5001/apiと定義しました。/apiはapiの実装を見るとここに流してあげると良さそうというのが見て取れます。その他の設定も同様にどこに通信を流していそうか確認して定義すると良いと思いますので、その他は割愛します。

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/network/nginx.yaml#L42-L43

apiの設定

  • spec.containers.image
    • difyのリリースノートを参考にimageを指定してください。Difyは開発が活発なので、どんどん新しい機能が出てきています。こまめにチェックして、最新を追いかけていきたいですね。

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/api/api.yaml#L22-L27

  • spec.containers.env
    • SECRET_KEYは、yamlに直接定義するのはセキュリティの観点から推奨されませんので、sealed-secretなどを利用して、環境変数を呼び出すという設定にするのが良さそうです。その他のenvに関してもセキュリティの観点を考慮して設定すると良さそうです。

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/api/api.yaml#L28-L34

# example
- name: SECRET_KEY
  valueFrom:
    secretKeyRef:
      name: dify-credentials
      key: sk-xxxx
  • DBは今回、AWSのRDSでDBを作成しましたので、そちらの情報を定義しています。

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/api/api.yaml#L49-L70

sandboxの設定

  • spec.containers.env
    • API_KEYを定義して、api.yamlのCODE_EXECUTION_API_KEYに同様の値をセット
    • HTTP_PROXYHTTPS_PROXYはProxyを使わない場合は、不要な設定なので、コメントアウトしておいても問題ありません。

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/middleware/sandbox.yaml#L23-L28

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/middleware/sandbox.yaml#L38-L41

weaviateの設定

  • spec.containers.env
    • AUTHENTICATION_APIKEY_ALLOWED_KEYSを定義して、api.yamlのWEAVIATE_API_KEYに同様の値をセット

https://github.com/Winson-030/dify-kubernetes/blob/84c9fadc0bf14b8c0ce97f340b3ccbd324a31029/dify/database/weaviate.yaml#L83-L84

workerの設定

  • resourcesは私が導入した際には設定されていましたが、現在は取り除かれているようでした。実際の使用状況をモニタリングしながら、設定するか否か判断して見ると良さそうです。

redis、webの設定

hostを独自のものにしていなければ、基本的にデフォルトのままで良さそうです。

デプロイ

ここまで設定して Let's apply!

成功していれば、初期のログイン画面が現れるので、設定できるようになります。
ちなみに、admin権限は複数設定できますが、ownerは一人しか設定できません。そして、ownerのアカウントは現状UIから変更することはできないので、ご注意ください。

構築後に直面した課題とその解決策

特定のパスにアクセスすると500エラーが発生する

  • 具体例

    $ k logs -f dify-api -n dify
    # ログはイメージで、更新ドキュメントから抜粋しています
    
    ERROR:root:Unknown Error in completion
    Traceback (most recent call last):
      File "/www/wwwroot/dify/dify/api/libs/rsa.py", line 45, in decrypt
        private_key = storage.load(filepath)
      File "/www/wwwroot/dify/dify/api/extensions/ext_storage.py", line 65, in load
        raise FileNotFoundError("File not found")
    FileNotFoundError: File not found
    
  • 対策

    • 下記の公式ドキュメントに則ってコマンド実行すると解決しました

      ref: https://docs.dify.ai/ja-jp/learn-more/faq/install-faq#id-2-rkarurogudefairugatsukarimasentoiuerwosuruha
      このエラーは、展開方法の変更や api/storage/privkeys ディレクトリの削除によって発生する可能性があります。このファイルは大規模モデルキーの暗号化に使用されるため、損失は不可逆です。次のコマンドを使用して暗号化キーペアをリセットできます

    $ k exec -it dify-api -- flask reset-encrypt-key-pair
    

まとめ

技術に関するまとめではありませんが、今回のDifyの構築を通じて、私自身の経験と成長について振り返って締めたいと思います。

  • 新しい技術への挑戦
    dify-kubernetesの導入にあたり、公式にサポートされていない設定方法を模索し、自力で環境構築を行いました。これにより、新しい技術に対応するための調査力や応用力が少しは、磨かれたと思います。
  • トラブルシューティング力
    環境変数の設定ミスなど、複数のトラブルに直面しましたが、これらを一つひとつ解決する中で問題解決能力が向上したと感じます。
  • 自信
    情報が少ない中でも自走してタスクを完遂できたことで、自分自身のエンジニアリングスキルに対する自信がつき、今後の新しい挑戦への意欲も高まったと感じます。この経験が、この後にK8sのアプデに挑戦した際に大きな支えになったと感じます。

最後に

Difyの開発は活発で、日々進化していますので、自前で管理する場合は常に最新のバージョンに気を配りながら、アップデートし続けることが競争力の面でも重要になりそうなので、メンテコストをいかに下げるかが今後の課題と感じています。

今回の構築を通じて、ドキュメントやGitHubのREADMEに頼らず、情報が乏しい中で環境をゼロから動かす経験を得られました。このタスクを一人でやり遂げたことで、自分の自走能力が大きく成長し、エンジニアとしての自信も深まりました。また、こうした挑戦の場を任せていただける環境に心から感謝しています。

最後までお読みいただき、ありがとうございました。

引き続き Atrae Engineers Advent Calendar 2024 をお楽しみください。

参考文献、関連リンク

Dify公式ドキュメント: 言わずもがな、Difyの概要や使用方法について詳しく解説されています。
https://docs.dify.ai/

インフラ視点でDifyのアーキテクチャを理解する(v0.13.1): Difyのアーキテクチャをインフラの観点から解説しています。
https://mazyu36.hatenablog.com/entry/2024/12/05/214145

Amazon公式(中国語):中国語ですが、Amazon EKS上での高可用性Difyのデプロイ方法を解説しています。
https://aws.amazon.com/cn/blogs/china/deploying-high-availability-dify-based-on-amazon-eks/

Difyは自前の環境で実行していますので、不具合が起きた際は公式の ローカルデプロイに関するFAQ を参考にすると良さそうです。
https://docs.dify.ai/ja-jp/learn-more/faq/install-faq

おまけ

Difyに関する最新情報やリリース情報はこちらからキャッチしておくと良さそうです。
https://dify.ai/blog

Discussion

ピン留めされたアイテム
Sherry MTSherry MT

初めまして。こんにちは。

突然のメッセージ失礼いたします。

私はDify.ai チームでございます。
Zennにて貴殿の記事を拝見し、大変興味を持ちました。

今回は、貴記事をDify公式文書に転載させていただきたく、ご連絡いたしました。
貴方のXアカウントではプライベートメッセージを送信することができないため、可能であれば直接ご連絡いただけますでしょうか。Zennアカウントに直接ご連絡いただくか、もしくはDify.AI Japan にDMを送信していただくことも可能です。

Dify.ai に対する愛とサポートに感謝いたします。お忙しい中恐縮ですが、ご返答をお待ちしております。

aki366aki366

ご連絡いただきありがとうございます。
Dify.ai チームの皆様に興味を持っていただけたこと、大変光栄です。

XでSherry_Nana@DifyLearningDify.AI Japanをフォローさせて頂きました。私の方からDMお送りすることが出来ないようでしたので、恐れ入りますがDM送って頂けますと幸いです。

私のアカウントはこちらになります。
@aki