Django shell_plus:如何在Docker容器中访问Jupyter笔记本

8

我正在尝试从Docker容器访问使用django-extensions的shell_plus命令创建的Jupyter Notebook。

docker-compose -f local.yml run --rm django python manage.py shell_plus --notebook

我的配置基于@RobM和@Mark Chackerian在此Stack Overflow问题的答案。也就是说,我安装并配置了一个自定义内核,并且我的Django应用程序配置文件中有一个名为NOTEBOOK_ARGUMENTS的常量被设置为:

NOTEBOOK_ARGUMENTS = [
    '--ip', '0.0.0.0',
    '--port', '8888',
    '--allow-root',
    '--no-browser',
]

我可以在日志中看到容器成功启动:
[I 12:58:54.877 NotebookApp] The Jupyter Notebook is running at:
[I 12:58:54.877 NotebookApp] http://10d56bab37fc:8888/?token=b2678617ff4dcac7245d236b6302e57ba83a71cb6ea558c6
[I 12:58:54.877 NotebookApp]  or http://127.0.0.1:8888/?token=b2678617ff4dcac7245d236b6302e57ba83a71cb6ea558c6

但是我无法打开这个网址。 我在我的docker-compose中转发了端口8888,尝试使用localhost代替127.0.0.1,并且还尝试使用容器的IP地址,但都没有成功。
感觉我错过了一些显而易见的东西... 感谢任何帮助。
4个回答

22

为了记录2020年的情况,我成功地在docker-compose中使用PostgreSQL创建了一个工作的django设置:

development.py (settings.py)

INSTALLED_APPS += [
    "django_extensions",
]

SHELL_PLUS = "ipython"

SHELL_PLUS_PRINT_SQL = True

NOTEBOOK_ARGUMENTS = [
    "--ip",
    "0.0.0.0",
    "--port",
    "8888",
    "--allow-root",
    "--no-browser",
]

IPYTHON_ARGUMENTS = [
    "--ext",
    "django_extensions.management.notebook_extension",
    "--debug",
]

IPYTHON_KERNEL_DISPLAY_NAME = "Django Shell-Plus"

SHELL_PLUS_POST_IMPORTS = [ # extra things to import in notebook
    ("module1.submodule", ("func1", "func2", "class1", "etc")),
    ("module2.submodule", ("func1", "func2", "class1", "etc"))

]

os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" # only use in development 

requirements.txt

django-extensions
jupyter
notebook
Werkzeug  # needed for runserver_plus
...

docker-compose.yml

version: "3"

services:
  db:
    image: postgres:13
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
    restart: always
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data/
  web:
    build: .
    environment:
      - DJANGO_SETTINGS_MODULE=settings.development
    command:
      - scripts/startup.sh
    volumes:
      - ...
    ports:
      - "8000:8000" # webserver 
      - "8888:8888" # ipython notebook
    depends_on:
      - db

volumes:
  postgres_data:

从您的主机终端运行此命令:

docker-compose exec web python manage.py shell_plus --notebook

最后在主机的Web浏览器中导航到http://localhost:8888/?token=<xxxx>


1
关键部分是 NOTEBOOK_ARGUMENTS,并且需要将端口 8888 映射到容器外部(例如使用 -p 参数)。 - n1_
@n1_ 对于数据库语句,异步部分也是必要的。 - rowman
@n1_ 在 django 3.0 中需要。 - rowman
不要在 settings.py 中设置 DJANGO_ALLOW_ASYNC_UNSAFE,我建议把它移到 docker-compose exec -e DJANGO_ALLOW_ASYNC_UNSAFE=true web python manage.py shell_plus --notebook - dyz

3

搞定了,但它为什么能这样工作超出了我的理解。在docker-compose run命令中暴露端口是关键。

docker-compose -f local.yml run --rm -p 8888:8888 django python manage.py shell_plus --notebook

我原以为在 local.yml 中暴露的端口会在使用 run 启动的容器中同样开放。


我已经提供了一个包含 docker-composedjangonotebook 的 MWE。 - rowman
进行了重启,笔记本现在可以启动了。但是我用run解决方案仍然遇到了与之前相同的AppRegistryNotReady: Apps aren't loaded yet.错误。 - Jean Zombie
我猜我知道发生了什么事情。我也在Django之上使用Wagtail,我认为这就是问题的源头。在纯净的Django上运行你的解决方案可以正常工作。因此,我会接受你的答案;-) - Jean Zombie
我也在使用wagtail,它运行良好。不过,我对你收到的错误没有任何想法。 - rowman
啊,真的吗?好的,至少我知道这是可能的。我可以问一下你是否在你的模型中使用了ClusterableModel吗?我怀疑它可能是罪魁祸首... - Jean Zombie
显示剩余4条评论

1

默认情况下,compose run命令不会暴露定义的服务端口。文档来源:https://docs.docker.com/compose/reference/run/

The [...] difference is that the docker-compose run command does not create any of the ports specified in the service configuration. This prevents port collisions with already-open ports. If you do want the service’s ports to be created and mapped to the host, specify the --service-ports flag:

docker-compose run --service-ports web python manage.py shell 

因此,您需要运行

docker-compose -f local.yml run --rm --service-ports django python manage.py shell_plus --notebook

可能默认的8888端口已被本地jupyter服务器使用(例如由VS Code的jupyter笔记本实现启动的服务器)。因此,我通常在settings.py NOTEBOOK_ARGUMENTS列表中映射到不同的端口。(在这种情况下,当然需要调整compose文件中的端口映射,并且不能有另一个容器在后台运行,其服务定义与此相同,因为这也可能占用端口。)


0
如果您想将Jupyter Notebook用作独立服务:
jupyter_notebook:
  build:
    context: .
    dockerfile: docker/dev/web/Dockerfile
  command: python manage.py shell_plus --notebook
  depends_on:
    - web
  ports:
  - 8888:8888 # ipython notebook
  env_file:
    - .env

之后:

docker-compose logs -f 'jupyter_notebook'

然后你将在日志中获得访问令牌


嗨,bandirom。请详细解释一下你的答案。我们应该如何处理你答案中提供的YAML?为什么这样做有助于打开原帖作者试图打开的URL?看起来原帖作者已经拥有访问令牌,但无法打开URL。 - Seth Difley
嗨@SethDifley!您可以在docker-compose.yml中像服务一样为您的笔记本创建单独的实例。 - bandirom
在上面的回答中,您应该手动启动Jupyter。而在这个解决方案中,您已经有一个运行的笔记本了。 - bandirom

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