如果使用 8888,配置 Docker 以动态选择第一个可用的 Jupyter 端口

Configure Docker to dynamically choose first available Jupyter port if 8888 is taken

tl;dr 如果 8888 端口被占用,有没有办法配置我们的 Dockerfile and/or docker run 命令为 Jupyter 动态选择下一个可用端口?

我们有一个 Docker,用户可以在其中 运行 Jupyter 笔记本。但是,当用户已经打开现有的 Jupyter 服务器时,我们会 运行 遇到问题。原因是因为,当他们 运行 Docker 时,它默认为端口 8888。如果另一个本地 Jupyter 服务器具有端口 8888,则 Docker Jupyter link 从 docker run 将不起作用(它会显示一些令牌身份验证屏幕,但它接受的唯一令牌是与其本地 Jupyter 服务器关联的令牌,而不是与我们的 Docker 关联的令牌)。

我们尝试将 start_docker.sh 脚本(用户将 运行 bash start_docker.sh 启动 Docker)更改为:

# find lowest open port available
PORT=8888

until [[ $(lsof -i -P -n | grep 127.0.0.1:$PORT | wc -l) -eq 0 ]]
  do
    ((PORT=PORT+1))
done

echo $PORT

# run docker and start notebook server
docker run -it \
  -p $PORT:8888 \
  -v ...
  ...

但是,在这种情况下,Jupyter 仍然在端口 8888 上打开,而不是在所需的 $PORT 计算上。

在我们的 Docker 文件中,我们的 Jupyter 配置设置是:

# jupyter notebook
CMD ["jupyter", "notebook", "--ip=0.0.0.0", "--allow-root"]

我们显然可以尝试添加参数 --port=8889(或其他一些硬编码端口),但如果用户也有使用指定端口的本地进程,那可能会出现问题。

是否可以配置这个,或者我们是否必须坚持用户在启动我们的 Docker 时没有任何使用端口 8888 的东西?

如果您 运行 docker run -p 只有一个端口号,Docker 会选择主机端口。然后您可以使用 docker port 找到它选择的实际主机端口。

# Start the container.
#
# Start it _in the background_, since we need to probe the dynamically
# assigned port.
#
# If we expect to have arbitrarily many of these containers, we also
# can't assign a fixed --name, so depend on `docker run -d` printing the
# container ID.
#
# Note only one port number `-p 8888` to let Docker pick the host port.
cid=$(docker run -d -i -t -p 8888 ...)

# Print out the port number
echo -n "Listening on "
docker port "$cid" 8888

# Wait for the container to exit on its own
docker wait "$cid"

# Clean up
docker rm "$cid"

请注意,docker port 输出包括绑定地址,通常是 0.0.0.0。这不是您实际可以用来到达容器的地址。您需要知道主机的 IP 地址,或者在某些环境中,您可能已经在系统前面配置了负载平衡器或其他网关。 Docker 不知道这些细节。