Docker 容器中部署 Jupyter Notebook 并通过宿主机端口访问的实践记录:使用 socat 桥接 Docker 与宿主机端口
Docker 容器中部署 Jupyter Notebook 并通过宿主机端口访问的实践记录:使用 socat 桥接 Docker 与宿主机端口
1. 问题背景
在深度学习环境部署过程中,经常会将实验环境运行在 Docker 容器中,例如 SAM2、PyTorch 等模型环境。为了方便开发和调试,需要在宿主机浏览器中访问容器内的 Jupyter Notebook。
本次场景如下:
- 宿主机:Ubuntu 系统
- Docker 容器:运行深度学习环境
- 容器内部:
- Python 虚拟环境
.venv - Jupyter Notebook 服务
- Python 虚拟环境
- 目标:
通过宿主机 IP 和指定端口访问容器中的 Jupyter:
http://宿主机IP:9999
最终实现:
浏览器
|
| 10.12.54.121:9999
|
宿主机 Ubuntu
|
| socat 转发
|
Docker 容器 172.17.0.x:8888
|
|
Jupyter Notebook
2. 初始问题
进入 Docker 容器:
docker exec -it <container_name> bash
启动虚拟环境:
source .venv/bin/activate
然后启动 Jupyter:
jupyter notebook
发现无法启动:
Running as root is not recommended. Use --allow-root to bypass.
原因:
Docker 容器默认通常使用 root 用户运行,而 Jupyter 默认禁止 root 启动。
3. 配置 Jupyter 服务
解决方法:
指定允许 root 用户运行:
jupyter notebook --allow-root
但是默认情况下:
Jupyter 只监听:
127.0.0.1:8888
只能容器内部访问。
因此需要指定监听所有地址:
jupyter notebook \
--ip=0.0.0.0 \
--port=8888 \
--allow-root
启动后:
Jupyter Server is running at:
http://0.0.0.0:8888
查看端口:
netstat -tlnp | grep 8888
正常:
tcp 0 0 0.0.0.0:8888 LISTEN
说明 Jupyter 已经允许外部连接。
4. Docker 网络访问测试
查看 Docker 容器 IP:
宿主机:
docker inspect <container_id> | grep IPAddress
例如:
172.17.0.4
测试宿主机访问容器:
curl http://172.17.0.4:8888/tree
返回:
HTTP/1.1 302 Found
Location: /login?next=%2Ftree
说明:
- Docker 网络正常
- Jupyter 服务正常
- 宿主机可以访问容器
5. 使用 socat 桥接 Docker 与宿主机端口
5.1 为什么需要 socat
如果 Docker 创建容器时没有设置:
-p 9999:8888
那么容器端口不会直接映射到宿主机。
重新创建容器成本较高,因此采用 socat 做端口转发。
结构:
宿主机9999端口
|
|
socat
|
|
Docker容器172.17.0.4:8888
5.2 安装 socat
Ubuntu:
sudo apt install socat
5.3 创建端口桥接
宿主机执行:
socat TCP-LISTEN:9999,reuseaddr,fork TCP:172.17.0.4:8888
参数说明:
| 参数 | 作用 |
|---|---|
| TCP-LISTEN:9999 | 监听宿主机9999端口 |
| reuseaddr | 允许端口快速复用 |
| fork | 每个连接创建独立进程 |
| TCP:172.17.0.4:8888 | 转发到Docker Jupyter |
6. 验证 socat 转发
查看监听:
ss -tlnp | grep 9999
显示:
LISTEN *:9999
测试:
curl -v http://127.0.0.1:9999/tree
返回:
HTTP/1.1 302 Found
Location: /login?next=%2Ftree
说明:
端口桥接成功。
完整链路:
127.0.0.1:9999
↓
socat
↓
172.17.0.4:8888
↓
Jupyter
7. 开放 Ubuntu 防火墙端口
如果其他机器无法访问宿主机,需要检查 Ubuntu 防火墙。
查看状态:
sudo ufw status
开放 9999 TCP:
sudo ufw allow 9999/tcp
查看:
sudo ufw status
结果:
9999/tcp ALLOW
此时其他机器可以访问:
http://10.12.54.121:9999
8. 删除防火墙规则
如果不再需要开放:
sudo ufw delete allow 9999/tcp
查看规则:
sudo ufw status numbered
也可以根据编号删除:
sudo ufw delete <编号>
9. 最终方案总结
最终采用方案:
Docker 内
启动 Jupyter:
jupyter notebook \
--ip=0.0.0.0 \
--port=8888 \
--allow-root
宿主机
获取容器 IP:
docker inspect <container>
例如:
172.17.0.4
启动 socat:
socat TCP-LISTEN:9999,reuseaddr,fork TCP:172.17.0.4:8888
防火墙
开放端口:
sudo ufw allow 9999/tcp
浏览器访问
http://宿主机IP:9999
例如:
http://10.12.54.121:9999
即可访问 Docker 内的 Jupyter Notebook。
10. 总结
本次问题的核心不是 Jupyter 本身,而是 Docker 容器网络与宿主机端口之间缺少映射关系。
解决方案由三部分组成:
- Jupyter 配置外部监听
--ip=0.0.0.0
确保容器内部服务可以被访问。
- socat 实现 Docker 与宿主机端口桥接
TCP-LISTEN:9999 → TCP:container_ip:8888
实现宿主机端口转发。
- Ubuntu 防火墙开放访问端口
ufw allow 9999/tcp
最终实现:
外部浏览器
|
|
宿主机:9999
|
|
socat
|
|
Docker:8888
|
|
Jupyter Notebook
该方案适用于:
- 已经运行的 Docker 容器
- 不方便重新创建容器
- 需要快速暴露开发服务(Jupyter、TensorBoard、Web 服务等)的场景。
更多推荐
所有评论(0)