本地开发与调试
本篇是给开发者的进阶调试指南:在本机 IDE 给后端打断点、前端本机开发与容器内编译、前后端镜像升级、常见问题。
先把环境跑起来:见 docker-compose 本地部署。注意:前后端代码在生产环境均在容器中运行。
后端调试方式概览
- docker-compose 调试(推荐):代码通过挂载进容器,在容器里跑、看日志 debug,dev 模式自动热更新。建议学习
pysnooper包。见 02-docker-compose本地部署 的「启动 docker-compose」小节(docker exec进容器后跑/entrypoint.sh或python myapp/run.py)。 - PC 非 docker(conda + IDE 断点):在本机 IDE 直接对 myapp 打断点单步调试,不进容器。下文详述。
前端调试:大部分功能在本机 IDE 开发调试即可(热更新);完整平台前端需打包成静态文件才能验证,可在本机编译也可在容器内编译,容器内编译不支持热更新。
PC 非 docker(conda + IDE 断点调试)
适用场景:在本机 IDE(PyCharm / VSCode)直接对 myapp 后端打断点单步调试,不进容器。后端在本机 conda 环境跑,mysql / redis 复用集群里 infra 命名空间下已有的实例。
1)准备 python 环境
conda create -y -n cube-studio-enterprise python=3.9
conda activate cube-studio-enterprise
pip install --upgrade pip setuptools wheel
pip install -r install/docker/requirements.txt
PC 上
dmPython==2.5.30(达梦驱动,见install/docker/requirements.txt:64)没有 wheel,装不上。不需要达梦的开发者可以跳过它:grep -vE "^(dmPython|dmSQLAlchemy)" install/docker/requirements.txt > /tmp/req.txt pip install -r /tmp/req.txt
2)把集群里的 mysql / redis 暴露成 NodePort
后端要连 k8s infra 命名空间下的 mysql / redis,它们默认是 ClusterIP,本机连不上。一次性 patch 成 NodePort(永久生效):
export KUBECONFIG=install/docker/kubeconfig/dev-kubeconfig
kubectl patch svc -n infra mysql-service --type=merge \
-p '{"spec":{"type":"NodePort","ports":[{"name":"tcp","port":3306,"protocol":"TCP","targetPort":3306,"nodePort":30306}]}}'
kubectl patch svc -n infra redis-master --type=merge \
-p '{"spec":{"type":"NodePort","ports":[{"name":"redis","port":6379,"protocol":"TCP","targetPort":6379,"nodePort":30379}]}}'
service 名已与代码一致:mysql 为
mysql-service(install/kubernetes/mysql/service.yaml),redis 为redis-master(install/kubernetes/redis/redis.yaml,集群中后端用REDIS_HOST=redis-master.infra连接,见install/kubernetes/cube/overlays/kustomization.yml:17)。
之后从本机连 <节点IP>:30306(mysql)和 <节点IP>:30379(redis)。节点 IP 看 kubectl get nodes -o wide 的 INTERNAL-IP。
3)准备 myapp/config.py
docker 启动时靠 docker-compose 挂载 install/docker/config.py 覆盖容器内的 myapp/config.py。本地非 docker 直接跑没有挂载,把 docker 用的那份复制过来覆盖:
cp install/docker/config.py myapp/config.py
注意:源文档
install/docker/README.md称「仓库里myapp/config.py是空文件」,这与当前仓库不符——myapp/config.py实为约 1419 行的完整默认配置(非空)。这里cp的意图是用部署用的install/docker/config.py覆盖这份默认配置;覆盖会改写已纳入版本管理的myapp/config.py,之后若改了install/docker/config.py需再cp一次同步。
4)配置 IDE Run/Debug
新建一个 Python 类型的 Run/Debug Configuration:
| 字段 | 值 |
|---|---|
| Script / Module | myapp/run.py |
| Working directory | 仓库根目录 |
| Python interpreter | conda 环境 cube-studio-enterprise |
环境变量(与 docker-compose 里 myapp 服务的 environment 段对齐,节点 IP / 数据库地址改成你自己的):
export FLASK_APP=myapp:app
export FLASK_ENV=development
export MYAPP_CONFIG=myapp.config
export STAGE=dev
export ENVIRONMENT=DEV
export MYSQL_SERVICE=mysql+pymysql://root:admin@192.168.3.22:30306/kubeflow?charset=utf8mb4
export REDIS_HOST=192.168.3.22
export REDIS_PORT=30379
export REDIS_PASSWORD=admin
export KUBECONFIG=<仓库根绝对路径>/install/docker/kubeconfig/dev-kubeconfig
export MYAPP_PORT=5000
命令行整段粘贴即可生效;IDE 的 Environment Variables 栏粘贴时去掉
export前缀。myapp/run.py已支持读取MYAPP_PORT(app.run(..., port=int(os.environ.get("MYAPP_PORT", 80)), debug=True),见myapp/run.py:5),不设置时仍走 80(容器原行为);本地直接监听 80 需要 sudo,所以这里设成 5000。
export 只对当前 shell 会话生效,开新终端要重 export。长期开发建议把上面那段存成仓库根的 dev.env,新开 shell 时一行加载:
set -a && source dev.env && set +a
5)准备宿主机数据目录
主机上创建 /data/k8s/kubeflow 目录并可读写,可软链到项目目录:
ln -sfn "$(pwd)/install/docker/file" /data/k8s/kubeflow
6)首次初始化数据库(仅 mysql 全新空库需要)
如果连的 mysql 已被其它环境初始化过(表都建好了),跳过本步。全新 mysql 按 docker entrypoint.sh 同样的流程跑一次:
# 1. 编译 i18n 翻译产物 (.po -> .mo)
pybabel compile -d myapp/translations
# 2. 创建数据库 schema
PYTHONPATH=. python myapp/create_db.py
# 3. 应用 alembic 迁移到最新版本
PYTHONPATH=. python myapp/bin/myapp db upgrade
# 4. 创建 admin 用户(用户名 / 密码都是 admin)
PYTHONPATH=. python myapp/bin/myapp fab create-admin \
--username admin --firstname admin --lastname admin \
--email admin@example.com --password admin
# 5. 创建默认角色 / 权限 / 自定义 menu
PYTHONPATH=. python myapp/bin/myapp init
这套流程与容器
install/docker/entrypoint.sh一致(容器内 create-admin 邮箱用的是admin@tencent.com,邮箱可任填)。后续改了 model 想生迁移文件:PYTHONPATH=. python myapp/bin/myapp db migrate,再db upgrade。
7)启动
在仓库根目录下执行(需先 export 过上面的环境变量):
PYTHONPATH=. python myapp/run.py
PYTHONPATH=.是因为命令行python myapp/run.py会把sys.path[0]设成myapp/而非仓库根,导致from myapp import app找不到。IDE 的 Run/Debug 默认把 working directory 加进 PYTHONPATH,所以 IDE 启动不需要这个前缀,直接 Run / Debug 即可,断点单步都生效。
浏览器访问 http://127.0.0.1:5000/,用 admin/admin 登录。若本地没有前端,后端接口都需认证:先打开 http://127.0.0.1:5000/login?username=admin,再直接访问接口(如 http://127.0.0.1:5000/dataset_modelview/api/)。
注意事项
- 本地 myapp 和集群里部署的 myapp 共用同一份
kubeflow数据库。改 model 或db migrate会影响线上 dev 环境。要隔离就单独起一个本地 mysql。 - celery worker / beat / watch 等后台进程没启动,只能调 web API。测异步任务还得靠 docker-compose。
- 后端运行仍需连 k8s,配置方法同 docker-compose(即
KUBECONFIG环境变量)。
前端本机开发和构建
前端代码可在本机开发调试,也可在容器内编译。不是前端开发人员建议用容器内编译,本机就不用配前端环境。
Windows 电脑前端开发视频:https://cube-studio.oss-cn-hangzhou.aliyuncs.com/video/window-frontend-dev.mp4
前端代码目录
myapp/frontend:主体前端项目(frontend 主项目)myapp/vision:流程图(AI pipeline)myapp/visionPlus:流程图(数据 ETL pipeline)
打包环境要求:
node: 16.15.0+
npm: 6.14.8+
yarn(建议): npm install yarn -g
纯前端开发(本地)
注意:本地前端开发需要先用 docker-compose 在本地起好 CubeStudio 前后端。
环境准备:
- 进 nodejs 官网( https://nodejs.org/en/download/ )下载 LTS 版本。
- 装 node 版本管理器:
npm install -g n,再n 16.15.0切到 16.x。
三个前端项目都在各自 src 下有 setupProxy.js 配代理转发:把 target 改成已有服务地址,重启前端项目即可生效。
frontend 主体前端(目录 myapp/frontend):
cd myapp/frontend
npm run start # 调试模式
- 首次进入
http://localhost:3000/login?username=admin&login_url=http://localhost:3000/frontend/,跳转后页面可关闭。 - 之后直接进
http://localhost:3000/frontend/。
vision 任务流编排(目录 myapp/vision):
cd myapp/vision
npm run dev
- 首页
http://localhost:3000/#/home/,或带 pipeline id:http://localhost:3000/?pipeline_id=1#/。
visionPlus 数据 ETL 编排(目录 myapp/visionPlus):
cd myapp/visionPlus
npm run dev
- 访问
http://localhost:3000/?scenes=etl_pipeline&pipeline_id=1。
前端容器内编译
docker-compose 起前后端,进后端容器(后端容器含前端编译环境,编译命令参考 entrypoint.sh 中 STAGE=build 分支):
# 构建前端主体
cd /home/myapp/myapp/frontend && npm install --force && npm run build
# 构建机器学习 pipeline
cd /home/myapp/myapp/vision && npm install && npm run build
# 构建数据 ETL pipeline
cd /home/myapp/myapp/visionPlus && yarn && npm run build
输出路径:myapp/static/appbuilder。
说明:
entrypoint.sh的STAGE=build分支中 frontend 用npm install --force(与上面命令一致),vision / visionPlus 与上面一致;以仓库内install/docker/entrypoint.sh为准。
前后端镜像升级
在项目根目录执行(xx.xx.xx/xx/ 换成你的镜像仓库地址):
前端镜像:
docker build --network=host -t xx.xx.xx/xx/kubeflow-dashboard-frontend:xx \
-f install/docker/dockerFrontend/Dockerfile .
然后在线上 infra 命名空间把 kubeflow-dashboard-frontend 的 deployment 镜像名换成你构建的。
后端镜像:
docker build --network=host -t xx.xx.xx/xx/kubeflow-dashboard:xx \
-f install/docker/Dockerfile .
然后在线上 infra 命名空间把 kubeflow-dashboard 的 deployment 镜像名换成你构建的。
镜像构建更细的说明见 06-二次开发/镜像构建/镜像构建总览.md。
Q&A
1)构建镜像因网络问题失败 —— 加 pip 国内镜像
在 install/docker/ 下新建 pip.conf:
[global]
index-url = http://mirrors.aliyun.com/pypi/simple/
extra-index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host=mirrors.aliyun.com
然后在 install/docker/Dockerfile-base 中增加:
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple
2)前端装依赖失败 —— 加 npm / yarn 国内镜像
npm config set registry https://registry.npmmirror.com
yarn config set registry https://registry.npmmirror.com
3)Windows 下 pip3 install -r requirements.txt 失败
PowerShell 单独安装失败的部分,确保版本号与 requirements.txt 一致,再重新执行 pip3 install -r requirements.txt。
4)Windows 下 docker-compose 报 UnicodeDecodeError: 'gbk' codec
编码类型问题,可参考 https://cloud.tencent.com/developer/article/1530430 修改本地 encoding.py(大致位置:XXX\AppData\Local\Programs\Python\Python312\Lib\site-packages\pip\_internal\utils\encoding.py)。
5)Windows 下 docker-compose 报 /usr/bin/env: 'python(3)\r': No such file or directory
Windows 行尾是 CRLF,Linux 是 LF。用 VSCode 打开项目,全文搜报错关键字(如 /usr/bin/env),打开对应文件,把 VSCode 右下角的 CRLF 切换为 LF 保存。
6)Windows 下打包 visionPlus 编译报错
myapp/visionPlus/.eslintrc 中注释掉 "linebreak-style": ["error", "unix"],取消注释 "linebreak-style": ["error", "windows"]。
命令 / 镜像名 / 配置项以源码(
install/docker/、myapp/run.py、myapp/bin/myapp)为准,本篇仅供导航与上手。