访问流量走向
对,你这里的 NodeExpose 本质上不是 Volcano 的调度能力,而是你们平台 SDK 在 VolcanoJob 外面额外做的一层:
用户 SDK 提交 VolcanoJob
|
平台后端创建 VolcanoJob
|
Volcano 调度 Pod 到 GPU 节点
|
平台后端再创建 Service / Ingress
|
用户通过某个地址访问这个任务里的端口
一句话:
Volcano 负责“任务跑在哪些 GPU 上”,NodeExpose 负责“用户怎么访问任务里的某个端口”。
最常见实现:Service Type NodePort
比如用户提交了一个训练任务,里面有一个 master Pod 暴露 8888,你想让用户访问 Jupyter / TensorBoard / Web UI。
平台后端会额外创建一个 K8s Service:
apiVersion: v1
kind: Service
metadata:
name: train-job-001-jupyter
namespace: team-a
spec:
type: NodePort
selector:
volcano.sh/job-name: train-job-001
volcano.sh/task-spec: master
ports:
- name: jupyter
port: 8888
targetPort: 8888
nodePort: 30888
这里的意思是:
访问 任意节点IP:30888
|
K8s Service / kube-proxy
|
转发到 train-job-001 的 master Pod:8888
所以用户访问的是:
http://<任意NodeIP>:30888
注意,是任意 Kubernetes 节点 IP,不一定是这个 Pod 所在的 GPU 节点。K8s 的 kube-proxy 会在节点上做转发规则,把流量送到真正的 Pod。
完整链路是这样
用户电脑
|
VPN / 办公网 / HTTPS
|
路由器 / 防火墙
|
Mgmt + Service 网络
|
任意 K8s Node IP:NodePort
|
kube-proxy
|
Service
|
VolcanoJob 里的 master Pod
|
容器端口 8888
也就是:
用户访问的不是 GPU 服务器本身的容器端口
而是访问 K8s 暴露出来的 Service 端口
SDK 里面怎么封装
你的 SDK 可以设计成这样:
job = VolcanoJob(
name="llama-sft-001",
image="registry.local/train/llama:latest",
queue="team-a",
gpu=8,
command="python train.py",
expose=[
{
"name": "jupyter",
"task": "master",
"container_port": 8888,
"protocol": "http"
},
{
"name": "tensorboard",
"task": "master",
"container_port": 6006,
"protocol": "http"
}
]
)
client.submit(job)
SDK 后端实际做两件事:
1. 创建 VolcanoJob
2. 为 expose 里声明的端口创建 Service / Ingress
不是让用户自己写 NodePort。
更推荐的生产做法
不要直接把 NodeIP:NodePort 丢给普通用户。生产里更建议这样:
用户
|
https://train.company.com/jobs/llama-sft-001/jupyter
|
Ingress / API Gateway / Nginx
|
ClusterIP Service
|
VolcanoJob master Pod:8888
也就是说:
外部用户访问域名
内部平台再转发到对应 Job 的 Service
这样安全很多,也好做权限控制、审计、HTTPS、SSO、过期回收。
NodePort 和 Ingress 的区别
NodePort 更像临时调试入口:
http://10.10.20.31:30888
优点是简单,缺点是不优雅、不安全、端口容易乱。
Ingress 更适合平台化:
https://train.your-domain.com/job/train-job-001/jupyter
优点是统一入口、支持 HTTPS、SSO、权限控制、审计。
你的用户使用 SDK 的话,我建议最终做成:
SDK 提交任务
平台返回访问地址
用户不用知道 NodePort
比如返回:
{
"job_name": "llama-sft-001",
"status": "running",
"endpoints": {
"jupyter": "https://train.example.com/jobs/llama-sft-001/jupyter",
"tensorboard": "https://train.example.com/jobs/llama-sft-001/tensorboard"
}
}
Volcano 自带的 svc 插件和 NodeExpose 不是一回事
Volcano 的 svc 插件主要解决的是 任务内部 Pod 之间互相发现,比如 master/worker 之间通信。官方文档里也说明它会给 Pod 加上类似这些 label:
volcano.sh/job-name: xxx
volcano.sh/task-spec: master
volcano.sh/job-namespace: team-a
这些 label 正好可以被你创建的 K8s Service 用来选择目标 Pod。
但它不是给外部用户访问用的。外部访问还得靠:
Service NodePort
Ingress
LoadBalancer / MetalLB
平台网关
参考:Volcano 官方 VolcanoJob 和 SVC Plugin 文档。
