Lab 1 的目标是在一台笔记本上用虚拟机或者 Docker 搭出一个小型集群,然后逐层把 HPC 集群需要的服务铺上去:并行计算环境(MPI + BLAS + HPL)、共享存储(NFS / BeeGFS)、作业调度(Slurm)、容器编排与可观测性(K3s + Prometheus)、集中式身份(FreeIPA)、以及集群网络入口。下面按主题而非按课程任务编号来组织,任务编号我保留在括号里方便溯源。
实验中我用 Claude / Codex 做交互式的报错分析、方案权衡和笔误排查,文中的判断均经过动手验证。
实验平台概况
在单台笔记本上通过 VMware Workstation Pro 构建一个小型集群。宿主机为 Intel Core Ultra 9 285H、32 GB 内存;虚拟机共享同一宿主资源,通过 VMware 的 NAT 网络互联。
集群共 5 个节点:4 台 Debian 节点承载计算、存储与编排;另有 1 台单独的 Rocky Linux 节点专门运行身份服务(详见集中式身份一节)。
| 节点 | IP | 角色 | vCPU | 内存 | 系统盘 | 附加盘 |
|---|---|---|---|---|---|---|
| node01 | 192.168.78.129 | 管理节点:NFS server、Slurm 控制节点(slurmctld)、K3s server、BeeGFS management | 2 | 3.8 GB | 60 GB | — |
| node02 | 192.168.78.130 | 计算节点 / K3s agent / BeeGFS metadata | 2 | 1.9 GB | 60 GB | — |
| node03 | 192.168.78.131 | 计算节点 / BeeGFS storage | 2 | 1.9 GB | 60 GB | 20 GB |
| node04 | 192.168.78.132 | 计算节点 / BeeGFS storage | 2 | 1.9 GB | 60 GB | 20 GB |
| ipa01 | — | 身份服务节点:FreeIPA server(LDAP + Kerberos + CA + DNS) | 2 | — | — | — |
- node01 在 K3s 阶段由 2 GB 上调至 4 GB 以容纳 K3s server,其余阶段为 2 GB。
- 4 台 Debian 节点操作系统为 Debian 13 (trixie),内核 6.12.90+deb13.1-amd64;身份节点为 Rocky Linux 9。
贯穿 Lab 的内存约束:除了 node01 外每个计算节点只有约 1.9 GB 内存。所以后续很多操作都是在资源受限的情况下所做的取舍。
并行计算环境:MPI、BLAS 与 HPL
HPL(High-Performance Linpack)是衡量集群浮点性能的经典基准,它依赖 MPI 做进程间通信、依赖 BLAS 做底层矩阵运算。动手搭建这条链有助于理解一个高性能计算程序是怎么被编译、链接、并找到它的依赖库的。
安装链(任务一)
-
OpenMPI

实验文档强调安装后要运行
ldconfig刷新动态链接库缓存,但我初次尝试时没执行,OpenMPI 也能正常运行。我用ldd $(which mpirun)和cat /etc/ld.so.conf*验证,发现原因是./configure时没加--prefix,默认装到了/usr/local/lib,而该目录本就在动态链接器的搜索路径里,所以无需额外刷新缓存即可解析。 -
BLAS

编译产物为
libblas.a(与文档示例的blas_LINUX.a命名不同,属于环境差异),已在Make.Linux_PII_FBLAS中对应调整LAlib路径。 -
CBLAS

-
HPL

关键 Make 变量
hpl-2.3/Make.Linux_PII_FBLAS:
ARCH = Linux_PII_CBLAS
TOPdir = $(HOME)/hpl-2.3
INCdir = $(TOPdir)/include
BINdir = $(TOPdir)/bin/$(ARCH)
LIBdir = $(TOPdir)/lib/$(ARCH)
HPLlib = $(LIBdir)/libhpl.a
MPdir = /usr/local
MPinc = -I$(MPdir)/include
MPlib = -L/usr/local/lib -lmpi
LAdir =
LAinc = -I/home/zscott/CBLAS/include
LAlib = /home/zscott/CBLAS/lib/cblas_LINUX.a /home/zscott/BLAS-3.12.0/build/libblas.a
LINKER = /usr/bin/gfortran
LINKFLAGS = $(CCFLAGS)
CBLAS/Makefile.in:
BLLIB = /home/zscott/BLAS-3.12.0/build/libblas.a
CBLIB = /home/zscott/CBLAS/lib/cblas_LINUX.a
CC = gcc
FC = gfortran
LOADER = $(FC)
注意这里手动构建的 HPL 用的是 netlib 参考实现 BLAS(
LAlib指向自己编的libblas.a)。这一点在后面解释多节点跑分为什么只有 ~10 GFLOPS时是关键。
用 HPL 跑分与调参(任务四)
多节点提交用 Slurm 的 sbatch:
#!/bin/bash
#SBATCH --job-name=hpl
#SBATCH --partition=debug
#SBATCH --nodes=3
#SBATCH --ntasks-per-node=2
#SBATCH --chdir=/shared/hpc101/src/hpl-2.3/bin/Linux_PII_CBLAS
#SBATCH --output=/shared/hpc101/hpl_%j.out
mpirun ./xhpl--nodes=3 --ntasks-per-node=2申请 6 个进程;mpirun ./xhpl不能带 hostfile,要让 mpirun 直接继承 Slurm 的分配(否则 hostfile 里的节点可能不在分区内,见踩坑)。
P×Q 与 Slurm 任务数的关系:Slurm 只负责把 6 个 MPI 进程拉起来分到节点上,它不知道 HPL 内部在做什么;而 HPL.dat 里的 P×Q 定义如何把 N×N 矩阵切给各进程。两者必须相等且需手动对齐——Slurm 不会替你改 HPL.dat。
HPL.dat 关键参数与选取依据
1 # of problems sizes (N)
24000 Ns
1 # of NBs
128 NBs
0 PMAP process mapping (0=Row-,1=Column-major)
1 # of process grids (P x Q)
2 Ps
3 Qs
- N:HPL 解 N×N 双精度矩阵,占用内存 ≈ 字节。3 个计算节点每个 RealMemory ≈ 1935 MB,总内存约 字节,按 80% 利用率反推 。
- NB:常用值 128 / 192 / 256,在 N=10000 下实测 GFLOPS 约 20 / 16 / 14,选 128。
- P×Q:取接近正方形以均衡通信(1×6 会让某一维通信特别慢);取 是因为 HPL 沿进程列方向的 panel 分解在关键路径上,让行数 P 小一点能缩短这条串行路径的通信开销。
跑分结果:多节点(3 节点、参考 BLAS)单组约 16 分钟,GFLOPS 在 ~10 量级。
这个 ~10 的数字看起来很低,但它是合理的。因为多节点跑的是 netlib 参考 BLAS(朴素三重循环),叠加 VMware NAT 的跨节点网络瓶颈。bonus 部分会证明:光是把参考 BLAS 换成优化库,单节点就能提升近 20 倍。目前来看,BLAS 实现是 HPL 性能的主导因素,而不是节点数。
踩坑记录
- hostfile 与 Slurm 分配冲突:
--hostfile ~/hostfile.txt -n 6报hostfile contains node not present in the allocation: node01,因为 node01 不在 debug 分区。删掉 hostfile,让 mpirun 继承 Slurm 分配即可。 - PRTE 通信中断:N=24000 长时间满载后出现
lost communication with a remote daemon(HNP daemon on node02,remote on node03)。发生在计算完成之后,未影响 GFLOPS 与正确性。初步归因为长时间满载下节点资源波动,此处未完全定位,留作后续用更小 N 或监控节点资源来复现。
HPL 性能调优:更换数学库(任务四 bonus)
思考:同一个 HPL、同样的硬件,只换底层 BLAS 库,性能能差多少?
用 Spack 构建了基于四个不同数学库的 HPL,单节点、OMP_NUM_THREADS=2:
| 数学库 | GFLOPS |
|---|---|
| Intel MKL | 91.07 |
| OpenBLAS | 87.48 |
| BLIS | 85.55 |
| netlib(参考实现) | 5.18 |
结果分析:
- MKL 最快,但原因不是 AVX-512。当前宿主机是 Arrow Lake(消费级已无 AVX-512),而且 Spack 把微架构识别为
linux-skylake(只有 AVX2)——所以所有库都是按 AVX2 编译的。MKL 领先是因为在相同 ISA(AVX2/FMA)下,它的微内核、缓存分块和线程调度更成熟。 - OpenBLAS ≈ BLIS:二者都有手写汇编微内核、SIMD 向量化和缓存分块。
- netlib 只有 5.18:纯朴素三重循环。但它是单线程、其余是 2 线程,所以并非纯内核对比。
收获:优化 BLAS 相对参考实现有近 20 倍差距(5 → ~90 GFLOPS)。回头看上一节多节点只有 ~10 的结果,就完全说得通了:那里用的是参考 BLAS。所以真正的生产配置应该是”优化库 + 多节点”。
动态链接排错
异常现象:在初次尝试更换数学库的时候发现 BLIS 版和 netlib 版的 HPL 跑分居然和 OpenBLAS 几乎一样——这不可能,说明它们根本没用上各自声称的库。排查过程:
-
ldd xhpl:发现 BLIS 版、netlib 版的xhpl都指向系统的/lib/x86_64-linux-gnu/libopenblas.so.0,没链到 Spack 编的库。== blis == libopenblas.so.0 => /lib/x86_64-linux-gnu/libopenblas.so.0 == netlib-lapack == libopenblas.so.0 => /lib/x86_64-linux-gnu/libopenblas.so.0 -
nm xhpl | grep dgemm:dgemm_是 undefined → xhpl 没静态链接 BLAS,而是运行时动态去找。 -
objdump -p xhpl | grep RPATH:BLIS 的路径确实在 RPATH 里 → 不是 RPATH 缺失。 -
objdump -p xhpl | grep NEEDED:NEEDED 列表里只有libopenblas.so.0,根本没有libblis.so.4→ HPL 压根没链 BLIS,Spack 写入的 BLIS RPATH 没被用上。 -
zgrep '-o xhpl' build-out.txt.gz:链接命令是... -lopenblas -lm -lmpi,自始至终就是-lopenblas。
根因:HPL 的 ./configure 自动探测 BLAS,按名字试 -lopenblas 时第一个就命中了系统装的 libopenblas-dev,于是无视了 Spack 放在 -L 路径里的 BLIS / netlib。三条链里只有 OpenBLAS 那条碰巧对了,因为它本该链的库也叫 OpenBLAS,Spack 版靠 RPATH 抢在系统前面解析了同名 symbol。整个环境一直被系统 dev 包污染,同名巧合把问题掩盖了很久(我在完成 2025 版 Lab1 的时候就撞过一次,当时误判成了 MPI 通信瓶颈)。
解决:卸掉系统 libopenblas-dev,再 spack install --overwrite 重编 BLIS 和 netlib 两条链。
共享存储:NFS 与 BeeGFS
目标:集群里的多个节点必须看到同一份文件(HPL 的
xhpl、HPL.dat要在每个节点同一路径)。这就需要共享存储。我做了两种:NFS(简单、单点)和 BeeGFS(并行文件系统,贴近真实 HPC)。对比二者能理解并行 I/O 的扩展性。
NFS:统一共享路径(任务二)
两处共享:
- 数据共享:node01 导出
/srv/hpc101-shared,所有节点挂到统一路径/shared/hpc101(node01 自己用符号链接把本地路径也映射成/shared/hpc101)。 - 家目录共享:
/home/zscott从 node01 导出给计算节点,统一个人环境与配置。
为什么导出源(/srv/hpc101-shared)和挂载点(/shared/hpc101)要分开:/srv 是本机对外提供数据的标准位置,适合放导出源;而所有节点统一看到 /shared/hpc101 这个逻辑路径,是为了保证路径一致性——xhpl 和 HPL.dat 在每个节点上必须是同一个绝对路径。
导出配置与选项含义
/home/zscott 192.168.78.0/24(rw,sync,no_subtree_check,no_root_squash)
/srv/hpc101-shared 192.168.78.0/24(rw,sync,no_subtree_check,no_root_squash)
- 网段限制:只有本集群网段的节点可挂载,集群外机器无法访问。
rw:计算节点要往共享目录写 HPL 输出,必须可写。sync:写操作落盘后才返回,数据一致性更有保障。no_subtree_check:关闭子树检查,避免文件移动出问题,也提升性能。no_root_squash:本环境启用它是为了简化多节点 root 操作。但真实实验室 / 生产集群不应启用——否则任一计算节点的 root 可以 root 身份读写共享目录,风险较大。此处因是隔离内网而接受这一风险。
自动挂载:客户端通过 /etc/fstab 配合 x-systemd.automount 实现 NFSv4 自动挂载,首次访问 /home/zscott 和 /shared/hpc101 时由 systemd 触发实际挂载。
验证:跨节点读写、四节点路径一致、四节点 UID/GID 一致。



NFS 的权限判断认 UID 而非用户名,这就引出后续为什么需要集中式身份。如果同一个用户在不同节点 UID 不同,NFS 会当成两个人,权限就乱了。
BeeGFS:并行文件系统(任务二 bonus)
选型:选 BeeGFS 以更贴近真实 HPC 集群的存储层(与 Lustre 同类)。原本想用 Rook-Ceph,但它依赖 K3s,K3s + Ceph 同时跑内存开销太大,单节点仅 1.9 GB 会 OOM,所以放弃。
架构分布(4 台 Debian 节点上按角色部署多个 BeeGFS 服务):
- management(node01):集群注册与协调,不存数据。
- metadata(node02):管理目录、文件名、属性、文件分布。
- storage(node03/04):各挂一块独立 20 GB 盘,实际存放数据块。
- client(四台):内核模块,把
/mnt/beegfs挂成本地目录。
并行 I/O 原理:client 先问 meta”这个文件被切成几块、在哪几个 storage”,拿到分布图后直接并行地向多个 storage 请求各自持有的分片,再拼成完整文件。数据流只发生在 client 与多个 storage 之间,meta 不参与数据块的搬运(只走控制路径)。所以加 storage 节点,总和带宽近似线性增长,meta 一般不会成为数据瓶颈。BeeGFS 提供的是 文件语义(POSIX,挂成普通目录用)。
与 NFS 的区别:
| NFS | BeeGFS | |
|---|---|---|
| 架构 | 单服务端导出目录 | mgmt / meta / storage 分离 |
| 数据分布 | 全在一台服务器 | 文件分块到多个 storage |
| 扩展性 | 受限于单机带宽 | 加 storage 即可扩容 |
验证:跨节点读写正常、health check 全绿、df 显示两块 20 GB 盘聚合成 40 GB。
集群状态与容量验证输出
❯ beegfs node list
ID TYPE ALIAS
m:1 meta node_meta_1
s:1 storage node_storage_1
s:2 storage node_storage_2
mg:1 management management
(外加四个 client)
❯ df -h | grep beegfs
beegfs_nodev 40G 847M 40G 3% /mnt/beegfs
health check 中除”可用容量”因阈值告警外,Reachability / Consistency / Mapping 全部通过。
作业调度:Slurm(任务三)
多个用户、多个作业怎么公平地共享一批计算节点?这里就需要作业调度器(slrum)了。它由控制节点 slurmctld 和各计算节点的 slurmd 组成,靠 MUNGE 做节点间认证。
- MUNGE key 一致:四节点
munge.key的 MD5 相同,这是 Slurm 节点间互信的前提。 - slurm.conf 依据
slurmd -C生成:节点的 CPU / 内存等硬件参数要与实际一致,否则调度器会拒绝节点。 - 验证 slurmctld(node01) 与 slurmd(node02–04) 均 running,节点 idle,
srun/sbatch可正常提交执行。


踩坑:slurmctld/slurmd 在 systemd 下以 User=slurm 启动,但 Slurm 本应以 root 启动后自动降权,导致 Failed to set GID to 0 而 core dump。用 systemd override 清空 slurm.conf 中的 User= / Group= 解决。
Slurm 报的这类错常常在权限降级这一层,而不是配置语法。
容器编排与云原生服务:K3s
HPC 集群越来越多地用 Kubernetes 来跑服务面——监控、面板、CI 等。这里用轻量版 K3s 理解容器编排的基本组件:控制面 / 工作面、Pod、Service、kube-proxy 的转发机制。
部署与原理(K3s 部分)
- node01 内存上调至 4 GB 后部署 K3s server,node02 用 token 加入为 agent(token 是 agent 加入时的共享认证密钥)。
- server 节点跑 API server / scheduler / controller;agent 侧是 kubelet,负责创建和监控 Pod。

验证:replicas=1 时 Pod 只在 node01,但用 node02 的 IP 也能访问。原因是 NodePort 型 Service 会在每个节点都打开同一端口,kube-proxy 收到请求后若本节点没有对应 Pod,就改写目标地址转发到集群内 Pod 的真实 IP。
可观测性:kube-prometheus-stack(进阶任务)
选型与裁剪:用 kube-prometheus-stack 一次性拿到 Prometheus + Grafana + node-exporter + kube-state-metrics + Operator,靠 ServiceMonitor 自动发现、免手写配置。因 node02 仅 2 GB,所以我关掉了 Alertmanager、将 retention 设为 2 天、给 Prometheus 加 cgroup 内存上限。
采集的是指标(metrics),不是日志或追踪。 工作流:Prometheus 主动 pull,目标不写死,而是靠 ServiceMonitor 选择器问 API server 要 Pod 真实 IP(Pod IP 变了也能继续采集)。pull 三类对象——node-exporter(节点)、cAdvisor(容器/Pod)、kube-state-metrics(watch API server,把集群对象状态变成指标,如 Pod 是否 Running、节点是否 Ready)。样本存进 node02 的 TSDB,Grafana 查询可视化。
我用三个场景验证监控栈能不能真的发现异常,每个场景都对应一类不可替代的信息:
-
场景一 · 节点繁忙:在 node02 跑单节点 HPL 的同时看 Grafana,发现指标更新从 30s 一次退化到约 150s 一次。原因是 Prometheus 和 HPL 抢同一节点的 CPU,scrape 拿不到足够调度时间。
这表明监控服务不应和计算任务放在同一节点,否则采样粒度下降、还会污染数据纯净度。
-
场景二 · Pod Pending:提交一个请求 100 GiB 内存的 Pod,
kubectl describe显示Insufficient memory,Grafana 里kube_pod_status_phase{...}的 Pending 为 1。这类异常 node-exporter / cAdvisor 无法感知(Pod 根本没被调度、没占任何资源),只能靠 kube-state-metrics 的对象状态监控。
-
场景三 · 服务不可达:把 nginx Deployment 副本缩到 0,Service 还在但没有就绪 endpoints,
curl被拒,kube_deployment_status_replicas_available从 2 跌到 0。

排障工作流(可将三个场景归纳成一套顺序):先看对象状态(Node/Pod/Service/Endpoint,up==0 列出不通目标)→ 看节点是否繁忙(top nodes、node_load1)→ 看服务/Pod 是否变慢(get endpoints、describe pod 看 limit/request)→ 看 Pod 是否 Pending(kube_pod_status_phase)→ 看服务是否不可达(available 副本、up=0)。
局限:这套栈目前只有指标,能定位”哪个节点/Pod、什么资源、何时异常”,但归因仍需日志——当前靠
kubectl logs/describe手动获取,更完整的做法是加 Loki 做日志聚合。
集中式身份:FreeIPA(进阶任务)
一个集群里几十台机器,怎么保证同一个用户在不同节点是同一个身份、一次登录到处通行?这里就需要集中式身份了。
选型:选 FreeIPA,因为它把 LDAP + Kerberos + CA + DNS 集成在一起(NIS 太老、自己拼 Kerberos/证书/DNS 工作量太大)。又因为 Debian 13 不提供 FreeIPA server 端包,所以我单独新建了一个 Rocky Linux 9 节点——真实集群本就应把身份服务节点与计算/存储节点分开,甚至用不同 OS。
各组件职责:
- LDAP(目录服务):存用户属性——UID、GID、家目录、所属组等。
ipa user-add alice实际是往 LDAP 写uidNumber/gidNumber等记录。 - Kerberos(认证服务):
kinit向 KDC 请求,KDC 用用户密钥加密一张 TGT 返回,本地用输入的密码解密即证明身份。此后用 TGT 向 TGS 换服务票据,服务器只验票、全程密码不过网络。这实现了单点登录:一次kinit,SSH 到其他节点、访问 BeeGFS 都免密。 - SSSD(客户端侧):负责身份解析(
id testuser时向 LDAP 查),核心价值是离线缓存。如果IPA server 单点挂了,已登录用户仍能用缓存继续工作,不会使得整个集群瘫痪。
部署要点:Kerberos 依赖节点间时间一致(TGT 带时间戳防重放),时间差超过 5 分钟 KDC 会当成重放旧票拒绝,所以必须用 chrony 同步时间。
验证:四节点 id testuser 的 UID/GID 完全一致,说明查的是同一个 LDAP 数据源。

收获:
- 以前保证 UID 一致要在每台机器
/etc/passwd手写相同数字,易错;现在数据只有 LDAP 一份,必然一致。- 这直接治好了 NFS/BeeGFS 的隐患:它们认 UID 判权限,UID 不一致就权限混乱;FreeIPA 集中分配并统一下发 UID,从根上消除。
- 三种身份:FreeIPA 管人的身份,Slurm 管作业身份,K3s 管工作负载(Pod)身份。
集群网络入口:从 Ingress 到 Gateway API(进阶任务)
一个跑在集群内部的服务(这里是 Grafana),怎么让集群外的浏览器通过域名访问到?这条从集群外进入 Pod 的路径要穿过好几层,每层各管一件事。
目标:让集群外浏览器通过 grafana.hpc.internal 访问集群内的 Grafana。
初始方案:MetalLB + ingress-nginx
沿请求路径从外到内,每一层的职责:
- 入口 IP 层 · MetalLB:裸金属集群默认没有集群外可路由的地址(云上由云厂商 LB 提供,自建环境这个位置是空的)。MetalLB 从预留地址段(192.168.78.240–245)分一个给入口服务(当前
192.168.78.240),并在局域网里用 ARP “认领”这个地址,让发往它的流量落到某个节点。它只把流量引到门口,不看请求内容。 - 路由层 · ingress-nginx:反向代理,读请求里的域名和路径(
grafana.hpc.internal+/),据此决定转发给谁。它依据的规则来自 Ingress 对象(注意:Ingress 对象只是声明式配置,真正干活的是 ingress-nginx 这个 controller)。 - 服务层 · Service + kube-proxy:Pod 会重启、IP 会变,Service 给后端一个固定的内部地址,kube-proxy 把流量转交给当前真正的 Grafana Pod。
- 工作负载 · Grafana Pod:监听 3000,真正处理请求。
两个不在主线、但支撑主线的组件:
- CoreDNS:集群内部各服务按名字互相发现(东西向)。它不负责把外部域名
grafana.hpc.internal解析成192.168.78.240——那是访问者自己的 DNS 或 hosts 文件做的。 - Flannel:CNI,给每个 Pod 分配内部 IP、让跨节点 Pod 互通,是整个网络的底座。
完整请求路径:浏览器解析域名 → 流量发往 VIP,MetalLB 引到某节点 → 交给 ingress-nginx → 按 Ingress 规则转发给 kps-grafana → 经 Service/kube-proxy 送到 Grafana Pod(10.42.0.40:3000)→ 原路返回。
❯ curl -I --resolve grafana.hpc.internal:80:192.168.78.240 http://grafana.hpc.internal/
HTTP/1.1 302 Found
Location: /login
跳转到 /login 是 Grafana 未登录时的正常响应,说明整条链路已通。
易混:CoreDNS 是集群内服务,不在外部进集群的入口路径上。
改进方案:换成 Gateway API(Envoy Gateway)
调研时发现 ingress-nginx 已于 2026 年初被 Kubernetes 官方退役、仓库归档,后续发展全部转移到新的 Gateway API。于是把入口这一层升级到 Gateway API。
只换路由层:ingress-nginx → Envoy Gateway,Ingress 对象 → Gateway API 的三个对象:
- GatewayClass:声明由谁实现这个入口(基础设施方);
- Gateway:定义入口监听哪些端口(集群运维方);
- HTTPRoute:定义具体域名/路径转发给谁(应用开发方)。
功能不变(还是读域名/路径并决定转发给谁),只是引擎换成 Envoy、配置模型从一个耦合的 Ingress 对象拆成三个各管一事的对象”。MetalLB、CoreDNS、Service、Flannel 全部不动——Envoy Gateway 会自动提供一个新的 LoadBalancer Service,其外部 IP 仍由 MetalLB 分配。
❯ kubectl -n envoy-gateway-system get svc -l gateway.envoyproxy.io/owning-gateway-name=eg-gateway
NAME TYPE EXTERNAL-IP PORT(S)
envoy-monitoring-eg-gateway-9f01f6bf LoadBalancer 192.168.78.241 80:32208/TCP
❯ curl -I --resolve grafana-gw.hpc.internal:80:192.168.78.241 http://grafana-gw.hpc.internal/
HTTP/1.1 302 Found
location: /login
新入口拿到的是
192.168.78.241而非.240,因为 ingress-nginx 那套仍占用着.240。两套入口并存。
总结:这些服务是怎么拼成一个集群的
做完 Lab 1 再回头看,这些看似独立的服务其实层层依赖、互相支撑:
- 底座:Flannel/网络 + NFS/BeeGFS 共享存储,让多节点”看到同一份文件、能互相通信”;
- 身份:FreeIPA 统一下发 UID,让存储权限、SSH 免密、作业归属在全集群一致;
- 调度:Slurm 把 HPC 作业公平地分到计算节点;
- 计算:MPI + 优化 BLAS + HPL 构成真正的计算负载,其性能主要由 BLAS 实现决定;
- 服务面:K3s + Prometheus + Gateway API 提供云原生的编排、可观测性与对外入口。
而贯穿始终的那部分,是在内存的约束下不断做取舍。