こんにちは!データサイエンスやAI開発の現場で、Jupyter NotebookやJupyterLabを毎日バリバリ使っていますか?
「自分のローカル環境では綺麗に動くのに、チームメンバーにコードを共有したら『動かない』と言われた」
「誰かがうっかり共通サーバーのライブラリをアップデートしてしまい、全員の環境が壊れた」
もしあなたが今、こんなチーム開発の闇に直面しているなら、それは個人利用のJupyterから、組織利用の「JupyterHub」へステップアップする最高のタイミングです。
今回は、数々の現場でデータ基盤やAI開発環境を構築してきた私から、JupyterLabのマルチユーザー運用を支えるJupyterHubの構築と、実務で絶対に外せないセキュアな設計・リソース管理の極意を優しく、そして徹底的に解説します。
これをマスターすれば、チーム全員にブラウザ一つで最高にセキュアかつ快適な開発環境を即座に提供できるようになり、毎日の環境トラブル対応から完全に解放されますよ。それでは、一緒に進めていきましょう!
—
1. なぜチーム開発に「JupyterHub」が必要なのか?
私たちが普段何気なく使っているJupyterLabは、基本的に「1人のユーザーが1つのマシンのリソースを独占する」前提で作られています。これをチームでそのまま共有しようとすると、次のような大問題が発生します。
- セキュリティの崩壊: 全員が同じ管理者権限や同じディレクトリで作業するため、他人のコードを誤って消したり、機密データを盗み見たりできてしまう。
- 依存関係の地獄: AさんはPython 3.9とTensorFlow 2.12を使いたい、BさんはPython 3.11とPyTorch 2.0を使いたいといった要望が衝突し、環境がカオスになる。
- リソースの枯渇: 誰かが暴走した機械学習の無限ループを回し始めると、サーバー全体のメモリが食い潰され、チーム全員の作業が吹き飛ぶ。
JupyterHubがもたらす革命
JupyterHubを導入すると、「ユーザーごとの完全な隔離(アイソレーション)」と「一元的なリソース管理」が同時に手に入ります。
[ ユーザーAのブラウザ ] –(HTTPS)–+–> [ JupyterHub (プロキシ/認証) ]
| +—> [ ユーザーAのJupyterLabコンテナ ]
[ ユーザーBのブラウザ ] –(HTTPS)–+ +—> [ ユーザーBのJupyterLabコンテナ ]
各ユーザーは自分のログインIDでアクセスし、自分専用の独立したコンテナやプロセス空間でJupyterLabを動かします。他のユーザーの領域には一切干渉できません。まさに「チーム全員に専用のハイエンドPCをクラウド上で配る」ような体験を構築できるのです。
—
2. 基礎知識:JupyterHubのアーキテクチャ
JupyterHubは、単体のツールではなく、以下の3つの主要コンポーネントが連携して動く「システム」です。
1. Proxy(プロキシ): 玄関口。外部からのリクエストを受け付け、適切なユーザーのJupyterLabへルーティングします。デフォルトでは`configurable-http-proxy`が使われます。
2. Hub(サーバー本体): 司令塔。ユーザーの認証を管理し、後述するSpawns(生成器)を通じてユーザーごとのJupyterLabプロセスやコンテナを起動・管理します。
3. Spawners(生成器): 実働部隊。ユーザーがログインした際、どのようにJupyterLabの環境を立ち上げるかを決めます。「OSの別プロセスとして起動する(PAM)」方法や、「Dockerコンテナとして起動する(DockerSpawner)」方法などがあります。
今回は、最も実務的で堅牢な「DockerSpawnerを用いたコンテナベースのマルチユーザー環境」の構築ハンズオンをお届けします。
—
3. 実践!JupyterHub構築ステップ
ここからは、実際にLinux環境(Ubuntuなどを想定)上でDockerとDocker Composeを使って、セキュアなJupyterHub環境を構築していきましょう。
ステップ1: 必要なディレクトリと設定ファイルの準備
まずは、プロジェクト用のディレクトリを作成し、設定ファイルを配置します。
作業用ディレクトリを作成
mkdir -p /opt/jupyterhub-cluster
cd /opt/jupyterhub-cluster
必要なディレクトリを作成(データ永続化用)
mkdir -p data/db
次に、JupyterHubの全体挙動を制御する設定ファイル `jupyterhub_config.py` を作成します。
ステップ2: jupyterhub_config.py の詳細設定
以下の内容で `jupyterhub_config.py` を作成してください。実務で必ず必要になる「Dockerコンテナの自動生成」と「永続化ボリュームの設定」が含まれています。
==========================================
JupyterHub 基礎設定ファイル
==========================================
c = get_config() # noqa
——————————————
1. ネットワークと基本動作の設定
——————————————
すべてのネットワークインターフェースからの接続を許可
c.JupyterHub.ip = ‘0.0.0.0’
c.JupyterHub.port = 8000
管理者ユーザーの設定(Hub自体の管理や全ユーザーのセッション確認が可能)
c.Authenticator.admin_users = {‘admin_user’}
新規ユーザーの自動作成を許可(初ログイン時にコンテナを自動生成)
c.Authenticator.allow_all = True
——————————————
2. Spawner(Docker連携)の設定
——————————————
プロセスではなく、Dockerコンテナとして各ユーザーのJupyterLabを起動する
c.JupyterHub.spawner_class = ‘dockerspawner.DockerSpawner’
ユーザーごとに起動するDockerイメージを指定
c.DockerSpawner.image = ‘jupyter/datascience-notebook:latest’
コンテナが接続するDockerネットワーク名
c.DockerSpawner.network_name = ‘jupyterhub-network’
コンテナ停止時にデータを失わないよう、ホームディレクトリをホスト側にマウントする
{username} 部分はログインしたユーザー名に動的に置き換わります
c.DockerSpawner.notebook_dir = ‘/home/jovyan/work’
c.DockerSpawner.volumes = {
‘jupyterhub-user-{username}’: ‘/home/jovyan/work’
}
——————————————
3. リソース制限(CPU・メモリ)のベストプラクティス
——————————————
1人のユーザーがサーバー全体をクラッシュさせないよう制限を設ける
c.DockerSpawner.cpu_limit = 2.0 # 最大CPUコア数(2コアまで)
c.DockerSpawner.mem_limit = ‘4G’ # 最大メモリ消費量(4GBまで)
——————————————
4. データベース設定
——————————————
ユーザー情報やセッション情報を保存するSQLiteのパス
c.JupyterHub.db_url = ‘sqlite:///data/jupyterhub.sqlite’
> 💡 アーキテクトの知見:
> `c.DockerSpawner.volumes` によるボリュームの動的マウントは非常に重要です。これを行わないと、コンテナを停止・削除した瞬間にユーザーが書いたコードやデータがすべて消滅します。Kubernetes環境の場合はPersistentVolumeClaim(PVC)と連携させる部分です。
ステップ3: Docker Compose で一括起動
次に、JupyterHub自体とプロキシを管理するための `docker-compose.yml` を作成します。
version: ‘3.8’
services:
jupyterhub:
image: jupyterhub/jupyterhub:latest
container_name: jupyterhub_server
restart: always
user: root
depends_on:
- proxy
volumes:
# Dockerソケットをマウントし、Hubから子コンテナを自由に出し入れできるようにする
- /var/run/docker.sock:/var/run/docker.sock
# 先ほど作成した設定ファイルをコンテナ内にマウント
- ./jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py
# データベース等の永続化データ
- ./data:/srv/jupyterhub/data
ports:
- “8000:8000”
environment:
- DOCKER_NETWORK_NAME=jupyterhub-network
command: jupyterhub -f /srv/jupyterhub/jupyterhub_config.py
networks:
jupyterhub-network:
name: jupyterhub-network
driver: bridge
ステップ4: 起動と動作確認
設定が完了したら、以下のコマンドでコンテナをバックグラウンド起動します。
コンテナのビルドとバックグラウンド起動
docker-compose up -d
起動ログをリアルタイムで確認し、エラーがないかチェックする
docker-compose logs -f jupyterhub
ログに `JupyterHub is now running at http://:8000` と表示されたら成功です!
ブラウザを開き、`http://<サーバーのIPアドレス>:8000` にアクセスしてみましょう。JupyterHubのログイン画面が表示されます。
- 初期ユーザーの作成: 初回ログイン画面で、任意のユーザー名(例: `data-scientist-01`)とパスワードを入力してログインしてください。設定ファイルで `allow_all = True` にしているため、この場で新しいアカウントが自動作成され、そのユーザー専用のJupyterLabコンテナが裏側で立ち上がります。
—
4. セキュリティとリソース管理のベストプラクティス
無事に動いたところで、実運用を見据えた「絶対に押さえておくべきプロの知見」をいくつかお伝えします。
① パスワード認証からOAuth / LDAP連携への移行
先ほどのハンズオンでは簡易的なパスワード認証(PAM)を使いましたが、実運用でこれを続けるのは危険です。社内のセキュリティ基準に合わせ、GitHub OAuth や Google Workspace (OIDC)、あるいは社内 LDAP / Active Directory と連携させましょう。
例えばGitHub連携にすれば、自社の特定Organization(組織)に所属しているメンバーだけがログインできるように制限でき、パスワード管理の手間もゼロになります。
② リソース制限(GPUの割り当てなど)
AI・ディープラーニング開発ではGPUの共有が鍵になります。DockerSpawnerでは、NVIDIA Container Toolkitと連携することで、特定のユーザーにのみGPUをアサインすることが可能です。
例: 特定のユーザーグループにのみGPUを1基割り当てる設定の断片
c.DockerSpawner.extra_host_config = {
“device_requests”: [
{
“Driver”: “nvidia”,
“Count”: 1,
“Capabilities”: [[“gpu”]],
}
]
}
③ アイドルシャットダウン(コスト最適化)
開発者がJupyterLabを開いたまま退勤したり、数日間放置したりすると、サーバーのメモリやCPUが無駄に消費されます。`jupyterhub-idle-culler` などのアドオンを導入し、一定時間(例: 2時間)操作がないユーザーのコンテナを自動停止する仕組みを必ず組み込みましょう。クラウドのAWSやGCPで運用する場合、これだけでインフラコストが劇的に削減されます。
—
5. おわりに
お疲れ様でした!今回は、JupyterHubを用いたマルチユーザー環境の構築から、実務で不可欠なセキュリティ・リソース管理の要点までを解説しました。
個人用環境からJupyterHubへのステップアップは、最初は少しハードルが高く感じるかもしれませんが、一度構築してしまえば、チーム全体の開発効率とセキュリティは劇的に向上します。「誰かの環境を壊してしまう恐怖」から解放されたチームで、ぜひ最高にクリエイティブなAI・データサイエンス開発を楽しんでください。
あなたの毎日の開発ライフが、より快適で知的になりますように。それではまた別の記事でお会いしましょう!