如何连接到运行在 Docker 容器上的远程 Jupyter Notebook?

3
我正在远程机器(Amazon P2)上运行一个运行在Docker容器(Ubuntu)中的Jupyter笔记本。我想通过浏览器(http://localhost:8883/)访问这个笔记本,但是出现了以下错误提示:
open failed: connect failed: Connection refused

我的ssh配置:

Host p3
    HostName <remote machine ip>
    User <user>
    LocalForward 8883 127.0.0.1:8884

我正在远程机器上运行容器,命令如下:

nvidia-docker run -it -p 8884:8884 <docker image>

我正在运行的Docker容器上:

jupyter-notebook --NotebookApp.iopub_data_rate_limit=10000000000 --no-browser --port=8884 --allow-root

我可以连接到运行在远程机器上的笔记本(不在docker容器中)。
我该如何从浏览器连接到运行在docker机器上的笔记本?

也许由于所有这些转发的网络流量在某个地方丢失了。在远程机器上启动容器后,请检查其IP地址(应该在docker inspect <container_name>输出中)。然后直接在ssh的LocalForward规则中使用此IP地址。这样,您就不会通过远程机器上的iptables NAT了。 - odk
这不起作用。 - avitheavi
1个回答

2
这是一个很好的问题。我的日常开发工作流程涉及从我的笔记本电脑连接到在GPU加速服务器上运行的Docker容器中的jupyter笔记本。
该问题有三个部分:
1. 容器 2. 主机 3. 远程
第一部分:配置容器。
您需要确保可以通过ssh连接到您的容器。我修改了Docker's sshd example中的Dockerfile。您应该修改Docker示例以适应自己的需求;例如,您的用例是否允许您以root身份连接?
我已经设置了无密码ssh的容器。请注意,在构建图像时,您可以预先制作所需的无密码ssh文件并将它们复制到相应的目录中。
如果您想节省一些后续的输入,我强烈建议您修改jupyter配置文件。
第二部分:配置主机
假设您在主机上运行Linux。 您将需要创建一个docker网络。 您只需要使用--attachable选项即可。 我喜欢在我的/etc/hosts中有一个条目,以使生活更轻松,例如:
172.21.0.2  container-1 container-1

您还需要修改主机系统上的/home/<user>/.ssh/config文件。
Host container-1
    Hostname container-1
    IdentityFile ~/.ssh/containers_rsa
    User root

Host tunnel-container-1
    Hostname container-1
    IdentityFile ~/.ssh/containers_rsa
    User root
    LocalForward 8888 localhost:8888
    LocalForward 8000 localhost:8000

你不厌烦每次都要输入 nvidia-docker 吗?这里是一个样例 /etc/docker/daemon.json:
  {
    "runtimes": {
        "nvidia": {
            "path": "nvidia-container-runtime",
            "runtimeArgs": []
        }
    },
    "graph":"/docker-files"
  }

第三部分:配置本地系统。
你已经接近成功了。你需要能够建立到远程系统的ssh隧道。以下是一个本地系统的示例~/.ssh/config文件:
Host remote_host
    Hostname remote_host
    IdentityFile ~/.ssh/remote_host/remote_rsa

Host tunnel-remote_host
    Hostname remote_host
    IdentityFile ~/.ssh/remote_host/remote_rsa
    LocalForward 10000 localhost:8888
    LocalForward 10006 localhost:8000

一个重要的注意事项。我在本地的/etc/hosts文件中有一个远程主机的条目。您的实例可能没有静态IP地址。因此,您可以每次启动实例时修改本地的/etc/hosts文件,或者编写一个脚本以正确的LocalForward指令连接到远程系统。
将所有步骤整合起来。
假设您的远程实例已成功启动,并且Docker正在正确运行。此外,它还假定您已经完成了我提到的便利步骤。
1. 远程SSH连接。 2. 启动Docker容器。注意容器名称,最好指定名称。 3. 将容器连接到网络,例如:docker network connect skynet container-1。您可以通过运行docker network inspect skynet检查容器是否已连接。请注意,您的网络很可能被命名为其他名称而不是skynet。 4. SSH连接到Docker容器,例如:ssh container-1。 5. 启动jupyter服务器,jupyter notebook &。我将进程后台化,以便无需打开另一个会话。 6. 在远程/主机系统上: ssh -N -f tunnel-container-1。现在我们有了从主机系统到Docker容器的SSH隧道。 7. 在本地系统上: ssh -N -f tunnel-remote_host。 8. 在本地系统上导航到http://localhost:10000
如果一切正常,您应该已连接到您在Dockerfile中指定的根目录中的jupyter服务器!
如何进行故障排除:
首先确认您可以使用正确的运行时环境手动启动Docker容器。确认您可以通过ssh启动Jupyter笔记本电脑。是的,您无法连接到它,但您会知道所有这些部分都在工作。接下来,请确认您可以从远程到容器建立ssh隧道。您可以使用wget获取Jupyter服务器登陆页面的HTML来确认隧道是否正常工作。然后检查从本地到远程/主机的转发。我花了一些时间尝试才找到正确的LocalForward指令顺序。
希望这有所帮助。

这里是一个链接,指向一个 GitHub 仓库,将所有内容整合在一起:https://github.com/VanBantam/one-env - VanBantam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接