新品 NVIDIA B300 · 288 GB HBM3e 服务器 — 起价 $4,019/月 每块 GPU

查看 B300

文档 · 应用

在 GPU 服务器上部署 JupyterLab

在您掌控的 GPU 服务器上运行 JupyterLab:把支持 GPU 的 PyTorch 装在独立的环境中,将 JupyterLab 作为 systemd 服务运行,只监听 localhost 并设置密码,再通过 SSH 隧道访问。

更新于 8 分钟阅读

在 GPU 服务器上安装 JupyterLab 和 PyTorch

要在 GPU 服务器上运行 JupyterLab,需要在 Python 虚拟环境中安装 JupyterLab 和 CUDA 版或 ROCm 版的 PyTorch,把 JupyterLab 作为 systemd 服务启动,让它绑定在 127.0.0.1:8888 上并设置密码,然后通过 SSH 隧道在浏览器中打开它。这样,notebook 就在服务器的 GPU 上运行,而且不会有任何端口暴露在互联网上。如果您下单时在“软件”步骤中选择了 JupyterLab,它已经安装好了;本指南介绍的是如何自行安装和运行。

除非某个步骤切换到了 alice(即在新 GPU 服务器上的第一个小时一文中创建的普通用户),否则请在 Ubuntu 22.04 或 24.04 上以 root 身份运行这些命令。绝不要以 root 身份运行 JupyterLab:它的 notebook 和终端都拥有运行它的那个用户的权限。请先安装 GPU 驱动(参见 NVIDIA 驱动与 CUDA;在 AMD MI355X 上则参见 MI355X 上的 ROCm)。在 NVIDIA GPU 上,nvidia-smi 输出的顶部必须显示 CUDA Version 13.0 或更高:PyTorch 的 wheel 包自带 CUDA 库,而 CUDA 13.x 程序要在 580 系列或更新的驱动上才能运行(参见 CUDA 发行说明)。

adduser alice                      # 如果 alice 已存在,跳过这一步
usermod -aG render,video alice     # 仅限 AMD MI355X
su - alice

# 以 alice 身份:先安装 uv,再在独立的环境中装好 Python 3.13
curl -LsSf https://astral.sh/uv/install.sh | sh
~/.local/bin/uv venv --python 3.13 --seed --managed-python ~/jupyter-env
source ~/jupyter-env/bin/activate

pip install torch torchvision --index-url https://download.pytorch.org/whl/cu132      # NVIDIA
# pip install torch torchvision --index-url https://download.pytorch.org/whl/rocm7.14 # AMD MI355X
pip install jupyterlab
python -c "import torch; print(torch.cuda.is_available(), torch.cuda.device_count())"

这两行 PyTorch 安装命令取自 pytorch.org 为 2.14.1 版给出的说明(2026年10月20日核对)。所有 NVIDIA GPU 都请使用 CUDA 13.2 构建,不要用选择器中同样列出的 CUDA 12.6 构建:PyTorch 2.7 通过其 CUDA 12.8 构建加入了对 Blackwell 的支持。pip install jupyterlab 来自 JupyterLab 安装指南,它还会一并安装 ipykernel,因此默认的 Python 3 内核就运行在这个环境中,使用的正是这里装好的 PyTorch。适合的 GPU 请参见科研和微调页面。

将 JupyterLab 作为 systemd 服务运行

服务会在开机时自动启动,崩溃后也会自动恢复运行。请先设置密码,这一步仍以 alice 身份执行。Jupyter Server 只保存密码的哈希值,存放在 ~/.jupyter/jupyter_server_config.json 中:

jupyter server password      # 会要求输入两次,然后写入哈希值
exit                         # 回到 root

以 root 身份把 notebook 和 Hugging Face 缓存放在挂载于 /data 的 NVMe 数据盘上(参见存储与数据),然后创建单元文件:

mkdir -p /data/notebooks /data/hf
chown alice:alice /data/notebooks /data/hf
tee /etc/systemd/system/jupyterlab.service >/dev/null <<'EOF'
[Unit]
Description=JupyterLab
After=network.target

[Service]
User=alice
WorkingDirectory=/data/notebooks
Environment=HF_HOME=/data/hf
ExecStart=/home/alice/jupyter-env/bin/jupyter-lab --no-browser --ip=127.0.0.1 --port=8888 --port-retries=0 --notebook-dir=/data/notebooks --MappingKernelManager.cull_idle_timeout=7200
NoNewPrivileges=yes
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now jupyterlab
ss -tln | grep 8888            # 应只显示 127.0.0.1:8888,没有其他地址
journalctl -u jupyterlab -f    # 查看日志;按 Ctrl-C 停止跟踪
  • --ip=127.0.0.1 让服务器只监听回环地址。--port-retries=0 会在 8888 端口被占用时让启动直接失败,而不是改用后面 50 个端口中的某一个,这样您的隧道就永远不会指向错误的端口。
  • cull_idle_timeout=7200 会关闭已空闲两小时且没有浏览器连接的内核,释放忘记关闭的 notebook 所占用的显存;正在执行代码的内核不会被关闭(参见 Jupyter Server 选项)。
  • NoNewPrivileges=yes 会阻止从 JupyterLab 启动的任何程序通过 sudo 等 setuid 程序获得更高权限:需要管理员权限的操作,请在您的 SSH 会话中完成。

如果不设置密码,Jupyter Server 每次启动时都会生成一个新的随机 token,并在日志中输出带有这个 token 的登录 URL;以 root 身份运行 su - alice -c '~/jupyter-env/bin/jupyter server list' 也能显示这个 URL。

通过 SSH 隧道远程访问 JupyterLab

在您自己的电脑上,把一个本地端口转发到远程服务器的回环地址,然后打开 http://localhost:8888,用您设置的密码登录:

ssh -N -L 8888:127.0.0.1:8888 gpu1

# 您电脑上的 8888 端口已被占用,例如被本地运行的 Jupyter 占用
ssh -N -L 8889:127.0.0.1:8888 gpu1      # 然后打开 http://localhost:8889

gpu1 是 SSH 访问一文中配置的主机条目;在该条目中加一行 LocalForward,每次连接时就会自动打开隧道。在 Windows 上,同样的命令也可以在 PowerShell 中使用。关闭浏览器或隧道不会停止您的内核。

绝不要用 --ip=0.0.0.0 启动 JupyterLab,也绝不要在防火墙中开放 8888 端口:任何人一旦进入,都能以 alice 的身份运行代码、打开终端。如果是团队使用,请改用 JupyterHub(见下文)。在 Docker 中,请以 -p 127.0.0.1:8888:8888 的形式发布端口,因为 Docker 的端口规则会绕过 ufw(参见容器)。

在 notebook 中确认 PyTorch 能识别 GPU

打开一个使用 Python 3 (ipykernel) 内核的 notebook,然后运行:

import torch
print(torch.__version__, "CUDA:", torch.version.cuda, "HIP:", torch.version.hip)
print("GPUs:", torch.cuda.device_count(), torch.cuda.is_available())
for i in range(torch.cuda.device_count()):
    free, total = torch.cuda.mem_get_info(i)
    print(i, torch.cuda.get_device_name(i), f"{free / 2**30:.0f} of {total / 2**30:.0f} GiB free")
print(torch.cuda.get_arch_list())   # MI355X:必须包含 gfx950
x = torch.randn(8192, 8192, device="cuda")
print((x @ x).sum().item())         # 在 GPU 0 上做一次矩阵乘法

输出应包含一个以 +cu132 或 +rocm7.14 结尾的版本号、True,以及每块 GPU 各占一行的名称和显存信息。ROCm 构建沿用了 torch.cuda 接口,因此同样的代码也能在 MI355X 上运行(参见 HIP 语义)。如果 is_available() 返回 False,请在终端中运行 nvidia-smi 或 amd-smi list,然后回到驱动安装指南排查。

在 notebook 中可以用 %pip install <package> 安装软件包,它会在当前内核中运行 pip(参见 IPython 魔法命令),因此软件包会装进 ~/jupyter-env。

为每个 notebook 选择 GPU 并监控显存

除非加以限制,否则每个内核都能看到所有 GPU。请在第一个单元格中、import torch 之前设置 CUDA_VISIBLE_DEVICES;之后要更改它,需要重启内核。也可以为每块 GPU 注册一个内核,这样变量在内核启动之前就已设置好:

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1"   # 这个内核只能看到 GPU 1,并把它视为 cuda:0
import torch
# 以 alice 身份执行:在内核列表中添加一个 Python (GPU 1) 内核
source ~/jupyter-env/bin/activate
python -m ipykernel install --user --name gpu1 --display-name "Python (GPU 1)" --env CUDA_VISIBLE_DEVICES 1

编号与 nvidia-smi 中的顺序一致,可见的 GPU 会从 0 开始重新编号(参见 CUDA 环境变量)。在 MI355X 上,请使用 HIP_VISIBLE_DEVICES(参见 MI355X 上的 ROCm)。在另一个环境中运行同一条命令,就会把那个环境添加为一个内核(参见内核安装)。

要找出是哪个内核占用了显存,可以在终端中运行:

nvidia-smi                       # 进程表会列出每个 PID 及其占用的显存
amd-smi process -G               # AMD MI355X:PID、进程名和显存
ps -o pid,etime,args -p <pid>    # notebook 内核运行的是 ipykernel_launcher

在 notebook 中:

print(torch.cuda.memory_allocated() / 2**30, torch.cuda.memory_reserved() / 2**30)   # 张量占用的 GiB 数、预留的 GiB 数
print(torch.cuda.memory_summary())
del model                  # 删除不再需要的对象
torch.cuda.empty_cache()   # 释放未使用的缓存显存

PyTorch 的缓存分配器会保留已释放的显存以便复用,而 nvidia-smi 和 amd-smi 会把这部分显示为已占用。empty_cache() 只会释放其中未使用的部分,绝不会释放仍被张量占用的显存(参见显存管理)。要释放全部显存,请重启内核。关闭 notebook 后,它的内核仍在运行,显存也照样占着:请在左侧边栏的 Running 面板中关闭内核(参见 JupyterLab 文档)。

让长时间的训练持续运行

关闭浏览器后,内核仍会继续运行;但 JupyterLab 本身一旦停止,内核也会随之结束。Jupyter Server 停止时会关闭它的所有内核,systemd 还会终止该服务控制组中残留的所有进程(参见 KillMode)。因此,一旦服务重启、升级、系统重启或崩溃,内存中的变量和模型都会丢失;notebook 文件则保留最后一次保存时的内容。

任何需要运行数小时的任务,都请在 JupyterLab 之外以脚本形式运行,并把检查点保存到 /data。jupyter nbconvert --to script 可以把 notebook 转换为 Python 脚本;请删掉 %pip 这类魔法命令,因为它们只能在 Jupyter 中运行(参见 nbconvert)。然后以 root 身份,把脚本作为临时 systemd 服务启动:

su - alice -c 'cd /data/notebooks && ~/jupyter-env/bin/jupyter nbconvert --to script train.ipynb'

systemd-run --unit=train --uid=alice --working-directory=/data/notebooks \
  -E CUDA_VISIBLE_DEVICES=0 -E HF_HOME=/data/hf \
  /home/alice/jupyter-env/bin/python -u train.py
journalctl -u train -f          # 跟踪输出;按 Ctrl-C 不会中断训练
systemctl stop train            # 停止训练
systemctl reset-failed train    # 训练失败后,释放这个单元名称

这样启动的训练在 SSH 会话断开和 JupyterLab 重启后仍会继续,但系统重启后不会;-u 让 Python 不再缓冲输出,日志因此能保持最新。也可以使用 tmux(参见 SSH 访问)。中断之后要继续训练,请从最近的检查点恢复,如用 LoRA 和 QLoRA 微调大模型一文所示。

另一种方式:在 Docker 中运行 JupyterLab

请先安装 Docker 和 NVIDIA Container Toolkit(参见容器)。官方的 Jupyter Docker Stacks 发布了 pytorch-notebook 的 CUDA 变体;以 cuda13- 开头的标签需要 580 系列或更新的驱动。请先停止上文配置的服务,或者改为发布另一个主机端口,例如 127.0.0.1:8890:8888:

mkdir -p /data/work && chown 1000 /data/work    # UID 1000 是 jovyan,即镜像中的用户
docker run -d --name jupyter --gpus all --restart unless-stopped \
  -p 127.0.0.1:8888:8888 \
  -v /data/work:/home/jovyan/work \
  quay.io/jupyter/pytorch-notebook:cuda13-2026-10-19
docker logs jupyter 2>&1 | grep token            # 登录 URL

带日期的标签会锁定所有组件的版本;cuda13-latest 则会跟随新的构建更新。替换容器时,只有 /home/jovyan/work 中的内容会保留下来。NVIDIA 的 NGC PyTorch 镜像也包含 JupyterLab(26.09 版中为 4.6.3):运行时使用同样的 --gpus all 和 -p 127.0.0.1:8888:8888,并以 jupyter lab --ip=0.0.0.0 --no-browser --allow-root 作为启动命令。发布在 127.0.0.1 上的端口只能从主机本身访问(参见 Docker 端口发布),因此容器内的 0.0.0.0 不会对外暴露。Docker Stacks 的 GPU 变体是为 CUDA 构建的:在 MI355X 上,请使用上文的原生安装方式。

多用户:使用 JupyterHub,而不是共享一个 JupyterLab

一个 JupyterLab 服务器只对应一个用户。所有知道密码的人都以 alice 的身份工作,共用同样的文件、权限和 GPU;Jupyter Server 的文档也提醒,多人在同一个服务器上执行的命令可能相互冲突、彼此覆盖(参见运行公共服务器)。

如果要为每个人提供独立账户,请使用 JupyterHub:这是一个多用户 Hub,会为每个人启动、管理并代理一个单用户服务器。默认情况下,用户用各自的本地 Unix 账户登录。The Littlest JupyterHub 把它打包成适合单台服务器、最多 100 名用户的发行版。请按照它的文档操作:文档指出每个部署都应启用 HTTPS,而这需要一个指向该服务器的域名。同一台服务器上的用户仍然共享它的 GPU:请约定好谁使用哪几块,或者为每人分配一台服务器。

在租期结束前备份 notebook

如果租期没有续费,服务器会在付费月份结束时停止运行,磁盘也会被清空。请在结束日期前几天,把您的 notebook、您生成的数据和检查点,连同可用于重建环境的软件包列表,一起复制到服务器之外:

su - alice -c '~/jupyter-env/bin/pip freeze > /data/notebooks/requirements.txt'

# 在您自己的电脑上执行
rsync -avhP gpu1:/data/notebooks/ ./notebooks/

在下一台服务器上,运行 pip install -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu132(在 MI355X 上改为 rocm7.14)即可重建环境。大型数据集和检查点请用 rclone 上传到对象存储,方法见存储与数据。

对这篇指南有疑问?

请通过联系表单告诉我们您使用的 GPU、运行的命令以及得到的输出结果。

客户中心

登录 CryptGPU

您的订单、账单和服务器,一站式管理。

还没有 CryptGPU 账户?

账户是在结账时创建的:先选择您的服务器和软件,然后在首次下单的账户步骤中创建账户。

部署服务器