【Windows 11】Gemini CLIのサンドボックス機能をDockerで動かす方法

Gemini CLIは、Googleが提供するAIコマンドラインツールで、自然言語からPythonなどのコードを生成・実行できる強力な機能を備えています。しかし、ローカル環境で直接コードを実行する場合、ファイルアクセスやネットワーク通信などのリスクが伴います。

そこで登場するのが「サンドボックスモード」です。このモードでは、生成されたコードを安全に隔離された環境で実行できるようになっており、内部的にはDockerコンテナを利用しています。

本記事では、Windows 11環境でDocker Desktopを使ってGemini CLIのサンドボックス機能を有効化し、Pythonコードを安全に実行する方法について詳しく解説します。実際の動作確認や制限事項、トラブルシュートのポイントも含めて、実践的な内容をお届けします。

前提条件

以下の環境を想定しています

項目内容
OSWindows 11
必要ソフトDocker Desktop, Gemini CLI

Gemini CLIのインストールは以下を参考にしてください。

Gemini CLI をWindowsで使ってみた!
本記事では、Windows 環境で Gemini CLI を使ってみた体験をベースに、インストール方法から実行例までを紹介していきます。Node.jsをインストールしてある状態なら簡単にインストールできます。あと必要なのはGoogleアカウ...

Docker Desktopのインストールは以下を参考にしてください。

【Docker】Windows11でプログラミング環境構築(Python、Django、Vue)
パソコン買ったのでプログラミング環境を整えました。その様子です。Python、Django、Vueの環境を設定していきます。Docker導入でハマった点と解決策をご紹介します。Dockerやubuntu使うの今回が初めての私がネットで調べ試...

動作確認コマンド

docker --version
gemini --version

どちらもバージョンが表示されればOKです。

サンドボックスとは?

Gemini CLIのサンドボックス機能(-s オプション)は、生成されたコードをローカル環境から隔離して実行します。
内部的には、Gemini CLIが自動的にDockerコンテナを起動して、その中でコードを実行します。

Dockerコンテナとは?
Linuxベースの軽量な仮想環境で、ホストOS(たとえばWindows)とは隔離された形でアプリケーションを実行できます。コンテナ内ではLinuxのユーザー空間が動作しており、まるで独立したOSのように振る舞いますが、実際にはホストのカーネルを共有しています。

このとき:

  • ホスト(パソコン)のファイルシステムは安全(ワークスペース以外はマウントされない)
  • ネットワークアクセスは制限される
  • 実行はコンテナ内で完結する

サンドボックスを実行してみる

先にDocker Desktopを立ち上げておく必要があります。
ターミナル(PowerShell または CMD)で次を実行します

gemini -s

Docker Desktopを見るとsandbox-0.12.0-0というコンテナが追加されているのが確認できます。

サンドボックスの仕組みを確認する

dockerコマンドを実行するターミナルをもう1個立ち上げます。(1つはGeminiCLIが立ち上がっている)

コンテナを確認

コンテナの状況をdocker psコマンドで確認しています。

docker ps
表示結果
CONTAINER ID   IMAGE                                                         COMMAND                   CREATED         STATUS         PORTS     NAMES
94aca30665dd   us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.12.0   "docker-entrypoint.s…"   6 minutes ago   Up 6 minutes             sandbox-0.12.0-0

Docker Desktopで確認したものと同じです。

コンテナの中を見る

コンテナの中に入ります。以下コマンドのコンテナIDは上記のCONTAINER IDを入れてください。上記の場合94aca30665dd。gemini -sを行うたびにコンテナが新しく作られるので毎回、異なります。

docker exec -it コンテナID /bin/bash
結果
node@sandbox-0:/c/Users/user/gemini_cli/geminiCLI_sandbox$ 
パソコンでgemini -sを実行したところがワークスペースになります。
上記ではc/Users/user/gemini_cli/geminiCLI_sandbox。
パソコン側で、このディレクトリにディレクトリやファイルを追加するとコンテナの中にもバインドマウントされます。

補足;
バインドマウントは、ホストマシン(Dockerが動いているPC)上の特定のディレクトリと、コンテナ内の特定のディレクトリを直接リンクさせます

試しに、パソコンのワークスペースにtest.txtファイルを作ります。
その後、コンテナのターミナルでls(ディレクトリの内容を確認するコマンド)
ls
結果
text.txt
コンテナの中にマウントされていることが分かります。

コンテナの情報を見る

コンテナに何がインストールされているかを見てみます。方法は以下コマンドによりコンテナの情報をファイルに入れ、そのファイルをChatGptに送って聞きました。一部、ChatGptの回答と実際が違ったので修正しました。(ChatGptの回答ではPythonは入ってないと言っていたが、実際に確認すると入っている)

docker inspect コンテナID > inspect_output.json

ChatGptの回答
この inspect_output.json から、あなたの Gemini CLI サンドボックス・コンテナ の中身を整理すると次のようになります👇

コンテナの基本情報

項目内容
コンテナ名sandbox-0.12.0-0
イメージus-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.12.0
ベースOSLinux (Debian/Node系)
ユーザーnode
Node.js バージョンv20.19.5
Yarn バージョン1.22.22
Gemini CLI バージョン0.12.0
PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/share/npm-global/bin
WorkingDir/c/Users/user/gemini_cli/geminiCLI_sandbox
このディレクトリはgemini -sを実行したディレクトリです。

インストールされている主なソフトウェア

コンテナ環境変数・PATHなどから判断すると:

種別バージョン / 備考
Node.jsv20.19.5(公式 Node ベースイメージ由来)
npmNode.js に同梱(20系は v10 以上)
Yarn1.22.22
Gemini CLI0.12.0gemini -s により起動)
bash/bin/bash(Entrypoint で使用)
Pythonコンテナの中に入って
python3 –versionで確認したらpython 3.11.2と出た
curl / wgetコンテナの中に入って
curl –versionで確認したら
curl 7.88.1 (x86_64-pc-linux-gnu)と出た
Gitコンテナの中に入って
git –versionで確認したらgit version 2.39.5と出た

ホストとのマウント共有

この構成ではホストのフォルダが明示的にバインドマウントされています:
inspect_output.jsonから抜粋

        "HostConfig": {
            "Binds": [
                "C:\\Users\\user\\gemini_cli\\geminiCLI_sandbox:/c/Users/user/gemini_cli/geminiCLI_sandbox",
                "C:\\Users\\user\\.gemini:/home/node/.gemini",
                "C:\\Users\\user\\.gemini:/c/Users/user/.gemini",
                "C:\\Users\\user\\AppData\\Local\\Temp:/c/Users/user/AppData/Local/Temp"
            ],
設定の意味
例:
"C:\\Users\\user\\gemini_cli\\geminiCLI_sandbox:/c/Users/user/gemini_cli/geminiCLI_sandbox",
ホストのC:\\Users\\user\\gemini_cli\\geminiCLI_sandbox
コンテナの/c/Users/user/gemini_cli/geminiCLI_sandbox
が共有されている(同じ場所)になるので、どちらかで読み書きすると反映される。

Pythonコード実験

Pythonコードを作って実験してみます。
プロンプト:
“このサイトhttps://kikuichige.com/index.htmlのh2タグを抽出するPythonコードを書いて”
以下にコードを載せてありますが、このコードはサンドボックスなしでGeminiCLIを立ち上げて、完成させました。サンドボックスありだと以下に記述しますが、追加のPythonライブラリが使えずGeminiCLIがPythonコードの実行、確認、修正できなかったためです。


import sys
import requests
from bs4 import BeautifulSoup

def extract_h2_tags(url, output_file=None):
    try:
        response = requests.get(url)
        response.raise_for_status()  # Raise an exception for HTTP errors
        response.encoding = 'utf-8'  # Explicitly set encoding to UTF-8
        soup = BeautifulSoup(response.text, 'html.parser')
        h2_tags = soup.find_all('h2')

        if output_file:
            with open(output_file, 'w', encoding='utf-8') as f:
                for h2 in h2_tags:
                    f.write(h2.get_text(strip=True) + '\n')
        else:
            for h2 in h2_tags:
                print(h2.get_text(strip=True))
    except requests.exceptions.RequestException as e:
        if output_file:
            with open(output_file, 'a', encoding='utf-8') as f:
                f.write(f"Error fetching URL: {e}\n")
        else:
            print(f"Error fetching URL: {e}")
    except Exception as e:
        if output_file:
            with open(output_file, 'a', encoding='utf-8') as f:
                f.write(f"An unexpected error occurred: {e}\n")
        else:
            print(f"An unexpected error occurred: {e}")

if __name__ == "__main__":
    url = "https://kikuichige.com/index.html"
    output_filename = "output.txt"
    extract_h2_tags(url, output_filename)

このコード(extract_h2.py)を実行してもらいます。
プロンプト:extract_h2.pyを実行して
Sandboxありでも、実行許可を求めてきます。(サンドボックスなしでも、この機能があるので、ある程度セキュリティは確保されていると思います。)

│ ?  Shell python3 extract_h2.py (Executing the extract_h2.py script using python3,…   
│   python3 extract_h2.py                                                              │ Allow execution of: 'python3'?                                                       │ ● 1. Yes, allow once                                                                 │   2. Yes, allow always ...                                                           │   3. No, suggest changes (esc)   

extract_h2.pyで使っているライブラリrequestsが標準で入っていないため、実行するにはrequestsを入れる必要があります。そこでvenvを使って、仮想環境を立ち上げ、そこに入れることにしたが・・・

プロンプト:venvを使って

✦ 了解しました。venv を使用します。

✓  Shell python3 -m venv venv (Create a virtual environment named 'venv'.)                     │    The virtual environment was not created successfully because ensurepip is not               │    available.  On Debian/Ubuntu systems, you need to install the python3-venv                        
│    package using the following command.                                                        │      
│        apt install python3.11-venv                                                             │    You may need to use sudo with that command.  After installing the python3-venv              │    package, recreate your virtual environment.                                                 │    Failing command: /c/Users/user/gemini_cli/geminiCLI_sandbox/venv/bin/python3 

コンテナの中のPythonにはvenvがないのでaptでインストールするように言われました。
ということでコンテナの中に入ってsudo付で実行したが、以下エラー
補足:sudoを使うとroot権限でコマンドを実行できる

sudo apt install python3.11-venv
このコンピューターでは Sudo が無効になっています。

uvもGeminiCLIのほうで実行してと頼んだが、うまく動かなかった。pipもだめだった。(ただし、uvはインストール先をユーザー領域に指定すればうまくいった。後述)

Shell python3 -m pip install requests beautifulsoup4 (Installing 'requests' and … │    
/usr/bin/python3: No module named pip 

原因調査

コンテナの中に入ってsudoなしでaptをアップデートするコマンドを試した。
以下実行でエラー 
apt update 
Reading package lists... Done 
E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied)

このエラーは、Gemini CLI のサンドボックスが意図的にパッケージ管理系の書き込みを禁止しているために起きています。

権限の確認(現在のユーザー名、現在のユーザーのID、/var/lib/apt/lists ディレクトリの詳細情報(パーミッション、所有者など))
whoami                                                                 
id                                                                                
ls -ld /var/lib/apt/lists                                                         

結果
node                                                                                 
uid=1000(node) gid=1000(node) groups=1000(node)                                                                                      drwxr-xr-x 1 root root 4096 Nov  4 23:34 /var/lib/apt/lists 

現在のユーザー node は rootではない 一般ユーザー。/var/lib/apt/lists は root所有のディレクトリ であり、node ユーザーには書き込み権限がありません。

エラーの原因の本質

E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied)

これは Ubuntu/Debian ベースのコンテナで、
apt update/var/lib/apt/lists/partial にキャッシュを書き込もうとして権限がないために失敗しています。

Gemini CLI のサンドボックス(us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.12.0)は:

この設定項目は、Dockerコンテナ(特にGemini CLIのサンドボックス)のセキュリティと制限の構造を示しています。それぞれの項目が何を意味し、どんな影響があるのかを詳しく解説します。

設定項目の意味と解説

設定項目状態解説
ユーザーnode(rootではない)コンテナ内の実行ユーザーが root ではなく、一般ユーザー node。これにより、システム領域への書き込みや特権操作が制限される。
Privilegedfalseコンテナは「特権モード」で動いていない。つまり、ホストのカーネル機能(デバイスアクセスやカーネルモジュール操作など)にはアクセスできない。
ReadonlyRootfsfalse(見た目はRWだが、実際には制限あり)コンテナのルートファイルシステムは読み書き可能に見えるが、実際には重要な領域(例:/var/lib/aptなど)への書き込みが制限されている。これはセキュリティのため。
/proc, /sys の一部Masked / ReadonlyLinuxのシステム情報を提供する仮想ファイルシステム /proc/sys の一部が隠されている(masked)か読み取り専用になっている。これにより、ホストやコンテナの内部構造を覗いたり操作したりすることができない。

🧠 これらの設定が意味すること

  • コンテナ内で apt installpip install などのシステムレベルの変更はできない
  • sudosu などの権限昇格コマンドは使えない
  • /proc/sys を通じたホスト情報の取得や改変は制限されている。
  • コンテナはアプリケーションレベルの実行に特化しており、OSのように振る舞うが、安全性を保つために制限された仮想環境である。

つまり、コンテナの root ファイルシステム全体は root 以外の書き込みを許可しておらず、
node ユーザーで実行するとシステムディレクトリへの変更は拒否されます。

sudoは使えません。
sudo apt update
bash: sudo: command not found

🧠 この挙動の意味(セキュリティ観点)

行動結果理由
apt update / apt install❌ 拒否nodeユーザーではrootディレクトリ書き込み不可
npm installnodeユーザー領域でOK
/var/lib/usr への変更読み取り専用(またはrootのみ)
/home/node 内の書き込みユーザー領域

補足:
コンテナ内において node ユーザーが書き込み可能な領域は、/home/node//tmp、およびホスト側からバインドマウントされたディレクトリに限定される。

つまり、このサンドボックスは:

  • ルート権限を完全に排除
  • システム変更禁止
  • アプリレベルだけ自由

という構成です。

Pythonを使うときにこまること

pipがないし、インストールできない。Pythonは入っているもののpipが入ってないようです。
また、上記理由により以下のようにしてpipを追加インストールすることができません。

sudo apt update
sudo apt install python3-pip

それに対してnpmは使える。実際、コンテナの中に入って以下のようにaxiosライブラリをインストールしてみたら成功しました。

npm install axios

added 23 packages in 3s

Pythonコードをサンドボックスで実行する方法

ユーザー領域/home/node/にuvをインストールすればPythonが自由に使えるようになりました。
単にuvをインストールしようとすると書き込めないところにインストールしようとするので、指定するのがポイントです。また、uvのインストーラーはユーザー権限で実行可能です。
補足:uvとは?

uv は、Pythonの仮想環境とパッケージ管理を高速・安全に行うためのツールです。従来の venvpip の代わりに使うことで、以下のようなメリットがあります:

  • 高速:依存関係の解決やインストールが非常に速い
  • 安全:ユーザー領域にインストールされるため、sudoapt が不要
  • シンプルuv venv で仮想環境を作り、uv pip install でライブラリを導入できる
  • 互換性pip と同じ構文で使えるので、既存のPythonプロジェクトにもすぐ適用可能

以下のプロンプトで指示すれば/home/node/にuvのインストールスクリプトをダウンロードし、スクリプトをそのまま sh に渡して実行するコマンドを実行してくれます。
プロンプトで頼まないでコンテナの中に入って、uvを/home/node/にインストールしてもいいと思います。

実演

プロンプト:pythonを実行したいので/home/node/にuvをインストールして

│ ?  Shell UV_HOME=/home/node/ curl -LsSf https://astral.sh/uv/install.sh |… ← │  
│                                                                              │  
│   UV_HOME=/home/node/ curl -LsSf https://astral.sh/uv/install.sh | sh        │  
                                                                               
│ Allow execution of: 'curl, sh'?                                              │  
│                                                                              │  
│ ● 1. Yes, allow once                                                         │  
│   2. Yes, allow always ...                                                   │  
│   3. No, suggest changes (esc)    

その後、パスの設定とバージョン確認が実行された。
│ ✓  Shell export PATH="/home/node/.local/bin:$PATH" && uv --version (Add uv'… │  
│    uv 0.9.8     

補足:export PATH="/home/node/.local/bin:$PATH"の意味
目的:/home/node/.local/bin を PATH に追加することで、そこにある実行ファイル(例:uv)をコマンドとして使えるようにします。

さらに、uvしか入っていなくてPythonがなかったので追加で指示
uv python installを実行して
│ ✓  Shell export PATH="/home/node/.local/bin:$PATH" && uv python install (Ad… 
│    Installed Python 3.14.0 in 28.95s                                         │  
│     + cpython-3.14.0-linux-x86_64-gnu (python3.14)    

コンテナの中に入ってPythonのバージョン確認

python3 --version
Python 3.11.2←こちらはサンドボックスに元から入っていたPython
uv run python --version
Python 3.14.0←こちらはuvのPython

本題のpythonコードを実行するようプロンプトで指示したらうまくいった。



╭──────────────────────────────────────────────────────────────────────────────╮  
│ ✓  Shell export PATH="/home/node/.local/bin:/home/node/.local/share/uv/pyth… │  
│                                                                              │  
│    Using CPython 3.14.0                                                      │  
│    Creating virtual environment at: .venv                                    │  
│    Activate with: source .venv/bin/activate                                  │  
╰──────────────────────────────────────────────────────────────────────────────╯  
╭──────────────────────────────────────────────────────────────────────────────╮  
│ ✓  Shell export PATH="/home/node/.local/bin:/home/node/.local/share/uv/pyth… │  
│                                                                              │  
│    Resolved 8 packages in 551ms                                              │  
│    Prepared 8 packages in 234ms                                              │  
│    ░░░░░░░░░░░░░░░░░░░░ [0/8] Installing wheels...                           │  
│    warning: Failed to hardlink files; falling back to full copy. This may l  │  
│    ead to degraded performance.                                              │  
│             If the cache and target directories are on different filesystem  │  
│    s, hardlinking may not be supported.                                      │  
│             If this is intentional, set `export UV_LINK_MODE=copy` or use `  │  
│    --link-mode=copy` to suppress this warning.                               │  
│    Installed 8 packages in 469ms                                             │  
│     + beautifulsoup4==4.14.2                                                 │  
│     + certifi==2025.10.5                                                     │  
│     + charset-normalizer==3.4.4                                              │  
│     + idna==3.11                                                             │  
│     + requests==2.32.5                                                       │  
│     + soupsieve==2.8                                                         │  
│     + typing-extensions==4.15.0                                              │  
│     + urllib3==2.5.0                                                         │  
╭──────────────────────────────────────────────────────────────────────────────╮  
│ ✓  Shell export PATH="/home/node/.local/bin:/home/node/.local/share/uv/pyth… │  
╰──────────────────────────────────────────────────────────────────────────────╯  
╭──────────────────────────────────────────────────────────────────────────────╮  
│ ✓  ReadFile output.txt         
✦ The extract_h2.py script has been executed successfully. The extracted <h2> tags
  have been written to output.txt.

  The content of output.txt is:

   1 NotebookLMでイチゲブログについて質問できます
   2 イチゲブログへようこそ
   3 絵本
   4 主要なカテゴリ
   5 注目の記事
   6 イチゲブログの最新記事をチェック!
   7 おすすめ自作アプリ
   8 関連サービス

実行されたことは
・バインドされている作業ディレクトリC:\Users\user\gemini_cli\geminiCLI_sandboxにvenvで仮想環境を立ち上げ
・必要なライブラリrequestsとbeautifulsoup4をインストール
・extract_h2.py が実行され結果が出力された。

ネットワーク

Windows11+Dockerデスクトップの場合、GeminiCLI のサンドボックスは、実体としては Dockerコンテナ です。
このコンテナは Docker の default bridge networkに接続されます。
docker network inspect bridge でbridgeネットワークの詳細が見れるが、sandbox-0.13.0-0という名前のDockerコンテナ が”IPv4Address”: “172.17.0.2/16″ということぐらいしかわからない。

docker network inspect bridge 
[
    {
        "Name": "bridge",
        "Id": "e47a05d9ceaa04e9b699f17aeabfdfa22e816e49f0d3d21e4101053abfd20970", 
        "Created": "2025-11-08T19:21:05.165238689Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv4": true,
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "399e4876e8ecd9b421006f9402da96a60cc6b1199afb6d70f2641f1e33415452": { 
                "Name": "sandbox-0.13.0-0",
                "EndpointID": "a215dc6ee64a1e1febb0b26fff21f5c0c99029947ec5d6f2c6bed7314e5f94f6",
                "MacAddress": "b6:28:65:9c:91:dd",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

コンテナ内から外部(インターネットには)への通信はDocker が内部で NAT(Network Address Translation) を使って通信しているということです。ということでコンテナ内部からcurlやPythonのrequestsライブラリでインターネットには接続可能です。
ここのログや制限を追加することは簡単ではなさそうでした。

一応、以下でログを出力できるが、文字化けが激しい。
docker logs sandbox-0.13.0-0 > log.txt

所感

サンドボックスありだと、Pythonを使うときに不便です。そのほかの用途でもコンテナにインストールできるものが限られるため、うまくいかないときの原因をさがすときに余計大変になります。

タイトルとURLをコピーしました