JupyterHub 生成的 Jupyter Notebook 容器没有外部网络访问
No outside network access for Jupyter Notebook container spawned by JupyterHub
所以,这就是我想要实现的目标:
- 一个 Jupyterhub 服务器
- 当您访问但未登录时,会将您带到另一个 Web 服务器(使用 Django 自定义编码)
- 该网络服务器使用 OAuth 对用户进行身份验证
- 并生成一个笔记本容器。
- 此笔记本容器必须预先填充一个令牌,该令牌由烘焙到笔记本 Docker 图像中的自定义库使用,以针对服务进行身份验证。
- 笔记本容器需要能够与 Web 服务器通信,以便进行进一步的交互,例如检索结果等。
除最后一部分外,我或多或少做到了这一点。我正在启动一个笔记本服务器,但它无法访问外部世界。它只能访问 Jupyter Hub(这就是它工作的原因!),没有别的。
这是我的与 DockerSpawner 相关的 Jupyter Hub 配置(我省略了 OAuth 设置,因为它们按预期工作。
# Tell JupyterHub that we want Docker Spawner to be used.
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
# And what image should be used by the Docker Spawner
c.DockerSpawner.image = 'jupyter/scipy-notebook:7a0c7325e470'
# The Hub must listen on all interfaces.
c.JupyterHub.hub_ip = '0.0.0.0'
# And this should be the address of the Hub API
c.JupyterHub.hub_connect_ip = 'jupyterhub'
# Ask containers to connect to this network so that they can
# communicate with the Hub.
c.DockerSpawner.network_name = 'djangodockerjupyterdemo_default'
# And let's not make a mess, remove user containers when done.
c.DockerSpawner.remove = True
# We need to set the Notebook Directory
notebook_dir = '/home/jovyan/work'
c.DockerSpawner.notebook_dir = notebook_dir
# Need to tell where to mount the volumes.
c.DockerSpawner.volumes = { 'jupyterhub-user-{username}': notebook_dir }
请注意,djangodockerjupyterdemo_default
是由 docker-compose 创建的,这要归功于项目目录的名称。 (我知道这不是最好的做法,但现在我只是希望有一个最简单的例子。)
这是我的 docker-撰写:
version: "2"
services:
database:
image: "mysql:5.6"
volumes:
- ./data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=test123
- MYSQL_DATABASE=oauthserver
- MYSQL_USER=oauthadmin
- MYSQL_PASSWORD=test123
webapp:
image: auth_server:latest
volumes:
- ./:/app
links:
- database:database
environment:
- PYTHONUNBUFFERED=1
- ENV=DEV
- DATABASE_HOST=database
- DATABASE_USER=oauthadmin
- DATABASE_DBNAME=oauthserver
- DATABASE_PASSWORD=test123
hostname: oauthserver.ddi.in
jupyterhub:
image: "jupyterhub:test"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:rw"
- "./jupyterhub:/srv/jupyterhub"
environment:
- OAUTH2_AUTHORIZE_URL=http://oauthserver.ddi.in:8000/o/authorize
- OAUTH2_TOKEN_URL=http://oauthserver.ddi.in:8000/o/token/
hostname: jhtest.ddi.in
links:
- webapp:oauthserver.ddi.in
我用 https://hub.docker.com/r/defreitas/dns-proxy-server to access the JupyterHub server by saying "http://jhtest.ddi.in:8000"。
现在,一旦容器启动,我可以确认以下内容:
docker exec
进入 webapp
或 jupyterhub
容器,然后 wget
从 Internet 上的某个地方下载文件。
docker exec
进入生成的 Jupyter 笔记本容器并执行相同的操作不会。尝试从笔记本内部使用 requests.get()
也是如此。
如何让生成的笔记本访问外界?这对我的用例至关重要(我确信这是一个合理的期望)。
PS:我注意到几乎没有任何示例涉及使用自定义 Django 应用程序设置 OAuth JupyterHub。我希望公开发布我的示例,并希望它可以构成 Jupyter Hub 文档中的资源。
您可能想在 Jupyter Discourse Forum 的 'JupyterHub' 类别下做一个非常简短的 post,突出显示此 post 以获得更多专家的关注。
所以我找到了解决方案。我总结如下。
对 docker-compose.yml
的调整包括向所有服务添加 network_mode: bridge
。这允许容器实质上访问外部世界。然而,这样做的代价是容器无法通过简单的服务名称引用自动相互对话。但这可以使用 links.
轻松解决
下一个调整是配置 DockerSpawner 以创建使用默认桥接网络而不是其他网络的容器。对此有帮助的设置包括:
c.DockerSpawner.network_name = 'bridge'
c.DockerSpawner.use_internal_ip = True
c.DockerSpawner.extra_host_config = {'network_mode': 'bridge'}
此外,由于笔记本无法使用服务名称发现主要的 JupyterHub,因此我将 c.JupyterHub.hub_connect_ip
调整为 JupyterHub 服务的主机名。请注意,使用我的问题中提到的 dns-proxy-server 有助于将主机名解析为容器 IP。
希望这对外面的人有所帮助。我很快就会 post 在我的博客上使用整个 Django-OAuth-JupyterHub 示例。
编辑:如上所述,我写了一篇博客 post 描述如何使用 Django 和 OAuth 使 JupyterHub 对用户进行身份验证。这是link:https://vkaustubh.github.io/blog/geek/2020-02-08-integrating-jupytethub-with-django.html
所以,这就是我想要实现的目标:
- 一个 Jupyterhub 服务器
- 当您访问但未登录时,会将您带到另一个 Web 服务器(使用 Django 自定义编码)
- 该网络服务器使用 OAuth 对用户进行身份验证
- 并生成一个笔记本容器。
- 此笔记本容器必须预先填充一个令牌,该令牌由烘焙到笔记本 Docker 图像中的自定义库使用,以针对服务进行身份验证。
- 笔记本容器需要能够与 Web 服务器通信,以便进行进一步的交互,例如检索结果等。
除最后一部分外,我或多或少做到了这一点。我正在启动一个笔记本服务器,但它无法访问外部世界。它只能访问 Jupyter Hub(这就是它工作的原因!),没有别的。
这是我的与 DockerSpawner 相关的 Jupyter Hub 配置(我省略了 OAuth 设置,因为它们按预期工作。
# Tell JupyterHub that we want Docker Spawner to be used.
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
# And what image should be used by the Docker Spawner
c.DockerSpawner.image = 'jupyter/scipy-notebook:7a0c7325e470'
# The Hub must listen on all interfaces.
c.JupyterHub.hub_ip = '0.0.0.0'
# And this should be the address of the Hub API
c.JupyterHub.hub_connect_ip = 'jupyterhub'
# Ask containers to connect to this network so that they can
# communicate with the Hub.
c.DockerSpawner.network_name = 'djangodockerjupyterdemo_default'
# And let's not make a mess, remove user containers when done.
c.DockerSpawner.remove = True
# We need to set the Notebook Directory
notebook_dir = '/home/jovyan/work'
c.DockerSpawner.notebook_dir = notebook_dir
# Need to tell where to mount the volumes.
c.DockerSpawner.volumes = { 'jupyterhub-user-{username}': notebook_dir }
请注意,djangodockerjupyterdemo_default
是由 docker-compose 创建的,这要归功于项目目录的名称。 (我知道这不是最好的做法,但现在我只是希望有一个最简单的例子。)
这是我的 docker-撰写:
version: "2"
services:
database:
image: "mysql:5.6"
volumes:
- ./data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=test123
- MYSQL_DATABASE=oauthserver
- MYSQL_USER=oauthadmin
- MYSQL_PASSWORD=test123
webapp:
image: auth_server:latest
volumes:
- ./:/app
links:
- database:database
environment:
- PYTHONUNBUFFERED=1
- ENV=DEV
- DATABASE_HOST=database
- DATABASE_USER=oauthadmin
- DATABASE_DBNAME=oauthserver
- DATABASE_PASSWORD=test123
hostname: oauthserver.ddi.in
jupyterhub:
image: "jupyterhub:test"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:rw"
- "./jupyterhub:/srv/jupyterhub"
environment:
- OAUTH2_AUTHORIZE_URL=http://oauthserver.ddi.in:8000/o/authorize
- OAUTH2_TOKEN_URL=http://oauthserver.ddi.in:8000/o/token/
hostname: jhtest.ddi.in
links:
- webapp:oauthserver.ddi.in
我用 https://hub.docker.com/r/defreitas/dns-proxy-server to access the JupyterHub server by saying "http://jhtest.ddi.in:8000"。
现在,一旦容器启动,我可以确认以下内容:
docker exec
进入webapp
或jupyterhub
容器,然后wget
从 Internet 上的某个地方下载文件。docker exec
进入生成的 Jupyter 笔记本容器并执行相同的操作不会。尝试从笔记本内部使用requests.get()
也是如此。
如何让生成的笔记本访问外界?这对我的用例至关重要(我确信这是一个合理的期望)。
PS:我注意到几乎没有任何示例涉及使用自定义 Django 应用程序设置 OAuth JupyterHub。我希望公开发布我的示例,并希望它可以构成 Jupyter Hub 文档中的资源。
您可能想在 Jupyter Discourse Forum 的 'JupyterHub' 类别下做一个非常简短的 post,突出显示此 post 以获得更多专家的关注。
所以我找到了解决方案。我总结如下。
对 docker-compose.yml
的调整包括向所有服务添加 network_mode: bridge
。这允许容器实质上访问外部世界。然而,这样做的代价是容器无法通过简单的服务名称引用自动相互对话。但这可以使用 links.
下一个调整是配置 DockerSpawner 以创建使用默认桥接网络而不是其他网络的容器。对此有帮助的设置包括:
c.DockerSpawner.network_name = 'bridge'
c.DockerSpawner.use_internal_ip = True
c.DockerSpawner.extra_host_config = {'network_mode': 'bridge'}
此外,由于笔记本无法使用服务名称发现主要的 JupyterHub,因此我将 c.JupyterHub.hub_connect_ip
调整为 JupyterHub 服务的主机名。请注意,使用我的问题中提到的 dns-proxy-server 有助于将主机名解析为容器 IP。
希望这对外面的人有所帮助。我很快就会 post 在我的博客上使用整个 Django-OAuth-JupyterHub 示例。
编辑:如上所述,我写了一篇博客 post 描述如何使用 Django 和 OAuth 使 JupyterHub 对用户进行身份验证。这是link:https://vkaustubh.github.io/blog/geek/2020-02-08-integrating-jupytethub-with-django.html