找回密码
 立即注册
首页 业界区 安全 Minikube 本地部署 Jupyter 集群

Minikube 本地部署 Jupyter 集群

鸳剿 2025-8-1 16:07:23
背景

Jupyter 是兼备优秀的编程体验和交互体验的在线 IDE,它能让你的代码不再受限于自己的电脑环境,也不只是编程语言本身,而是可以结合数学公式、Markdown、命令行等各种语法和指令,在更高性能的服务器以更灵活的交互方式,随处运行,随时可见结果。也正因为这些特性,它在教学、大数据分析、机器学习等领域都能助开发者一臂之力

在最近一年维护和使用 Jupyter 服务的过程中,我部署 Jupyter 的方式也经历了从 linux 服务器单点,到 minikube 本地部署模拟集群,再到生产环境 k8s 正式部署集群的升级过程。之所以要将 Jupyter 从单点升级成集群,主要是为了解决单点会遇到的可靠性、可扩展性和可维护性等问题

上面的问题要解决,首先需要一套可以管理集群的基础服务,这个服务就是 Kubernetes ,而借助 Jupyter 官方提供的 helm chart,几行配置几条指令,就可以部署成集群了,“理论上”整个过程可以非常顺滑
当然,上线生产之前必不可少的过程是测试。在这篇文章中,我们就以自己电脑作为基本环境,借助 minikube 和 k8s 生态下的工具, 部署一套类似生产环境的 Jupyter
事不宜迟,让我们先从了解 Jupyter 服务开始,一步步深入了解如何在本机玩转 Jupyter 集群吧
Jupyter 生态

Jupyter 在组件通信、页面交互和后台运行环境上,都具有各司其职的组件,这也形成了 Jupyter 独一无二的生态

图片来源若从最关键的用户使用场景入手,最重要的组件有以下四个:

  • JupyterHub: 登录页面,只提供简单的用户信息输入框( 不过默认的 Spawner 和 Authticator 也在其源码中 )
  • JupyterLab: 新一代的 Notebook 编辑器,界面功能更丰富,且支持通过插件系统扩展更多功能(如 git、资源查看器等)
  • Spawner: 登录 JupyterHub 后实际运行的 IDE(主要是 Notebook 或者 JupyterLab ),IDE 可以自定义运行环境: 跑在本地、 k8s 或者 yarn 等等。一个用户 IDE 进程也可以称作 Jupyter Server
  • Ipykernel: 用户运行每一个 Notebook,又会在 Spawner 运行的服务器上启动一个个负责运行代码的进程。它既是进程,也是服务器上预装的不同开发环境( 比如可选择在不同 Python 版本作为运行代码的环境 )
只是简单介绍这些组件的概念,并不能讲清楚它们之间的协同和交互机制。相信通过接下来的实践,它们各自的发挥的作用都会在我们面前清晰展现出来
环境准备

既然要在 k8s 部署 Jupyter,第一步当然需要把 k8s 先启动起来
在自己电脑启动 k8s 可选的工具有 minikube, kind, k3s, microk8s 等,它们实际启动集群的过程是差不多的。这里笔者从功能的完善程度考虑,选择了 minikube
在文章最后会提到 k3s 也可作为在电脑资源受限情况下的备选
minikube

minikube 是一个在本地快速启动 k8s 集群的工具,由 kubernetes 社区开源,支持多种虚拟化运行环境(Docker、Hyper-V、VirtualBox、podman 等)。它基于一个轻量级虚拟机 coreboot 启动,因此 minikube 也支持跨平台
minikube 可执行文件可以直接从 官方仓库 或者 官方网站 下载
Docker 镜像源配置

注: 由于 minikube 网络插件的依赖,会导致非 root 权限运行的 podman 无法启动 minikube,笔者为测试 root 的 podman,目前还是建议使用 Docker
Docker 的具体的安装方式这里就不赘述了。不过还是要提一下镜像源的配置
网易云、中科大等之前常用的比较官方的镜像源现在都用不了,其他第三方可用的镜像源可以 参考这里 或 这里, 目前可用的部分镜像源如下:
  1. // vim /etc/docker/daemon.json
  2. {
  3.     "registry-mirrors": [
  4.         "https://docker-0.unsee.tech",
  5.         "https://docker.1ms.run",
  6.         "https://docker.m.daocloud.io"
  7.         "https://docker.xuanyuan.me",
  8.     ]
  9. }
复制代码
注: 一切网络问题都不是等等就能好的,再等也是浪费时间,这也是在开始就要把国内镜像源这种信息告诉大家的原因
minikube 安装和启动

启动 minikube 遇到的第一个坑,就是经典的国内网络问题: 下载镜像和二进制文件时不太顺畅
首先 minikube 运行的基础系统镜像 kicbase 会按照 docker.io、 gcr.io 和 github release 的顺序尝试下载。然而这些下载地址都在外网,都可能下载不成功
其次,minikube 还会下载 kubectl, kubelet 和 kubeadm 这三个用于访问和管理 k8s 集群的可执行文件(下载后放在虚拟机内部)在设置了 image-mirror-country=cn 参数后,下载地址会被替换成 kubernetes.oss-cn-hangzhou.aliyuncs.com,但是这个地址并没有提供这些文件,所以还需要配置正确的 binary-mirror 参数
(不得不说坑是真的多啊)
正是因为有这些问题,建议通过源码编译来生成 minikube 二进制文件,方便快速修正镜像下载问题
  1. # linux 下载 minikube
  2. curl -LO https://github.com/kubernetes/minikube/releases/download/v1.36.0/minikube-linux-amd64
  3. # windows
  4. curl -LO https://github.com/kubernetes/minikube/releases/download/v1.36.0/minikube-windows-amd64.exe
  5. # github 加速
  6. curl -LO https://ghfast.top/https://github.com/kubernetes/minikube/releases/download/v1.36.0/minikube-linux-amd64
  7. curl -LO https://ghfast.top/https://github.com/kubernetes/minikube/releases/download/v1.36.0/minikube-windows-amd64.exe
  8. # 安装 minikube
  9. sudo install minikube-linux-amd64 /usr/local/bin/minikube
  10. # 通过源码编译 minikube
  11. git clone https://github.com/kubernetes/minikube
  12. git checkout tags/v1.36.0
  13. ## 替换 docker.io/kicbase/stable 下载镜像源
  14. sed -i "s#"docker.io/#"docker.1ms.run/#g" pkg/drivers/kic/types.go
  15. ## 编译
  16. make
  17. mv out/minikube /usr/local/bin/
  18. # 启动 k8s 1.33.1 版本
  19. minikube start --kubernetes-version=v1.33.1
  20. # “最终版”启动 k8s 参数 (适配国内网络)
  21. # --v 和 --log_file: 增加日志输出,并打印到指定日志文件中,方便定位问题
  22. minikube start --kubernetes-version=v1.33.1 --iso-url https://ghfast.top/https://github.com/kubernetes/minikube/releases/download/v1.35.0/minikube-v1.35.0-arm64.iso   --image-mirror-country=cn --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers --binary-mirror https://files.m.daocloud.io/dl.k8s.io/release --v=8 --log_file /tmp/test.log
  23. # 扩展: 限定运行资源、磁盘大小等
  24. minikube start --cpus=2 --memory=4096 --disk-size=20g ...
  25. # 扩展: 指定镜像下载路径
  26. export MINIKUBE_HOME=/opt/minikube
复制代码
顺利启动 minikube 后,我们在命令行可以通过 minikube 虚拟机内部的 kubectl 来访问集群,或者为了操作更方便可以在主机也安装 kubectl( minikube 启动时已经在本机设置好了 ~/.kube/config )
  1. # kubectl 安装
  2. curl -LO https://dl.k8s.io/release/v1.33.0/bin/linux/amd64/kubectl
  3. curl -LO https://dl.k8s.io/release/v1.33.0/bin/windows/amd64/kubectl.exe
  4. # 国内源
  5. curl -LO https://files.m.daocloud.io/dl.k8s.io/release/v1.33.0/bin/linux/amd64/kubectl
  6. curl -LO https://files.m.daocloud.io/dl.k8s.io/release/v1.33.0/bin/windows/amd64/kubectl.exe
  7. # 或者通过 k8s 源码安装
  8. git clone https://github.com/kubernetes/kubernetes
  9. make kubectl
  10. mv _output/local/bin/linux/amd64/kubectl /usr/local/bin
  11. # 获取所有 pod
  12. kubectl get pods --all-namespaces
  13. # 使用 minikube 自带的 kubectl
  14. minikube kubectl -- get pods --all-namespaces
复制代码
通过 kubectl get pods -A 查看所有 pod,可以看到 minikube 启动了一套标准的 k8s 组件,简单说明每个组件的作用

图片来源

  • CoreDNS: k8s 集群内部的 DNS 服务,负责提供 k8s 内服务的访问地址,前身是 kube-dns,现在发展成 CNCF(Cloud Native Community Foundation 云原生基金会) 中的独立项目
  • ETCD: k8s 的元数据服务,记录了当前集群的所有节点、配置、服务、密钥等等信息
  • kube-apiserver: 提供k8s资源( pod, deployment, service 等)的 restful api 接口
  • kube-controller-manager: 通过 api 对集群资源进行管理和控制,在资源出现异常的时候自动恢复
  • kube-proxy: 在每个 k8s 节点(node)上运行,负责 监测 apiserver 收到的用户请求,并将请求转发到具体的 Pod 进行处理
  • kube-scheduler: 负责将 Pending 状态的 pod 分配到最合适的 node 上运行
  • storage-provisioners: 在服务需要挂载存储目录的时候,自动从本地分配一块目录空间给服务使用
dashboard

dashboard 是 kubernetes 官方提供的 k8s 集群看板,通过它能够看到集群的基本状态、资源、日志等,尽管功能简单,还是建议在首次启动时候打开它,方便后续查看 pod 日志定位问题
minikube 内置 dashboard, 执行 minikube dashboard 即可打开


helm

在不使用 k8s,只用 docker 如何启动,最简单的方案通常会用到 docker compose,在 docker-compose.yaml 配置文件中编写集群每个节点部署的服务和配置,比如 flink 的官方示例,一个 jobmanager 和一个 taskmanager 组成的集群

但这种方式对于生产环境部署大规模集群的目标,就有点力所不及了。自动发现和恢复故障节点、自动扩缩容、动态升级和配置变更等方面的支持,还是 k8s 更擅长
当然 k8s 这套生态的门槛也比较高,相关的组件和配置也更多,如何在 k8s 也像 docker compose 一样能丝滑一键启动集群呢?Helm 就是我们的答案
Helm 是 CNCF 社区孵化的集群服务编排和部署工具,它将一个服务在 k8s 部署需要的服务以及依赖的资源,抽象成了可以通过 golang template 批量生成的配置,配置的格式也统一为 yaml
从 2016 年发展至今,Helm 已经成为了在 k8s 平台管理服务发行包和发布服务的主流标准
Helm 的几个概念这里也简单介绍下,稍做了解就好

  • chart: 服务定义,包括服务名、服务版本、依赖 k8s 版本
  • value: 启动服务所需所有资源的配置默认值,可在启动时加上 -f new.yaml 覆盖默认配置文件
  • template: k8s 相关资源( deployment, service, pvc, configmap 等)的配置模板,和 values 结合生成完整的资源清单
  • release: chart 可以发布到 k8s 的版本
  • repo: 用于存放所有 chart release 打包文件的服务器

图片来源大部分支持云原生的开源组件,官方都会提供 Helm chart,让我们只修改少量的配置,即可完成集群部署
Helm 的安装也非常简单,只需下载一个二进制文件
  1. # linux
  2. curl -LO https://get.helm.sh/helm-v3.18.2-linux-amd64.tar.gz
  3. # mac
  4. brew install helm@stable
  5. curl -LO https://get.helm.sh/helm-v3.18.2-darwin-arm64.tar.gz
  6. # windows
  7. choco install kubernetes-helm
  8. https://get.helm.sh/helm-v3.18.2-windows-amd64.zip
复制代码
Jupyter

环境准备工作终于万事俱备,各位久等,我们终于要来启动 Jupyter 服务了
这里我们需要用到 Jupyter 官方提供的 chart zero-to-jupyterhub-k8s
启动服务
  1. # 在本地添加 jupyter 官方 repo
  2. helm repo add jupyterhub https://hub.jupyter.org/helm-chart
  3. helm repo update
  4. # 启动
  5. # vim start.sh
  6. RELEASE=jhub
  7. NAMESPACE=jhub
  8. VERSION=4.2.0
  9. # 彻底清理上次启动 Jupyter 的所有资源
  10. helm uninstall ${RELEASE} -n ${NAMESPACE}
  11. kubectl delete daemonsets,replicasets,services,deployments,pods,jobs,rc,ingress,persistentvolumes,persistentvolumeclaims --all --namespace=jhub
  12. # 将 Jupyter 组件安装到 jhub 的命名空间(namespace)下
  13. helm upgrade --cleanup-on-fail \
  14.   --install $RELEASE jupyterhub/jupyterhub \
  15.   --namespace $NAMESPACE  \
  16.   --create-namespace \
  17.   --timeout 600s \
  18.   --version $VERSION
复制代码
成功启动后查看 jhub 这个 namespace 下相关的 pod 如下:

默认方式启动后,再通过执行 minikube service proxy-public -n jhub --url ,即可随机开放一个端口以供访问 JupyterHub 登录页面了

Hub 默认使用 DummyAuthenticator 作为用户登录校验器 ( values.yaml 中的 hub.config.JupyterHub.authenticator_class 默认值 ),所以我们可以使用任意用户名 + 任意密码登录
登录后,默认的界面不是最经典的 Notebook 而是功能更现代更丰富的 JupyterLab( JupyterHub 在 2.0 版本后就将用户登录后默认跳转 url 指向了 /lab,参考配置 : c.Spawner.default_url )

Jupyter on k8s

相较于直接通过容器或者运行 JupyterLab 命令启动的 Jupyter,这套 Jupyter helm chart 在哪里做了优化呢?我们可以从启动的 Pod 中一步步探究竟


  • hub: JupyterHub,提供登录页面
  • continuous-image-puller: 在新的 node 加入 k8s 集群的时候,自动在该 node 拉取 Jupyter 所需要的镜像,避免用户在登录后因拉取 Jupyter 服务镜像长时间等待
  • proxy: JupyterHub 的上层代理, 即 configurable-http-proxy
  • user-scheduler: 通过 k8s 的调度策略让 Jupyter 相关的 Pod 尽量分配到同个节点,资源更紧凑
  • singleuser.storage: 每个用户首次启动时都会自动申请一个 pv, 后续用户重新登录,重启 notebook 也能使用之前已经保存的文件
  • singleuser.cpu & singleuser.memory: 单个 Notebook 的资源限制, 默认对 cpu 无限制,内存最多 1G
功能概述

在 JupyterLab 界面你能看到的几个基本功能有 Notebook 、Console 和 Terminal 等
具体功能有机会可以单开一篇详细介绍,这里只提几点注意的

  • 你在其中一个 Jupyter Server 中编写的 Notebook,启动其他镜像也能看到,因为是同一个目录
  • 打开 Terminal 并执行 pwd 你会看到每个用户的主目录都是 /home/jovyan ,这是因为 Notebook 镜像设置了默认用户就是 jovyan ,但因为每个用户都会申请独立的存储挂载到 Notebook,所以实际目录是分开的
  • Notebook 快捷键和 ipykernel 语法非常强大,强烈建议在深度使用 Notebook 之前先了解这些技巧
自定义配置


那么到这里我们已经通过 minikube + helm 在本地成功启动了类生产环境启动的一个 Jupyter 集群了,不妨先喝杯茶
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册