前言
在现代数据中心里,经常存在两座”孤岛”:一座是运行传统 HPC 和批处理作业的 LSF 集群,另一座是运行微服务和 AI 服务的 Kubernetes (K8s) 集群。这种割裂不仅导致资源利用率低,也增加了管理复杂度。
IBM Spectrum LSF Suite(HPC 版和 Enterprise 版)内置了 LSF Connector for Kubernetes,旨在打破这一边界。它允许 LSF 作为 K8s 的调度器,让 K8s Pods 与 LSF 批处理作业在同一套基础设施上共存。
本篇将带您了解这一集成的架构原理,并演示如何通过 LSF 调度器提交 K8s Pod 和并行作业。
一、集成架构:告别资源孤岛
LSF 与 Kubernetes 的集成方案并非简单的双系统并排,而是深度的调度融合。
1. 逻辑架构
| 特性 | 说明 |
|---|---|
| 单一资源池 | LSF 和 Kubernetes 共享底层物理机器,无需物理隔离 |
| 角色分离 | LSF Master 和 Kubernetes Master 必须部署在不同物理机 |
| 统一调度 | LSF 充当 K8s 的调度器,决定 Pod 放置位置 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌─────────────────────────────────────────────────────────────┐
│ LSF + Kubernetes 融合架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ LSF Master │ │ K8s Master │ │
│ │ (独立节点) │ │ (独立节点) │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ │ LSF Connector │ │
│ └────────────┬───────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 共享计算节点池 │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │Node1│ │Node2│ │Node3│ │Node4│ │Node5│ │ │
│ │ │LSF │ │LSF │ │LSF │ │LSF │ │LSF │ │ │
│ │ │+K8s │ │+K8s │ │+K8s │ │+K8s │ │+K8s │ │ │
│ │ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
这种架构使得管理员可以维护一套统一的环境,根据实际负载动态分配资源,而不是维护两个僵化的孤岛。
2. 调度流程
1
2
3
4
5
6
7
8
9
10
11
12
13
用户提交 K8s Pod (schedulerName: lsf)
↓
K8s API Server 接收请求
↓
LSF Connector 监听到 Pending Pod
↓
LSF 调度器评估资源、队列策略、公平共享
↓
LSF 决定目标节点
↓
Pod 在指定节点上启动
↓
LSF 持续跟踪 Pod 状态
二、实战演练:像提交 Job 一样提交 Pod
集成启用后,用户依然可以使用熟悉的 Kubernetes CLI (kubectl) 来提交任务,只需指定调度器即可。
1. 定义使用 LSF 调度的 Job
编写一个标准的 K8s Job YAML 文件(例如 job-1.yaml),关键在于 spec 中添加 schedulerName: lsf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: batch/v1
kind: Job
metadata:
name: job-1
spec:
template:
metadata:
annotations:
lsf.ibm.com/queue: "normal" # 指定 LSF 队列
spec:
schedulerName: lsf # 关键:指定 LSF 为调度器
containers:
- name: myjob
image: ubuntu:latest
command: ["sleep", "120"]
resources:
requests:
cpu: "1"
memory: "512Mi"
limits:
cpu: "2"
memory: "1Gi"
restartPolicy: Never
关键配置说明
| 配置项 | 说明 |
|---|---|
schedulerName: lsf |
指定 LSF 为调度器(必需) |
lsf.ibm.com/queue |
指定 LSF 队列(可选) |
resources.requests |
资源请求,LSF 用于调度决策 |
resources.limits |
资源限制,K8s 用于 cgroups 约束 |
2. 提交与验证
使用 kubectl 提交作业:
1
2
$ kubectl create -f job-1.yaml
job.batch/job-1 created
状态流转
| 阶段 | 状态 | 说明 |
|---|---|---|
| 1 | Pending | 作业在 K8s 中等待调度 |
| 2 | Scheduled | LSF 接管调度,分配资源 |
| 3 | Running | Pod 开始在指定节点运行 |
| 4 | Completed | 作业完成 |
查看 Pod 状态
1
2
3
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
job-1-abc12 1/1 Running 0 30s
3. 可观测性与排错
LSF 会自动将作业信息作为 Label(标签) 和 Annotation(注解) 注入到 Pod 中,方便追踪。
1
$ kubectl describe pod job-1-abc12
注入的 LSF 元数据
| 标签/注解 | 示例值 | 说明 |
|---|---|---|
lsf.ibm.com/jobId |
305 | 关联的 LSF 作业 ID |
lsf.ibm.com/queue |
normal | 使用的队列 |
lsf.ibm.com/pendingReason |
- | 排错神器 |
排错技巧
如果作业一直 Pending,查看 Annotations 中的 lsf.ibm.com/pendingReason:
1
2
$ kubectl get pod job-1-abc12 -o jsonpath='{.metadata.annotations.lsf\.ibm\.com/pendingReason}'
Blocked by Kubernetes policies (Insufficient cpu)
这会直接显示 LSF 的拒绝原因,帮助快速定位问题。
三、高级功能:在 K8s 上运行并行作业 (Parallel Jobs)
Kubernetes 原生对并行作业(如 MPI 任务、分布式 AI 训练)的支持相对有限。LSF Connector 引入了自定义资源定义 (CRD) paralleljobs.ibm.com,填补了这一空白。
1. 并行作业结构
LSF 定义的 ParallelJob 包含多个 任务组 (Task Groups)。
例如,在 AI 训练场景中:
| 任务组 | 角色 | 副本数 |
|---|---|---|
| group0 | Parameter Server | 1 |
| group1 | Worker | 4 |
每个组内可以包含多个运行相同镜像的 Pod。
2. 定义并行作业
创建一个 YAML 文件(例如 pjob-3.yaml),使用 kind: ParallelJob:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: ibm.com/v1alpha1
kind: ParallelJob
metadata:
name: pjob-3
spec:
schedulerName: lsf
taskGroups:
# Parameter Server 组
- metadata:
name: ps
spec:
replica: 1
template:
spec:
containers:
- name: ps-container
image: tensorflow/tensorflow:latest
command: ["python", "ps_server.py"]
resources:
requests:
cpu: "2"
memory: "4Gi"
# Worker 组
- metadata:
name: worker
spec:
replica: 4
template:
spec:
containers:
- name: worker-container
image: tensorflow/tensorflow:latest-gpu
command: ["python", "train.py"]
resources:
requests:
cpu: "4"
memory: "8Gi"
nvidia.com/gpu: "1"
3. 提交与管理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 提交并行作业
$ kubectl create -f pjob-3.yaml
paralleljob.ibm.com/pjob-3 created
# 查看并行作业状态
$ kubectl describe pj pjob-3
Name: pjob-3
Namespace: default
Status: Running
Task Groups:
Name: ps
Replica: 1
Status: Running
Name: worker
Replica: 4
Status: Running
# 查看所有相关 Pod
$ kubectl get pods -l paralleljob=pjob-3
NAME READY STATUS RESTARTS AGE
pjob-3-ps-0 1/1 Running 0 2m
pjob-3-worker-0 1/1 Running 0 2m
pjob-3-worker-1 1/1 Running 0 2m
pjob-3-worker-2 1/1 Running 0 2m
pjob-3-worker-3 1/1 Running 0 2m
LSF 会协调启动所有组内的 Pod。当您看到所有 Pod 成功运行时,证明 LSF 已经成功在 Kubernetes 环境中编排了复杂的并行工作负载。
集成优势总结
| 优势 | 传统方案 | LSF + K8s 融合 |
|---|---|---|
| 资源利用率 | 两套独立资源池,利用率低 | 统一资源池,按需分配 |
| 管理复杂度 | 维护两套系统 | 统一管理界面 |
| 调度策略 | K8s 原生调度较简单 | LSF 丰富的调度策略(公平共享、优先级、抢占) |
| 并行作业 | K8s 原生支持有限 | ParallelJob CRD 完美支持 |
| 可观测性 | 分散在两个系统 | LSF 标签注入,统一追踪 |
1
2
3
4
5
6
7
8
9
10
11
┌─────────────────────────────────────────────────────────────┐
│ 工作负载统一视图 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 传统 LSF 作业 ───┐ │
│ │ │
│ K8s Pods ────┼────→ LSF 调度器 ────→ 统一资源池 │
│ │ │
│ K8s ParallelJob ─┘ │
│ │
└─────────────────────────────────────────────────────────────┘
下期预告:
随着集群运行时间的增长,日志和历史数据会不断累积,导致磁盘空间告急。Elasticsearch 索引该如何维护?数据盘满了怎么迁移?在系列的最后一篇《IBM Spectrum LSF Suite 最佳实践 (7):Explorer 数据维护与 Elasticsearch 管理技巧》中,我们将关注长期运维中的数据管理问题。