DifyセルフホストでPythonからファイルを扱う方法
こんにちは。
BtoBマーケティング領域でプロダクト開発を担当しているエンジニアです。
業務では主にGo、React、Google Cloud、AWSなどを利用しています。
社内でAI活用が進む中で、Difyを利用したいという要望があり、セルフホスティングを行いました。
AWSがDifyのセルフホスト用サンプルを公開していたため、今回はそちらを利用しました。
AWSでセルフホストを実施する記事は他にも多数存在するため、具体的な手順については本稿では割愛しますが、個人的に躓いた点や工夫した点について簡単にご紹介します。
その後に、本稿の本題であるSandBox環境におけるPython実行について述べていきます。
工夫した点
CI/CD
運用を考慮し、GitHub Actionsを用いたCI/CDパイプラインを構築しました。
シークレットの管理や、後述するDocker HubからECRへのDockerイメージ同期処理など、特定の担当者に依存しない仕組み作りを意識しました。
- mainブランチへのプルリクエスト時に
cdk diff
を実行 - mainブランチへのマージ時に
cdk deploy
を実行 - AWSへの認証にはOIDCを利用
リージョンとリソースについて
上記のAWSサンプルでは、リソースがオレゴンリージョン (us-west-2
) に作成される実装でしたが、これを東京リージョンで作成するように変更しました。
また、ドメインも自動的にRoute 53に登録される処理になっていましたが、こちらは既存の登録済みドメインを使用し、サブドメインに関する制御のみを行うようにコードを変更しました。
このあたりは、ご自身の既存リソース状況に合わせて、適切なCDKを作成すると良いでしょう。
躓いた点
Fargate Spotについて
AWSサンプルのcdk.ts
に、以下のような記述があります。
// uncomment the below options for less expensive configuration:
// isRedisMultiAz: false,
// useNatInstance: true,
// enableAuroraScalesToZero: true,
// useFargateSpot: true,
コスト削減のためにはこれらのコメントを外して有効にするよう推奨されていました。そこで、すべて有効にしてみましたが、Fargate Spot
ではうまく動作せず(そもそもデプロイ自体が安定しませんでした)、useFargateSpot: false
で使用することにしました。
また、AWSサンプルではAPIサーバーのタスク定義がcpu: 1024, memoryLimitMiB: 2048
でしたが、パフォーマンスがやや不安定(特にメモリ使用量が多い)と感じられたため、cpu: 2048, memoryLimitMiB: 4096
として運用しています。現在はこれで比較的安定して動作しています。
こちらもご自身の環境に合わせて調整してください。
Dockerイメージについて
AWSサンプルではDockerイメージをDocker HubからPullしていましたが、先日発表された未認証ユーザーに対するPull制限の影響を受けました。
そのため、基本的に利用したいDifyのDockerイメージを一度ECRに同期させ、デプロイ時にはECRからPullするように変更することをおすすめします。
幸い、AWSサンプルにはこの点を考慮したスクリプトが用意されており、非常に助かりました。
私の環境では、Dockerイメージの変更が必要になった際に、workflow_dispatch
を利用して手動でGitHub Actionsのワークフローを実行し、DockerイメージをECRに同期させる、という工夫を行いました。
Dify Plugin Daemonイメージのバージョンについて
Difyは複数のコンテナが連携して動作するマルチコンテナ環境ですが、Dify APIサーバー内で主に稼働するdify-plugin-daemon
が、取得するバージョンによって不安定な挙動を示し、初回デプロイ時に全く動作せず、原因究明に苦労しました。
AWSサンプルで当初取得していたdify-plugin-daemon
のDockerイメージタグはmain-local
でしたが、このタグはおそらく開発中でマージされた直後の変更が含まれるイメージであり、破壊的変更が含まれたバージョンを取得した場合に動作しなくなることが原因と考えられました。
しかし、この点に関するIssueがAWSサンプル側で公開されており、そちらを参考に修正しました。
現時点(2025/4/13
)では、AWSサンプル側で0.0.6-local
という安定版を取得する実装に変更されているため、おそらく上記の問題は発生しないと考えられますが、このような不安定な挙動が発生する可能性については、留意しておくと良いでしょう。
本題
無事にセルフホストは完了しましたが、運用していく中で、いくつかの課題が見つかりました。
SandBox環境について
DifyにはPythonコードを実行できるSandBox環境が用意されています。
これはDifyのコンテナに対応したもので、以下のリポジトリで公開されています。
なお、利用したいPythonパッケージをSandBoxにインストールするには、以下のpython-requirements.txt
に記述します。
Pythonでどのようなことが「できないか」?
このPythonコード実行機能は便利ですが、セキュリティ上の理由から、デフォルトで様々な操作が禁止されています。例えば、ディレクトリの参照、ファイルの保存、外部ネットワークへのアクセスなどです。もともとDifyはクラウドサービスとして提供されているため、セキュリティ面を考慮した設計になっていると考えられます。
上記のコードを見るとわかるとおり、例えばルートディレクトリが特定の場所に制限されていたり、デフォルトで多くのシステムコールが禁止されていたりします。
SandBox環境でファイルを作成しダウンロードさせたい
このような制限の中で、Pythonで任意のファイルを作成し、それをダウンロードさせたいという要望がありました。これを実現するには、以下の二点を満たす必要がありました。
- SandBox内のシステムコール制限を緩和する
- ファイルをダウンロードさせる仕組みを検討する
SandBox内のシステムコール制限を緩和する
これは比較的簡単に行えます。
AWSサンプルではallowAnySyscalls
というプロパティが用意されているため、これをtrue
に設定するだけです。
SandBoxに対応する環境変数が用意されており、許可するシステムコールをSandBoxに渡す実装となっています。ただし、このプロパティを許可すると、かなり広範囲のシステムコールが許可されるため、調整が必要な場合は下記の部分を修正する必要があります。
ファイルをダウンロードさせる仕組みを検討する
次に問題となったのは、SandBox内で作成したファイルをどうやってダウンロードさせるか、という点でした。例えば、以下のような方法が考えられます。
- SandBox内にファイルを保存し、そこからダウンロードさせる
- S3などの外部ストレージへ一度保存し、そこからダウンロードさせる
一つ目の方法ですが、結論から言うと、この方法はうまくいきませんでした。
例えばPythonのtempfileモジュールでは、おそらく/tmp
ディレクトリへのアクセス制限が原因で失敗しました。また、ioモジュールによるメモリへのデータ保存は成功しましたが、その後、データをダウンロードする方法が見つからず断念しました。そもそも、SandBox内にファイルを保存できたとしても、ダウンロードする方法がわからなかったため、この方法は採用しませんでした。(また、ファイルの削除忘れによるストレージ容量の圧迫も懸念されました。)
最終的に二つ目の方法で成功しました。
具体的には、以下の手順で実装しました。
- IAMユーザーを作成し、boto3を使用して明示的にアクセスする
- S3に保存したファイルに一時的な参照URLを付与してダウンロードを実行する
boto3は、デフォルトではECSにアタッチされたIAMロールの権限を使用しようとしますが、おそらくSandBoxのアクセス制限により、該当のクレデンシャルファイルにアクセスできず、ECSにどのようなIAM Roleを付与しても403エラーが発生しました。
したがって、boto3のパラメータにIAMユーザーのアクセスキー情報などを渡す必要があります。
セキュリティの観点からは推奨される方法ではありませんが、Difyの各ワークフローにはシークレットを登録できる機能があるため、できるだけハードコーディングを避け、運用するようにしています。
ここまで実装できれば、あとは簡単です。一時的なURLを発行し、最終的にそれをDifyの出力結果に含めるだけです。
また、S3へアクセスできたということは、そこからイベントを発火させて別のプロセスに連携することも可能になるため、応用の幅が広がると考えています。
最後に
Difyのセルフホスティングは、いくつか躓いた点もありましたが、比較的スムーズに運用を開始できたという印象です。
その他、Bedrockのナレッジベースへのアクセス設定はサンプルに含まれていますが、Bedrock自体のセットアップはサンプルに含まれていないため、その部分は自身で行う必要がありそうです。
Difyは今後も様々なアップデートが予定されているため、任意のタイミングでバージョンアップも検討しています。(特に、アプリケーションの権限管理機能やMCPの導入に期待しています。)
Discussion