基于 kubesphere + cube-studio搭建一站式云原生机器学习平台 国产纯中文 实操记录
1. cube studio 简介
cube studio开源云原生一站式机器学习/深度学习/大模型AI平台,支持sso登录,多租户,大数据平台对接,notebook在线开发,拖拉拽任务流pipeline编排,多机多卡分布式训练,超参搜索,推理服务VGPU,边缘计算,serverless,标注平台,自动化标注,数据集管理,大模型微调,vllm大模型推理,llmops,私有知识库,AI模型应用商店,支持模型一键开发/推理/微调,支持国产cpu/gpu/npu芯片,支持RDMA,支持pytorch/tf/mxnet/deepspeed/paddle/colossalai/horovod/spark/ray/volcano分布式
开源地址: https://github.com/tencentmusic/cube-studio
2. 单机版安装
下载源码
cd /data/kubesphere
git clone https://github.com/tencentmusic/cube-studio.git
处理脚本start.sh
2.1 对于ipvs模式的k8s特殊处理
(1)要将start.sh脚本最后面的kubectl patch注释掉。然后手动释放istio-system命名空间 istio-ingressgateway,服务类型改为NodePort。
通过命令确定模式: kubectl -n kube-system get configmap kube-proxy -o yaml|grep mode
(2)将配置文件install/kubernetes/cube/overlays/config/config.py中的K8S_NETWORK_MODE 改为ipvs
2.2 start.sh命令修改kubectl相关部分
由于我是单机版本, 所以kubectl命令已经存在, 而且本机就有 $HOME/.kube/config , 所以相关脚本注释掉
#mkdir -p ~/.kube && rm -rf ~/.kube/config && cp config ~/.kube/config
#ARCH=$(uname -m)
#if [ "$ARCH" = "x86_64" ]; then
# wget https://cube-studio.oss-cn-hangzhou.aliyuncs.com/install/kubectl && chmod +x kubectl && cp kubectl /usr/bin/ && mv kubectl /usr/local/bin/
#elif [ "$ARCH" = "aarch64" ]; then
# wget -O kubectl https://cube-studio.oss-cn-hangzhou.aliyuncs.com/install/kubectl-arm64 && chmod +x kubectl && cp kubectl /usr/bin/ && mv kubectl /usr/local/bin/
#fi
2.3 kubectl拿version时, 由于1.28版本高的原因问题会报错
version=`kubectl version --short | awk '/Server Version:/ {print $3}'`
修改成
version=`kubectl version | awk '/Server Version:/ {print $3}'`
2.3 create_ns_secret.sh 修改
一般应该是可以忽略的, 我修改成自己内网的 harbor网址
kubectl create secret docker-registry hubsecret --docker-server=https://172.16.20.20/v2/ --docker-username=admin --docker-password=Harbor12345 -n $namespace
2.4 平台部署命令
将k8s集群的kubeconfig文件复制到install/kubernetes/config文件中,对于双网卡的同学,记得rancher里面current-context切换为内网的连接形式,然后执行如下命令,其中xx.xx.xx.xx为机器内网的ip(不是外网ip)
我当前下载源码位置是在 这里 cd /data/kubesphere/cube-studio
由于是root账号安装的kubernetes, 所以在root账号下执行如下命令
cp $HOME/.kube/config install/kubernetes/config 由于上面注释掉了此复制的命令, 这个可以不需要, 因为是单机版的, config已经存在了, 如果是别的机器需要加哦
cd /data/kubesphere/cube-studio/install/kubernetes
# 在k8s worker机器上执行
sh start.sh 172.16.21.35
3. 安装结束
virtualservice.networking.istio.io/infra-kubeflow-dashboard created
打开网址:http://172.16.21.35
service/istio-ingressgateway patched
打开网址:http://172.16.21.35:30571
输入用户名: admin
密码: admin
4. 问题记录
4.1 耐心等待安装
4.2 大量失败
第二天上班检查一下, 发现大量失败
4.3 失败原因 failed to resolve reference "docker.io/library/busybox:1.36.0"
拿mysql举例
查看pods
kubectl -n infra get pods
NAME READY STATUS RESTARTS AGE
kubeflow-dashboard-694954997d-nm5f7 1/1 Running 88 (4m6s ago) 16h
kubeflow-dashboard-frontend-79df687b96-ckkbp 1/1 Running 0 16h
kubeflow-dashboard-schedule-5868649bcd-9qflm 0/1 CrashLoopBackOff 165 (3m24s ago) 16h
kubeflow-dashboard-worker-588d7759d4-k975w 0/1 CrashLoopBackOff 166 (55s ago) 16h
kubeflow-watch-7b8bfd6598-2dfhx 1/1 Running 1 (5h17m ago) 16h
mysql-5d9696cccc-98dlb 0/1 Init:ImagePullBackOff 0 16h
redis-6d8c76cc5f-ffmjz 0/1 ImagePullBackOff 0 16h
检查mysql详情
kubectl -n infra describe pod mysql-5d9696cccc-98dlb
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal BackOff 19m (x3524 over 16h) kubelet Back-off pulling image "busybox:1.36.0"
Warning Failed 14m (x188 over 15h) kubelet (combined from similar events): Failed to pull image "busybox:1.36.0": failed to pull and unpack image "docker.io/library/busybox:1.36.0": failed to resolve reference "docker.io/library/busybox:1.36.0": failed to do request: Head "https://registry-1.docker.io/v2/library/busybox/manifests/1.36.0": dial tcp 128.242.240.189:443: i/o timeout
Normal Pulling 4m21s (x164 over 16h) kubelet Pulling image "busybox:1.36.0"
4.4 根据找不到镜像的, 使用本地harbor逐一修改, 例如:
docker tag bitnami/redis:6.2.12 172.16.20.20/bitnami/redis:6.2.12
docker push 172.16.20.20/bitnami/redis:6.2.12
修改yml
image: '172.16.20.20/bitnami/redis:6.2.12'
然后修改自签证书
编辑 /etc/containerd/config.toml,找到 plugins."io.containerd.grpc.v1.cri".registry 部分,添加私有仓库信息。
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."172.16.20.20"]
endpoint = ["https://172.16.20.20"]
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."172.16.20.20".tls]
ca_file = "/etc/containerd/certs.d/172.16.20.20/ca.crt"
创建证书目录:
sudo mkdir -p /etc/containerd/certs.d/172.16.20.20
将自签名证书复制到 /etc/containerd/certs.d/172.16.20.20/ca.crt
编辑完 config.toml 后,重启 Containerd:
sudo systemctl restart containerd
其它镜像如法炮制
4.5 批量删除有问题pod
#!/bin/bash
# 显示帮助信息
function show_help {
echo "使用方法: $0 [-n NAMESPACE]"
echo ""
echo "参数说明:"
echo " -n NAMESPACE 指定命名空间(必填)"
echo " -h 显示帮助信息"
exit 0
}
# 检查命名空间是否存在
function validate_namespace {
local namespace=$1
kubectl get namespace "$namespace" &>/dev/null
if [ $? -ne 0 ]; then
echo "错误: 命名空间 '$namespace' 不存在。"
exit 1
fi
}
# 解析输入参数
while getopts "n:h" opt; do
case $opt in
n)
NAMESPACE="$OPTARG"
;;
h)
show_help
;;
*)
show_help
;;
esac
done
# 检查是否提供命名空间
if [ -z "$NAMESPACE" ]; then
echo "错误: 必须提供命名空间。"
show_help
fi
# 验证命名空间
validate_namespace "$NAMESPACE"
# 获取 ContainerStatusUnknown 的 Pod 名称列表
PODS=$(kubectl -n "$NAMESPACE" get pods --no-headers | awk '$3 == "ContainerStatusUnknown" {print $1}')
if [ -z "$PODS" ]; then
echo "没有处于 ContainerStatusUnknown 状态的 Pod。"
exit 0
fi
# 删除这些 Pod
echo "以下处于 ContainerStatusUnknown 状态的 Pod 将被删除:"
echo "$PODS"
for POD in $PODS; do
echo "删除 Pod: $POD"
kubectl -n "$NAMESPACE" delete pod "$POD"
done
echo "操作完成。"
4.6 记录其它缺失的镜像
docker tag grafana/grafana:9.5.20 172.16.20.20/grafana/grafana:9.5.20
docker push 172.16.20.20/grafana/grafana:9.5.20
docker pull ccr.ccs.tencentyun.com/cube-studio/kubeflow-dashboard:2024.11.01
验证:
crictl pull 172.16.20.20/grafana/grafana:9.5.20
修改yml中的镜像路径 为 172.16.20.20/grafana/grafana:9.5.20
docker tag minio/minio:RELEASE.2023-04-20T17-56-55Z 172.16.20.20/minio/minio:RELEASE.2023-04-20T17-56-55Z
docker push 172.16.20.20/minio/minio:RELEASE.2023-04-20T17-56-55Z
根据下方的脚本push
如果harbor项目中,没有此项目, 可以手工创建一下, 例如 volcanosh
./push.sh volcanosh/vc-controller-manager:v1.7.0
./push.sh volcanosh/vc-scheduler:v1.7.0
./push.sh kubeflow/training-operator:v1-8a066f9
./push.sh argoproj/workflow-controller:v3.4.3
./push.sh istio/proxyv2:1.15.0
./push.sh istio/pilot:1.15.0
./push.sh kubernetesui/metrics-scraper:v1.0.8
./push.sh kubernetesui/dashboard:v2.6.1
./push.sh prom/node-exporter:v1.5.0
./push.sh prom/prometheus:v2.27.1
./push.sh bitnami/kube-rbac-proxy:0.14.1
./push.sh bitnami/kube-rbac-proxy:0.14.1
4.7 批量修改镜像并推送脚本
#!/bin/bash
# 显示帮助信息
function show_help {
echo "使用方法: $0 <镜像名称>"
echo ""
echo "参数说明:"
echo " <镜像名称> 要处理的源镜像,例如 minio/minio:RELEASE.2023-04-20T17-56-55Z"
echo ""
echo "示例:"
echo " $0 minio/minio:RELEASE.2023-04-20T17-56-55Z"
exit 0
}
# 检查输入参数
if [ "$#" -ne 1 ]; then
echo "错误: 参数不足!"
show_help
fi
SOURCE_IMAGE=$1
TARGET_IMAGE="172.16.20.20/$SOURCE_IMAGE"
# 验证 Docker 是否可用
if ! command -v docker &>/dev/null; then
echo "错误: Docker 未安装或未正确配置,请检查环境!"
exit 1
fi
# 验证源镜像是否存在
if ! docker image inspect "$SOURCE_IMAGE" &>/dev/null; then
echo "错误: 源镜像 '$SOURCE_IMAGE' 不存在,请检查输入!"
exit 1
fi
# 镜像打标签
echo "正在为镜像打标签: $SOURCE_IMAGE -> $TARGET_IMAGE"
docker tag "$SOURCE_IMAGE" "$TARGET_IMAGE"
if [ $? -ne 0 ]; then
echo "错误: 镜像打标签失败,请检查输入参数!"
exit 1
fi
# 推送镜像
echo "正在推送镜像到仓库: $TARGET_IMAGE"
docker push "$TARGET_IMAGE"
if [ $? -ne 0 ]; then
echo "错误: 推送镜像失败,请检查目标仓库地址和权限!"
exit 1
fi
echo "操作成功: 镜像 '$SOURCE_IMAGE' 已成功推送到 '$TARGET_IMAGE'"