单机 k8s 部署
本篇讲在机器上以 k8s 形态部署完整平台:先有一个 k8s 集群(不熟 k8s 可用 rancher 起),再用 start.sh 把 CubeStudio 部署到 k8s 上。部署完成后能调度真实的 pipeline / notebook / 推理任务。
机器规格、操作系统、k8s 版本等前置要求见 部署总览与前置要求。
部署提前预备内容
- 分布式存储:挂载到
/data/k8s目录下(单机可忽略)。NFS 等分布式存储的搭建可参考仓库内install/kubernetes/nfs/NFS离线部署.md;存储目录约定见 04-运维管理/分布式存储目录.md。 - 私有镜像仓库:在每台机器的 docker 配置中添加 Insecure Registries(体验可忽略)。Harbor 搭建见 04-运维管理/私有镜像仓库Harbor.md(仓库内对应
install/harbor/readme.md)。 - GPU / IB 驱动:GPU 机器要安装 nvidia-docker2,并安装对应厂商驱动;IB 设备也需安装对应驱动(CPU 机器可忽略)。可参考仓库内
install/rancher目录。
1、对于不熟悉 k8s 的同学
可以先用 rancher 部署 k8s,再部署 CubeStudio。
- 视频教程:单机部署视频(bilibili)
- 文档:仓库内
install/kubernetes/rancher/readme.md。
2、对于已有 k8s 的同学
- ipvs 模式的 k8s:
- (1)把
start.sh脚本最后面的kubectl patch注释掉,然后手动把 istio-system 命名空间的istio-ingressgateway服务类型改为 NodePort。 - (2)把 k8s overlay 配置文件
install/kubernetes/cube/overlays/config/config.py中的K8S_NETWORK_MODE改为ipvs(默认iptables)。
- (1)把
- containerd 运行时的 k8s:
- (1)把
install/kubernetes/cube/overlays/config/config.py中的CONTAINER_CLI改为nerdctl(默认docker)。
- (1)把
- 服务可用端口范围要放大到 10 ~ 60000。
配置项含义与位置说明见 04-运维管理/配置文件管理.md。
注意:平台入口是 istio-system 命名空间的 istio-ingressgateway,不是 CubeStudio 的前端部分。
平台部署命令:把 k8s 集群的 kubeconfig 文件复制到 install/kubernetes/config 文件中。对于双网卡的机器,记得 rancher 里 current-context 切换为内网的连接形式,然后执行如下命令,其中 xx.xx.xx.xx 为机器内网 IP(不是外网 IP):
# 在 k8s worker 机器上执行
sh start.sh xx.xx.xx.xx
3、对于隔离内网部署的同学
参考仓库内 install/kubernetes/offline.md(离线部署流程 + 离线镜像)。
修改为非 80 端口
修改 istio-system 命名空间下名为 istio-ingressgateway 的 service,将服务类型改为 NodePort。将 80 端口的 nodePort 改为其他可访问的端口,注意不要删除 80 端口的配置,因为 gateway 中会读取这个 80 参数。
同时商业版需修改 kubeflow 命名空间 labelstudio deployment 中环境变量 LABEL_STUDIO_HOST 的值,添加上暴露出来的端口号。
域名访问
修改 install/kubernetes/virtual.yaml,将其中 hosts 参数 * 改为域名,然后重新部署:kubectl apply -f virtual.yaml。
配置文件 config.py 中修改 SERVICE_EXTERNAL_IP,将域名作为外网 IP,比如设置为 ['192.168.3.22|localhost.example.com'];如果是多个集群,则修改 CLUSTERS 的每个集群的 HOST 字段。删除后重启后端 pod,使配置生效(配置文件说明见 04-运维管理/配置文件管理.md)。
然后删除所有之前创建的虚拟服务:
kubectl delete vs --all -n jupyter
kubectl delete vs --all -n service
kubectl delete vs --all -n automl
kubectl delete vs --all -n aihub
修改域名后,notebook / 内部服务 / 推理服务要清理、重启才能打开。
如果没有域名但想通过域名访问,除上面的修改外,还需在本地 hosts 文件中添加域名解析:
xx.xx.xx.xx your.host.com
若使用域名访问前,没有清理重启 notebook、内部服务、推理服务和 aihub 应用,那么在使用域名访问后,reset notebook 和部署服务会造成平台无法域名访问。这是因为 istio 代理中 IP 代理优于域名代理,此时要用 IP 进入平台,把 jupyter 和 service 命名空间的所有 notebook、内部服务、推理服务全部清理掉,再重新用域名访问。
内部 IP 和外部 IP
- 部署 CubeStudio 时,
start.sh脚本后面要填内网 IP,浏览器访问使用外网 IP(公网 IP),并修改 config.py 中SERVICE_EXTERNAL_IP为['内网ip|外网ip'](见 04-运维管理/配置文件管理.md)。 - 标注平台:修改 kubeflow 命名空间 labelstudio 的 deployment 中前后端环境变量
LABEL_STUDIO_HOST,改为公网 IP 和端口。
nginx 反向代理 istio-ingressgateway
有时浏览器只能打开物理机 IP,而部署 CubeStudio 用的是虚拟机,需要加 nginx 代理。注意 nginx 访问超时时长要设大一些,否则 websocket 协议的 webshell 执行命令会失败。
nginx 配置参考仓库内 install/kubernetes/nginx-https/nginx.conf,相关说明见 04-运维管理/平台HTTPS配置.md。
内网穿透形式
内网穿透参考仓库内 install/kubernetes/frp/readme.md。
https 协议
因为 istio-ingressgateway 只暴露 80 端口,需要通过 nginx 代理 https 协议,以 http 协议格式代理到 istio-ingressgateway。nginx 的 https 代理参考仓库内 install/kubernetes/nginx-https/readme.md(见 04-运维管理/平台HTTPS配置.md)。
由于从 nginx 流出后均为 http 协议,后端返回某项数据或协议时可能无法识别前端是 http,所以还需要修改前端镜像构建用的 install/docker/dockerFrontend/nginx.80.conf,取消注释:
proxy_set_header X-Forwarded-Proto https;
同时在 config.py 中为 AIHUB_ENV 增加 "PROTOCOL":"https" 环境变量,重启后端 pod。
部署后排查
部署后打不开 / 任务起不来时,按下面顺序排查。先了解 平台基础组件,机器标签管理可参考 03-平台使用/02-资源与存储/机器资源配置.md。
- 用
kubectl version查看是否存在 kubectl。内网中可能 kubectl 不存在又无法下载,可改start.sh脚本手动下载 kubectl。 - rancher 部署的是 iptables 模式,kubekey 部署是 ipvs 模式。若 k8s 采用 ipvs 网络模式,把 istio-ingressgateway 改为 nodeport 模式(而非 externalIPs),并在 config.py 中把
K8S_NETWORK_MODE由 iptables 改为 ipvs。 - 查看机器是否打了标签:
没有标签则用下面命令添加(替换kubectl get nodes --show-labels$node变量):kubectl label node $node train=true cpu=true notebook=true service=true org=public istio=true knative=true kubeflow=true kubeflow-dashboard=true mysql=true redis=true monitoring=true logging=true --overwrite - pv 和 pvc 是否绑定。有些 k8s 平台会自动为 pvc 添加 Storage Classes,需要对应 pv 也添加完成绑定。
- infra 命名空间其他组件是否成功,它们会连接 mysql 完成数据库初始化。kubeflow 数据库由
kubeflow-dashboard.infra组件完成初始化。- 4.1 数据库如果库表不全,可把对应库删掉重启相应组件:
rm -rf /data/k8s/infra/mysql,然后重启 infra 命名空间 mysql 的 pod,再重启 kubeflow-dashboard 相关 pod。 - 4.2 如果 kubeflow-dashboard 报 core dump,可能是 linux 系统内核版本太低,需要升级系统内核。
- 4.1 数据库如果库表不全,可把对应库删掉重启相应组件:
- kube-system 命名空间 coredns 的 pod 是否正常,看日志是否有 timeout 报错。
- 5.1 可以放开流量代理:
放开后重启 coredns 的 pod。/sbin/iptables -P FORWARD ACCEPT /sbin/iptables -P INPUT ACCEPT /sbin/iptables -P OUTPUT ACCEPT - 5.2 查看 53 端口是否被占用(比如 bind 服务),关闭主机原有 53 端口服务:
systemctl stop bind9 && systemctl disable bind9(注意机器重启后原 53 端口服务可能被重新打开)。 - 5.3 参考 https://www.cnblogs.com/zhaichao93/p/16224163.html 修正 dns 配置。
- 5.1 可以放开流量代理:
- istio-system 空间下,istio-ingressgateway 的 svc 是否以 externalIPs 形式暴露了内网 IP。如果有双网卡,执行
sh start.sh xx.xx.xx.xx时用的是内网 IP,浏览器打开的是外网 IP。 - istio-ingressgateway 暴露 80 后仍无法打开,可能原因:(1)80 被内网封禁(2)80 被其他服务占用(3)没有禁用 nginx-ingress(4)防火墙限制,可执行
/sbin/iptables -P FORWARD ACCEPT。 - istio-ingressgateway 暴露其他端口:如果 80 被占用,可修改
istio-system/svc/istio-ingressgateway类型为 NodePort,同时商业版需修改 kubeflow 命名空间 labelstudio deployment 中环境变量LABEL_STUDIO_HOST的值,加上暴露出来的端口号。 - 镜像拉取不下来:可离线拉取一遍平台镜像(仓库内脚本
install/kubernetes/pull_image_kubeflow.sh);对于其他仓库镜像最好设为 public,否则更新每个命名空间 hubsecret 的账号密码。配置在“在线开发 -> 镜像仓库”中 hubsecret 的账号密码为自己的 dockerhub 账号密码。 - 如果报错
failed to create fsnotify watcher: too many open files,一般由于机器算力太小,执行下面命令修复:sudo sysctl -w fs.inotify.max_user_watches=2099999999 sudo sysctl -w fs.inotify.max_user_instances=2099999999 sudo sysctl -w fs.inotify.max_queued_events=2099999999
命令、脚本路径与配置项以源码(
install/kubernetes/、install/docker/config.py)为准,仅供导航。