一台新 ECS 十分钟配成 DFT 计算节点
买好机器到跑出第一个算例之间,真正耗时间的不是 VASP 编译本身,而是那些「装错了才发现的系统小事」。这篇给出一份可复现的初始化脚本,把这些小事一次性做完,并且能用六项检查证明做对了。
为什么值得用脚本,而不是手敲
手工配置出错的四类原因,几乎每次都一样:
- stack 限制——
ulimit -s默认 8192 KB,VASP 编译到一半Segmentation fault,而且换个 shell 又复現,很多人会误以为是编译器问题。 - 编译器与 MPI 混搭——用 gcc 编译却链接 Intel MPI,或者反过来。能编过,跑起来在第一次
MPI_Allreduce就挂。必须同族搭配。 - scratch 落在系统盘——WAVECAR 与临时波函数把 40 GB 系统盘写满,机器卡死,还可能连带影响同机其他服务。
- limits 只改当前 shell——
ulimit -s unlimited敲在终端里,退出即失效;必须写进/etc/security/limits.d/。
这四件事都可以在开跑之前用脚本消灭,代价是十分钟。
怎么用
# 1. 下载(也可以直接看最后一节的全文)
curl -O https://physedu.top/compute/assets/dft-bootstrap.sh
# 2. 先干跑:只打印会执行的命令,不改系统
bash dft-bootstrap.sh --dry-run
# 3. 确认无误后执行
sudo bash dft-bootstrap.sh
脚本是幂等的:重复执行不会重复装包,已存在的用户、目录、limits 文件会跳过。
脚本做了哪六件事
1. 装环境:gfortran、OpenMPI、OpenBLAS、LAPACK、ScaLAPACK、FFTW3(+MPI)、HDF5(+MPI)、numactl、iotop、sysstat。Debian/Ubuntu 走 apt,RHEL/CentOS/阿里云 Linux 走 dnf 回退 yum,约 1~2 GB。
2. 准备 /scratch:如果 /scratch 已经是独立挂载点就跳过;否则建立目录并明确警告「当前在系统盘上」——这是故意不自动格式化任何磁盘,因为自动分区是灾难的主要来源。
3. 建计算账号:dft 用户,/opt/src(源码)、/opt/build(构建)、/scratch(临时)三个目录归属它。计算不用 root 跑,是习惯也是安全边界。
4. 写 limits:/etc/security/limits.d/99-dft.conf,stack unlimited 与 nofile 65536。
5. 生成 Makefile.include 模板:VASP 6 的通用 GNU 版,注释里写了 MKL 的替换行。模板不等于可直接用——路径与 MPI 家族要按你的源码确认。
6. 验收:下面六项,每项都要有输出。
六项验收与判定标准
gfortran --version | head -1 # 有版本号,且与 mpif90 同代
mpif90 -show # 输出的编译器路径与 gfortran 一致(同族)
mpirun --version | head -1 # 有版本号;RHEL 系先 source 环境
df -h /scratch # 确认挂的是数据盘,不是 / 所在盘
ulimit -s # unlimited 或 ≥ 65536
numactl --hardware | head -6 # 看 NUMA 节点数,决定后续绑核策略
第三项在 RHEL 系最容易翻车:mpif90 在 PATH 里但 mpirun 不在,因为 openmpi 的环境脚本需要 source。脚本会打警告而不是静默继续。
它不做什么
- 不安装 VASP、Gaussian 或任何商业软件。这些软件的许可在你自己手里,脚本只准备环境,源码与许可都不经手。
- 不格式化磁盘、不改分区表、不动 fstab。自动磁盘操作省下的两分钟,值得用一次数据丢失来换吗。
- 不碰 nginx、MySQL、面板与任何 web 服务。这台机器上可能同时跑着别的项目,脚本的作用域只有编译环境。
- 不调内核参数。透明大页、swappiness 这类参数该不该改取决于你的负载,改了不实测等于赌。
常见疑问
能不能只用 MKL 不装 OpenBLAS?可以,把 Makefile.include 里 BLAS/LAPACK/FFTW/ScaLAPACK 四行换成注释里的 MKL 行,同时确保 Intel 编译器与 Intel MPI 配套。混搭是最常见的失败原因。
2 核 2 GB 的机器能跑吗?能装能编译,但跑不动真实算例。这样的机器适合当跳板机或做编译验证,正式计算至少要 16 核、32 GB 起。
脚本跑完就能提交任务了吗?不能,还差三步:源码放进去、Makefile.include 按实际路径改、用一个小算例标定每步耗时。标定这一步决定了后面所有关于「要多少核、要多少钱」的判断。完整流程在这里。
内网多台机器呢?每台跑一遍即可;跨节点并行还要额外确认 SSH 免密与主机名解析,见多节点并行。
脚本全文
#!/usr/bin/env bash
# dft-bootstrap.sh — 把一台全新的 ECS 配成能编译 VASP / 跑 Gaussian / LAMMPS 的计算节点
# 用法:
# bash dft-bootstrap.sh --dry-run # 只看会做什么,不改系统
# sudo bash dft-bootstrap.sh # 真正执行
# 特性:幂等、只增不改、不碰 web 服务与数据库;VASP 源码需自备(许可在你自己手里)。
set -euo pipefail
DRY=0
for a in "$@"; do
case "$a" in
--dry-run) DRY=1 ;;
-h|--help) sed -n '2,9p' "$0"; exit 0 ;;
*) echo "未知参数: $a"; exit 2 ;;
esac
done
say() { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[!]\033[0m %s\n' "$*"; }
fail() { printf '\033[1;31m[x]\033[0m %s\n' "$*" >&2; exit 1; }
run() {
if [ "$DRY" = 1 ]; then printf ' \033[2m$ %s\033[0m\n' "$*"; return 0; fi
printf ' $ %s\n' "$*"; eval "$@"
}
[ "$(id -u)" = 0 ] || [ "$DRY" = 1 ] || fail "请用 root 或 sudo 运行"
have() { command -v "$1" >/dev/null 2>&1; }
os=""
if have apt-get; then os=deb; elif have dnf; then os=rpm; elif have yum; then os=yum; else fail "只支持 Debian/Ubuntu 与 RHEL/CentOS/Alibaba Cloud Linux"; fi
say "发行版包管理器: $os"
say "1/6 安装编译与并行运行环境(约 1-2 GB,10 分钟)"
if [ "$os" = deb ]; then
run "apt-get update -qq"
run "DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential gfortran openmpi-bin libopenmpi-dev libopenblas-dev liblapack-dev libscalapack-openmpi-dev libfftw3-dev libfftw3-mpi-dev libhdf5-openmpi-dev numactl htop iotop sysstat"
else
run "dnf install -y epel-release || yum install -y epel-release || true"
run "dnf install -y gcc gcc-gfortran gcc-c++ make openmpi openmpi-devel openblas-devel lapack-devel scalapack-openmpi-devel fftw-devel fftw-mpi-devel hdf5-openmpi-devel numactl htop iotop sysstat || yum install -y gcc gcc-gfortran gcc-c++ make openmpi openmpi-devel openblas-devel lapack-devel fftw-devel numactl htop iotop sysstat"
fi
say "2/6 准备 /scratch(优先本地 NVMe,DP 计算的 IO 命脉)"
if mountpoint -q /scratch 2>/dev/null; then
say " /scratch 已挂载,跳过"
elif [ ! -e /scratch ]; then
run "mkdir -p /scratch"
warns=1; warn "没有检测到独立数据盘,/scratch 建立在系统盘上"
warn "正式计算前请把数据盘挂到 /scratch(见文章《云上跑 VASP 全流程》第 2 步)"
fi
say "3/6 建立计算账号与目录约定"
if ! id dft >/dev/null 2>&1; then
run "useradd -m -s /bin/bash dft"
else
say " 用户 dft 已存在"
fi
run "mkdir -p /opt/src /opt/build && chown -R dft:dft /opt/src /opt/build /scratch"
say "4/6 提高资源上限(stack unlimited 是 VASP 编译期的头号报错来源)"
if [ -f /etc/security/limits.d/99-dft.conf ]; then
say " 99-dft.conf 已存在,跳过"
else
if [ "$DRY" = 1 ]; then echo ' $ cat > /etc/security/limits.d/99-dft.conf'; else
cat > /etc/security/limits.d/99-dft.conf <<'LIM'
dft soft stack unlimited
dft hard stack unlimited
* soft stack unlimited
* hard stack unlimited
* soft nofile 65536
* hard nofile 65536
LIM
fi
fi
say "5/6 生成 Makefile.include 模板(VASP 6 通用版,需按你的源码调整路径)"
TMEM=/opt/src/Makefile.include.template
if [ "$DRY" = 1 ]; then echo " \$ write $TMEM"; else
cat > "$TMEM" <<'MK'
# 由 dft-bootstrap.sh 生成的模板:先 cp 到 vasp 源码根目录再按注释修改
# 关键:编译器与 MPI 必须同一家族(gcc 配 openmpi,Intel 配 Intel MPI,切勿混搭)
CPP_OPTIONS = -DHOST=\"LinuxGNU\" -DMPI -DMPI_BLOCK=8000 -Duse_collective -DscaLAPACK -DCACHE_SIZE=4000 -Davoidalloc -Dvasp6 -Duse_bse_te -Dtbdyn -Dfock_dblbuf
CPP = gcc -E -P -C -w $*$(FUFFIX) >$*$(SUFFIX)
FC = mpif90 -fopenmp
FCL = mpif90 -fopenmp
FREE = -ffree-form -ffree-line-length-none
FFLAGS = -w -O2 -march=native -mtune=native
OFLAG = -O2 -march=native -mtune=native
OFLAG_IN = $(OFLAG)
DEBUG = -O0
BLAS = -lopenblas
LAPACK = -lopenblas
BLACS =
SCALAPACK = -lscalapack-openmpi
FFTW = -lfftw3 -lfftw3_omp
# 若用 MKL,把上面四行换成:
# BLAS = LAPACK = -mkl ; FFTW = -mkl ; SCALAPACK = -lmkl_scalapack_lp64 -lmkl_blacs_intelmpi_lp64
OBJECTS = fftw3d.o fft3dlib.o
INCS = -I$(MKLROOT)/include
LLIBS =
MK
chown dft:dft "$TMEM"
fi
say "6/6 验收:以下每一项都要有输出"
if [ "$DRY" = 1 ]; then
echo ' $ gfortran --version | head -1'; echo ' $ mpif90 -show'; echo ' $ mpirun --version | head -1'
echo ' $ df -h /scratch'; echo ' $ ulimit -s'; echo ' $ numactl --hardware | head -6'
else
gfortran --version | head -1
mpif90 -show
mpirun --version 2>/dev/null | head -1 || warn "mpif90 不在 PATH:RHEL 系需 source /etc/profile.d/modules.sh 或加载 openmpi 环境"
df -h /scratch | tail -1
echo "stack limit: $(ulimit -s)"
numactl --hardware 2>/dev/null | head -6 || true
fi
cat <<'NEXT'
下一步(都需要你自备许可与源码):
1. 把 VASP 源码放到 /opt/src/vasp.6.x/,sudo -iu dft
2. cp /opt/src/Makefile.include.template /opt/src/vasp.6.x/Makefile.include 并按注释改
3. cd /opt/src/vasp.6.x && make DEPS=1 -j4 && make -j4 std gam ncl
4. 用同一输入分别跑 16 / 32 / 64 核,记下墙钟,算出你自己的加速比曲线
5. scratch 指向 /scratch,输出目录另放,避免 WAVECAR 把系统盘写满
本脚本不安装任何商业软件、不修改 nginx/数据库、可重复运行。
NEXT
say "完成"