自分だけのDify-Sandboxを構築する：Dockerfile完全解説

近年のソフトウェア開発において、セキュリティは最重要課題の一つです。特に、外部からのコード実行が必要となるオンラインジャッジシステムやコード実行環境では、悪意のあるコードからシステムを守るための対策が必須となります。

そんな課題を解決するのが**Dify-Sandbox**です。Dify-Sandboxは、信頼できないコードを安全な分離環境で実行するためのオープンソースライブラリであり、システムコールの制限やリソース制限など、強固なセキュリティ機能を提供します。

本記事では、Dify-Sandboxをより深く理解し、自分の環境に合わせてカスタマイズできるように、Dockerfileを用いたDify-Sandboxの構築方法をステップバイステップで解説します。

---

こちらの記事もおすすめ

https://hamaruki.com/dify-sandbox-secure-code-execution/

https://hamaruki.com/difys-docker-compose-upgrade-instructions/


### なぜDify-Sandboxを自分でビルドするのか？

公式イメージを利用する手軽さの一方で、独自のニーズに合わせたカスタマイズが必要となるケースも少なくありません。例えば、

* 特定のバージョンのGo言語やPython環境を使用したい
* 特定のライブラリを追加したい
* セキュリティ設定をより厳密にカスタマイズしたい

このような場合、Dockerfileを用いたDify-Sandboxのセルフビルドが有効です。

### DockerfileによるDify-Sandbox構築

それでは、実際にDockerfileを作成し、Dify-Sandboxをビルドしてみましょう。

#### Dockerfileの作成

まず、以下の内容を記述した `Dockerfile` を作成します。

```dockerfile
# ビルドステージ
FROM python:3.10-slim AS builder

# 必要な依存関係をインストール（sudoを含む）
RUN apt-get update && apt-get install -y \
    sudo \
    pkg-config \
    libseccomp-dev \
    wget \
    xz-utils \
    gcc \
    g++ \
    git \
    make \
    cmake \
    curl

# Go言語のインストール
RUN wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz && \
    tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz && \
    rm go1.21.6.linux-amd64.tar.gz

# 環境変数の設定
ENV PATH="/usr/local/go/bin:${PATH}"

# Dify-Sandboxのソースコードを取得
WORKDIR /tmp
RUN git clone https://github.com/langgenius/dify-sandbox.git

# Dify-Sandboxのビルド
WORKDIR /tmp/dify-sandbox
# install.shとbuild_amd64.shを実行
RUN ./install.sh && ./build/build_amd64.sh # amd64の場合
# ARM64の場合は以下を使用
# RUN ./install.sh && ./build/build_arm64.sh

# 実行ステージ
FROM python:3.10-slim

# ビルドしたDify-Sandboxバイナリをビルドステージからコピー
COPY --from=builder /tmp/dify-sandbox/main /main

# 設定ファイルと依存関係をコピー
COPY conf/config.yaml /conf/config.yaml
COPY dependencies/python-requirements.txt /dependencies/python-requirements.txt

# Pythonの依存関係をインストール
RUN pip3 install -r /dependencies/python-requirements.txt

# Node.jsとcurlをインストール
RUN apt-get update && apt-get install -y wget xz-utils curl && \
    wget -O /opt/node-v20.11.1-linux-x64.tar.xz https://npmmirror.com/mirrors/node/v20.11.1/node-v20.11.1-linux-x64.tar.xz && \
    tar -xvf /opt/node-v20.11.1-linux-x64.tar.xz -C /opt && \
    ln -s /opt/node-v20.11.1-linux-x64/bin/node /usr/local/bin/node && \
    rm -f /opt/node-v20.11.1-linux-x64.tar.xz && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

# 実行権限を付与
RUN chmod +x /main

# コンテナ起動コマンド
ENTRYPOINT ["/main"]
```

#### Docker イメージのビルド

Dockerfile を作成したら、以下のコマンドを実行してDockerイメージをビルドします。

```bash
docker build -t my-dify-sandbox .
```

#### Docker コンテナの実行

ビルドが完了したら、以下のコマンドでコンテナを実行します。

```bash
docker run -p 8194:8194 my-dify-sandbox
```

これで、Dify-Sandboxが起動し、ポート8194でアクセスできるようになります。

### Dockerfileの詳細解説

#### ビルドステージ

```dockerfile
# ビルドステージ
FROM python:3.10-slim AS builder
```

* `FROM python:3.10-slim AS builder`: ベースイメージとして `python:3.10-slim` を使用し、ステージ名を `builder` としています。
* ビルドステージでは、Dify-Sandboxのビルドに必要な環境を構築します。


#### 依存関係のインストール

```dockerfile
# 必要な依存関係をインストール（sudoを含む）
RUN apt-get update && apt-get install -y \
    sudo \
    pkg-config \
    libseccomp-dev \
    wget \
    xz-utils \
    gcc \
    g++ \
    git \
    make \
    cmake \
    curl
```

* `RUN apt-get update && apt-get install -y ...`:  Dify-Sandboxのビルドに必要な依存関係をインストールします。
* `sudo`, `pkg-config`, `libseccomp-dev` など、ビルドに必要なツールやライブラリをインストールしています。

#### Go言語のインストール

```dockerfile
# Go言語のインストール
RUN wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz && \
    tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz && \
    rm go1.21.6.linux-amd64.tar.gz

# 環境変数の設定
ENV PATH="/usr/local/go/bin:${PATH}"
```

* `RUN wget ...`: 指定したURLからGo言語のアーカイブをダウンロードします。
* `tar -C /usr/local -xzf ...`: ダウンロードしたアーカイブを `/usr/local` に展開します。
* `rm ...`: アーカイブファイルを削除します。
* `ENV PATH="/usr/local/go/bin:${PATH}"`: Go言語へのパスを通すために環境変数 `PATH` を設定します。

#### Dify-Sandboxのソースコード取得とビルド

```dockerfile
# Dify-Sandboxのソースコードを取得
WORKDIR /tmp
RUN git clone https://github.com/langgenius/dify-sandbox.git

# Dify-Sandboxのビルド
WORKDIR /tmp/dify-sandbox
# install.shとbuild_amd64.shを実行
RUN ./install.sh && ./build/build_amd64.sh # amd64の場合
# ARM64の場合は以下を使用
# RUN ./install.sh && ./build/build_arm64.sh
```

* `WORKDIR /tmp`: 作業ディレクトリを `/tmp` に変更します。
* `RUN git clone ...`: Dify-SandboxのソースコードをGitHubリポジトリからクローンします。
* `WORKDIR /tmp/dify-sandbox`:  作業ディレクトリをクローンしたDify-Sandboxのディレクトリに変更します。
* `RUN ./install.sh && ./build/build_amd64.sh`:  Dify-Sandboxのインストールスクリプトとビルドスクリプトを実行します。 `build_amd64.sh` はamd64アーキテクチャ用のビルドスクリプトです。ARM64アーキテクチャの場合は `build_arm64.sh` を使用します。

#### 実行ステージ

```dockerfile
# 実行ステージ
FROM python:3.10-slim
```

* `FROM python:3.10-slim`: 実行環境のベースイメージとして `python:3.10-slim` を使用します。

#### ビルド済みバイナリと設定ファイルのコピー

```dockerfile
# ビルドしたDify-Sandboxバイナリをビルドステージからコピー
COPY --from=builder /tmp/dify-sandbox/main /main

# 設定ファイルと依存関係をコピー
COPY conf/config.yaml /conf/config.yaml
COPY dependencies/python-requirements.txt /dependencies/python-requirements.txt
```

* `COPY --from=builder /tmp/dify-sandbox/main /main`: ビルドステージでビルドした `main` バイナリを実行ステージの `/main` にコピーします。
* `COPY conf/config.yaml /conf/config.yaml`: Dify-Sandboxの設定ファイルをコピーします。
* `COPY dependencies/python-requirements.txt /dependencies/python-requirements.txt`: Pythonの依存関係が記述されたファイルをコピーします。

#### Python、Node.js、curl のインストール

```dockerfile
# Pythonの依存関係をインストール
RUN pip3 install -r /dependencies/python-requirements.txt

# Node.jsとcurlをインストール
RUN apt-get update && apt-get install -y wget xz-utils curl && \
    wget -O /opt/node-v20.11.1-linux-x64.tar.xz https://npmmirror.com/mirrors/node/v20.11.1/node-v20.11.1-linux-x64.tar.xz && \
    tar -xvf /opt/node-v20.11.1-linux-x64.tar.xz -C /opt && \
    ln -s /opt/node-v20.11.1-linux-x64/bin/node /usr/local/bin/node && \
    rm -f /opt/node-v20.11.1-linux-x64.tar.xz && \
    apt-get clean && rm -rf /var/lib/apt/lists/*
```

* `RUN pip3 install -r ...`: Pythonの依存関係をインストールします。
* `RUN apt-get update && apt-get install -y ...`: Node.jsとcurlをインストールします。

#### 実行権限の付与と起動コマンド

```dockerfile
# 実行権限を付与
RUN chmod +x /main

# コンテナ起動コマンド
ENTRYPOINT ["/main"]
```

* `RUN chmod +x /main`:  `main` バイナリに実行権限を付与します。
* `ENTRYPOINT ["/main"]`: コンテナ起動時に `/main` バイナリを実行するよう設定します。


<blockquote class="twitter-tweet" data-media-max-width="800"><p lang="ja" dir="ltr">Dify-SandboxでセルフビルドできるようなDockerfileとDocker-composeを作成しました！<br>これで改造しまくれる！ <a href="https://t.co/z6f1Tag8Ta">https://t.co/z6f1Tag8Ta</a> <a href="https://t.co/B3mDTkEKcG">pic.twitter.com/B3mDTkEKcG</a></p>&mdash; Maki@Sunwood AI Labs. (@hAru_mAki_ch) <a href="https://twitter.com/hAru_mAki_ch/status/1812043651142549703?ref_src=twsrc%5Etfw">July 13, 2024</a></blockquote>


### まとめ

本記事では、Dockerfileを用いてDify-Sandboxをビルドする方法を解説しました。

Dockerfileを用いることで、Dify-Sandboxを自身の環境に合わせてカスタマイズし、よりセキュアなコード実行環境を構築することが可能になります。

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>