项目一:
项目要求README:
# Docker 训练营项目指南
## 项目概述
本结业项目旨在通过构建一系列渐进式的 Jupyter 环境,帮助你掌握 Docker 容器化技术在数据科学平台搭建中的应用。项目分为四个阶段,每个阶段都会增加新的功能和复杂度,让你逐步应用所学的 Docker 知识。
- **阶段 1-3**: 基本要求,完成这些阶段即可达到及格标准 - **阶段 4**: 进阶要求,完成此阶段可获得优秀评价
## 项目结构
. ├── 01-single-container/ # 阶段1: 单用户 Jupyter 环境 ├── 02-jupyterhub/ # 阶段2: 基础多用户环境 ├── 03-jupyterhub-github-auth/ # 阶段3: GitHub 认证集成 └── 04-jupyterhub-ai-enhanced/ # 阶段4: AI 增强版本(优秀要求)
## 阶段 1: 单容器 Jupyter 环境
### 目标
构建一个基于 Docker 的单用户 Jupyter Notebook 环境,适合个人数据分析和学习使用。
### 需要完成的任务
1. 创建一个基于 Python 数据科学镜像的 Dockerfile 2. 配置 docker-compose.yml 文件实现容器编排 3. 实现数据持久化存储 4. 添加示例数据和欢迎笔记本
### 技术要点
- Docker 基础命令 - Dockerfile 编写 - Docker Compose 基础配置 - 数据卷(Volumes)挂载 - 端口映射
### 参考资源
- [Jupyter Docker Stacks 文档](https://jupyter-docker-stacks.readthedocs.io/) - [Docker Compose 文档](https://docs.docker.com/compose/) - [Dockerfile 最佳实践](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
### 提示
- 使用官方的 `jupyter/scipy-notebook` 或 `jupyter/datascience-notebook` 作为基础镜像 - 注意配置正确的工作目录和权限 - 使用 Docker Compose 的 volumes 配置实现数据持久化 - 确保 Jupyter 服务可以通过浏览器访问
## 阶段 2: JupyterHub 多用户环境
### 目标
构建一个支持多用户的 JupyterHub 环境,每个用户拥有独立的工作空间。
### 需要完成的任务
1. 创建 JupyterHub 的 Dockerfile 2. 配置 docker-compose.yml 实现多容器编排 3. 编写 jupyterhub_config.py 配置文件 4. 实现用户数据的持久化 5. 添加基本的系统测试
### 技术要点
- Docker 网络配置 - Docker Compose 多服务编排 - JupyterHub 配置 - DockerSpawner 使用 - 容器间通信
### 参考资源
- [JupyterHub 文档](https://jupyterhub.readthedocs.io/) - [DockerSpawner 文档](https://jupyterhub-dockerspawner.readthedocs.io/) - [Docker 网络配置](https://docs.docker.com/network/)
### 提示
- 使用 DockerSpawner 为每个用户创建独立容器 - 配置 Docker 网络使 JupyterHub 能与用户容器通信 - 使用命名卷为每个用户提供持久化存储 - 注意容器的资源限制配置
## 阶段 3: GitHub 认证集成
### 目标
为 JupyterHub 环境添加 GitHub OAuth 认证,提高系统安全性和用户管理能力。
### 需要完成的任务
1. 配置 GitHub OAuth 应用 2. 更新 jupyterhub_config.py 添加认证配置 3. 使用环境变量管理敏感信息 4. 实现用户权限管理
### 技术要点
- OAuth 认证流程 - Docker 环境变量配置 - Docker Secrets 管理 - JupyterHub 认证插件配置
### 参考资源
- [OAuthenticator 文档](https://oauthenticator.readthedocs.io/) - [GitHub OAuth 应用创建指南](https://docs.github.com/en/developers/apps/building-oauth-apps) - [Docker 环境变量](https://docs.docker.com/compose/environment-variables/) - [Docker Secrets](https://docs.docker.com/engine/swarm/secrets/)
### 提示
- 创建 .env.example 文件作为环境变量模板 - 使用 GitHub 的 OAuth 应用设置正确的回调 URL - 配置管理员用户和访问控制 - 注意保护 OAuth 密钥和令牌
## 阶段 4: AI 增强版本(优秀要求)
### 目标
构建一个集成多种 AI 工具和模型的高级 JupyterHub 环境,支持 AI 辅助编程和数据分析。
### 需要完成的任务
1. 创建支持 AI 工具的自定义 Notebook 镜像 2. 配置多种 AI 模型(国际和国内)的接入 3. 添加 AI 示例笔记本 4. 实现资源限制和管理 5. 编写详细的使用文档
### 技术要点
- 高级 Dockerfile 多阶段构建 - Docker Compose profiles 配置 - 容器资源限制 - API 密钥管理 - 多容器协作 - 高级网络配置
### 参考资源
- [Jupyter AI 文档](https://jupyter-ai.readthedocs.io/) - [Docker 多阶段构建](https://docs.docker.com/build/building/multi-stage/) - [Docker Compose Profiles](https://docs.docker.com/compose/profiles/) - [容器资源限制](https://docs.docker.com/config/containers/resource_constraints/) - [各 AI 服务提供商 API 文档] - [OpenAI API](https://platform.openai.com/docs/api-reference) - [Anthropic API](https://docs.anthropic.com/claude/reference/getting-started-with-the-api) - [阿里云百炼 API](https://help.aliyun.com/document_detail/2400152.html) - [DeepSeek API](https://platform.deepseek.com/docs)
### 提示
- 使用 Docker Compose profiles 分离构建和运行环境 - 创建启动和停止脚本简化操作 - 为不同的 AI 模型提供配置选项 - 添加详细的示例和教程 - 考虑国内用户的网络环境,提供替代方案
## 提交要求
1. 完整的源代码,包含所有 Dockerfile、docker-compose.yml 和配置文件 2. README.md 文件,包含项目说明和使用指南
## 实施建议
1. **循序渐进**: 按照阶段顺序完成项目,每个阶段都建立在前一个阶段的基础上 2. **参考官方文档**: 优先参考官方文档解决问题 3. **版本控制**: 使用 Git 管理代码,每个阶段完成后提交一次 4. **测试验证**: 每完成一个功能就进行测试,确保其正常工作 5. **记录问题**: 记录遇到的问题和解决方案,作为报告的一部分
祝你在项目中取得好成绩!如有任何问题,请随时向导师咨询。
|
阶段一: 单容器 Jupyter 环境
写完compose和dockerfile运行之后发现容器直接退出了,想到查看容器日志:
docker logs 01-single-container-jupyterhub-1
|
发现
[W 2025-07-18 06:08:00.476 ServerApp] notebook_shim | error linking extension: [Errno 13] Permission denied: '/home/jovyan/.local/share' ... PermissionError: [Errno 13] Permission denied: '/home/jovyan/.local/share'
|
这里猜测可能是权限报错,因此回去检查dockerfile文件的权限问题,并把dockerfile文件的内容丢给了AI
发现可能有一个有问题的点:
USER root
USER $NB_UID
WORKDIR /home/jovyan/work
COPY requirements.txt /tmp/requirements.txt RUN pip install ... RUN mkdir -p ... RUN jupyter lab --generate-config ...
|
AI回答说:
$NB_UID 是 Jupyter 基础镜像在容器运行时(通过 start-notebook.sh 脚本)才会设置的环境变量。在构建镜像时(即 docker build 或 docker compose build 期间),这个变量是不可用的。因此,USER $NB_UID 这条指令很可能会失效,导致后续的所有 RUN, COPY 等指令仍然是以 root 用户的身份执行的。
因此修改dockerfile文件,通过添加 chown 命令:在所有需要 root 权限的操作完成后,通过 chown 命令将 /home/jovyan 目录的所有权交还给 jovyan 用户。
RUN mkdir -p /home/jovyan/work && \ chown -R ${NB_UID}:${NB_GID} /home/jovyan/
但是,修改完成后重新docker compose up -d --build
后发现容器还是直接退出了,再次回去logs查看日志,发现这次还是文件权限的问题,不满足于之前的测试,AI向我提供了一个新的测试方案:
步骤二:进入容器进行交互式调试
如果日志信息不够明确,或者你想亲自动手检查,可以按以下步骤操作。这个过程不需要 docker compose down
。
启动一个临时的、可交互的容器:
在你的 01-single-container
目录下,运行以下命令:
docker compose run --rm jupyter /bin/bash
|
* docker compose run
: 这个命令会为 compose.yml
文件中定义的服务(这里是 jupyter
)创建一个新的临时容器,并运行你指定的命令。
* --rm
: 表示当容器退出时,自动删除它。非常适合一次性的调试任务。
* jupyter
: 这是你在 compose.yml
文件里定义的服务名称。
* /bin/bash
: 这是我们要运行的命令。它会覆盖 Dockerfile
中默认的 CMD ["start-notebook.sh", ...]
,转而启动一个 Bash 交互式命令行。
在容器内部进行检查:
运行上述命令后,你的终端提示符会变成类似 jovyan@<container_id>:/home/jovyan/work$
的样子,这表示你已经成功进入了容器内部。现在,你可以像在普通的 Linux 系统里一样进行检查:
* 检查当前用户:运行 whoami
。输出应该是 jovyan
,这表示用户切换是成功的。
* 检查文件权限:运行 ls -la /home/jovyan
。检查该目录下的文件和文件夹(特别是 .local
, .jupyter
)的所有者是不是 jovyan users
。这是为了验证我们之前在 Dockerfile
里加的 chown
命令是否生效。
* 手动执行启动命令:这是最关键的一步。直接在命令行里运行 Dockerfile
里的启动脚本,看看会输出什么:
/usr/local/bin/start-notebook.sh --ServerApp.token='' --ServerApp.password=''
|
因为你是在交互式终端里直接运行它,任何错误都会立刻打印在你的屏幕上,这样就能非常直观地定位问题。
之后我通过docker run -rm jupyter bash
进入容器内部,检查当前用户:运行 whoami
。输出确定是 jovyan
,这表示用户切换是成功的。之后我检查文件权限:运行 ls -la /home/jovyan
。检查该目录下的文件和文件夹(特别是 .local, .jupyter)的所有者是不是 jovyan users
。发现.jupyter
的所有者是jovyan user
但是.local
的所有者还是root,之后我手动执行启动命令:直接在命令行里运行 Dockerfile 里的启动脚本/usr/local/bin/start-notebook.sh --ServerApp.token='' --ServerApp.password=''
。得到输出跟我前面运行容器是一样的,得到权限的报错:PermissionError: [Errno 13] Permission denied: '/home/jovyan/.local/share'
这导致我考虑到是不是另一个yml文件有问题,我找到docker compose文件查看有关权限设置的地方,发现有一段挂载卷的内容涉及到了.local
文件,同时AI也回答说当你在 docker-compose.yml
中使用命名卷(如 jupyter_packages
)并将其挂载到容器的某个目录(如 /home/jovyan/.local
)时,Docker 会在宿主机上创建一个由 root
用户拥有的目录来管理这个卷。这个 root
权限会覆盖掉你在 Dockerfile 中为 jovyan
用户设置的权限,导致容器内的 jovyan 用户无法写入这些目录。
volumes:
- jupyter_packages:/home/jovyan/.local
- jupyter_config:/home/jovyan/.jupyter
|
正确的做法是只挂载你需要持久化的工作数据(比如你的 notebook 文件和数据集),而不要挂载用户的配置文件或软件包安装目录。软件包应该构建在镜像里,配置文件让容器自己管理。
修改为:
volumes: - ./notebooks:/home/jovyan/work/notebooks - ./data:/home/jovyan/work/data
|
之后我们再运行docker compose up -d --build
,容器终于成功运行了!
到此为止我们该项目的阶段一:构建一个单容器的Jupyter环境就完成了!

阶段二:JupyterHub 多用户环境:
阶段任务:
### 目标
构建一个支持多用户的 JupyterHub 环境,每个用户拥有独立的工作空间。
### 需要完成的任务
1. 创建 JupyterHub 的 Dockerfile 2. 配置 docker-compose.yml 实现多容器编排 3. 编写 jupyterhub_config.py 配置文件 4. 实现用户数据的持久化 5. 添加基本的系统测试
### 技术要点
- Docker 网络配置 - Docker Compose 多服务编排 - JupyterHub 配置 - DockerSpawner 使用 - 容器间通信
### 参考资源
- [JupyterHub 文档](https://jupyterhub.readthedocs.io/) - [DockerSpawner 文档](https://jupyterhub-dockerspawner.readthedocs.io/) - [Docker 网络配置](https://docs.docker.com/network/)
### 提示
- 使用 DockerSpawner 为每个用户创建独立容器 - 配置 Docker 网络使 JupyterHub 能与用户容器通信 - 使用命名卷为每个用户提供持久化存储 - 注意容器的资源限制配置
|
JupyterHub是什么?
JupyterHub 是一个轻量级的工具,用于部署多个 Jupyter Notebook 服务器,每个用户都可以有自己的独立工作空间。这使得团队成员能够在共享的基础设施上进行协作,同时也为教育机构提供了强大的教学平台。
JupyterHub 的特点:
1.多用户支持:允许多个用户同时使用 Jupyter Notebook。
2.资源管理:根据用户需求动态分配资源。
3.安全性:提供多种认证机制。
4.可扩展性:可以根据需要增加或减少服务器资源。
很符合该阶段的一些要求,同时提示中还提到了DockerSpawn
1.项目基础介绍和主要编程语言
DockerSpawner 是一个开源项目,旨在帮助 JupyterHub 在 Docker 容器中启动单用户笔记本服务器。该项目的主要编程语言是 Python,它充分利用了 Python 的灵活性和强大的生态系统来实现其功能。
2.项目的核心功能
DockerSpawner 的核心功能包括:
DockerSpawner: 为经过身份验证的用户在 Docker 容器中启动单用户笔记本服务器。
SwarmSpawner: 在 Docker Swarm 模式下将单用户笔记本服务器作为服务启动。
SystemUserSpawner: 启动与系统用户对应的单用户笔记本服务器。
这些功能使得 JupyterHub 能够更高效地管理和扩展其用户环境,特别是在需要隔离和资源管理的情况下。
之后我把任务要求发给AI让AI先帮我初步实现一个代码
以下是AI实现这个目标生成的三个文件。
1. 02-jupyterhub/Dockerfile
- JupyterHub 服务的构建蓝图
首先,我们需要一个 Dockerfile
来构建 JupyterHub 服务本身。这个镜像将包含 JupyterHub、DockerSpawner 以及运行它们所需的环境。
在 02-jupyterhub/
目录下创建 Dockerfile
文件,内容如下:
FROM python:3.10-slim
RUN pip install --no-cache-dir jupyterhub dockerspawner
COPY conf/jupyterhub_config.py /srv/jupyterhub/jupyterhub_config.py
EXPOSE 8000
CMD ["jupyterhub", "-f", "/srv/jupyterhub/jupyterhub_config.py"]
|
文件解析:
FROM python:3.10-slim
: 我们选择了一个轻量级的 Python 官方镜像作为基础。
RUN pip install ...
: 安装了两个核心的 Python 包:jupyterhub
(Hub 服务本身)和 dockerspawner
(让 Hub 能够与 Docker 交互的插件)。
COPY conf/...
: 将我们本地的配置文件 jupyterhub_config.py
复制到容器内的指定位置,以便启动时使用。
CMD ["jupyterhub", ...]
:定义了容器启动时要执行的命令,即用我们提供的配置文件来启动 JupyterHub 服务。
2. 02-jupyterhub/compose.yml
- 多容器编排文件
这个文件是整个多用户系统的“总指挥”,负责定义和连接所有服务。
文件内容 (02-jupyterhub/compose.yml
):
services: jupyterhub: build: context: . dockerfile: Dockerfile container_name: jupyterhub volumes: - "/var/run/docker.sock:/var/run/docker.sock" ports: - "8000:8000" networks: - jupyterhub_network environment: HUB_NETWORKS_NAME: jupyterhub_network DOCKER_JUPYTER_IMAGE: quay.io/jupyter/scipy-notebook:latest USER_MEM_LIMIT: 4G USER_CPU_LIMIT: 4 HUB_ACTIVE_SERVER_MAX: 4 HUB_ADMIN_USER: yiqiu
networks: jupyterhub_network: name: jupyterhub_network driver: bridge
|
文件解析:
build:
: 指示 Docker Compose 使用我们刚刚创建的 Dockerfile
来构建 jupyterhub
服务的镜像。
volumes: - "/var/run/docker.sock:/var/run/docker.sock"
: 这是实现 DockerSpawner 功能的核心。它将你本地主机的 Docker 套接字文件 (docker.sock
) 挂载到容器内部。这使得 JupyterHub 容器可以“命令”主机上的 Docker 来创建、管理其他容器(即每个用户的 Jupyter 容器)。
ports: - "8000:8000"
: 将 JupyterHub 的登录页面端口映射到本地,这样你就可以通过 http://localhost:8000
访问。
networks:
: 创建了一个名为 jupyterhub_network
的自定义桥接网络。所有由 Hub 生成的用户容器都会被连接到这个网络,确保它们之间以及它们与 Hub 之间可以顺畅通信。
environment:
: 通过环境变量传入配置,增加了灵活性。
DOCKER_JUPYTER_IMAGE
: 指定了为每个用户创建容器时所使用的单用户 Jupyter 镜像。这里我们直接使用了官方的 scipy-notebook
镜像。
HUB_ADMIN_USER
: 定义了管理员用户的名称,这个值会被 jupyterhub_config.py
读取。
3. 02-jupyterhub/conf/jupyterhub_config.py
- JupyterHub 核心配置
这个 Python 脚本定义了 JupyterHub 的所有行为。
文件内容 (02-jupyterhub/conf/jupyterhub_config.py
):
import os c = get_config()
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
c.DockerSpawner.image = os.environ['DOCKER_JUPYTER_IMAGE']
c.DockerSpawner.network_name = os.environ['HUB_NETWORKS_NAME'] c.JupyterHub.hub_ip = '0.0.0.0' c.JupyterHub.hub_connect_ip = 'jupyterhub'
data_dir = os.environ.get('DATA_VOLUME_CONTAINER', '/home/jovyan/work') c.DockerSpawner.volumes = { 'jupyterhub-user-{username}': data_dir }
c.DockerSpawner.remove_containers = True
c.JupyterHub.authenticator_class = 'jupyterhub.auth.DummyAuthenticator'
admin_name = os.environ['HUB_ADMIN_USER'] c.Authenticator.admin_users = [admin_name] c.DummyAuthenticator.admin_users = [admin_name]
c.JupyterHub.services = [ { 'name': 'idle-culler', 'command': ['python3', '-m', 'jupyterhub_idle_culler', '--timeout=360'], 'admin': True, } ]
|
docker compose up -d --build
后容器服务运行成功了。
但是当我测试页面的时候发现jupyterhub输入账号密码后页面没有跳转,还是停留在需要输入账号密码的页面,因此我们需要再次查看日志寻找出错原因。
之前的日志是我们解决“容器无法启动”问题的,现在容器已经启动了,我们需要在尝试登录的那一刻看看后台发生了什么,因此应该使用docker logs -f jupyterhub
命令来查看日志。
-f: (follow)
参数,它会让命令持续运行,并实时打印出所有新的日志,就像看直播一样。
之后我们再次尝试输入账号密码查看日志输出的结果:

项目二:
任务要求:
官方要求
- 您需要按照原始项目说明在 CNB 云原生开发平台中将项目运行起来
- 您需要确保启动后的服务功能正常可用,可以正常进行 RAG 问答。
- 确保整个 docker compose 启动服务时间尽可能短。
- 系统提供默认账号 (admin / Admin123),登录后可以体验问答功能。
- 如果您对 RAG 领域有兴趣,也可以对项目进项二次开发,完成你想做的功能【可选】。