Linux 服务器配置笔记
记录一下我在服务器上鼓捣了什么。
家目录下的目录结构
家目录~
为/home/username
,主要包含
~/software
目前把第三方软件都安装在这里- 按照每个软件分配次级目录 ,例如
~/software/git
就是 git 的安装位置 ~/software/tmp
把软件的压缩包以及解压后的文件夹放置于此,因为服务器不能连接外网,压缩包通过 ftp 传入。
- 按照每个软件分配次级目录 ,例如
~/scripts
存放一些常用的脚本文件(添加到PATH
)~/pbshome
存放PBS作业提交时的快照~/tmp
存放一些临时文件
配置文件
因为安装软件往往需要设置环境变量,因此在原本的.bashrc
脚本最后加上一行,用
source 命令加载自己的.my_bashrc
脚本:
1 | source ~/.my_bashrc |
把频繁修改的内容写在这个.my_bashrc
脚本中,把原本的.bashrc
以及其他内容都在
Onedrive 上进行了备份。
例如当前(2024-6-05)的.my_bashrc
内容如下
1 | # here is my own shell profile |
这里有一个重要的部分就是多版本gcc共存导致的运行时路径问题,最终没有使用修改环境变量
LD_LIBRARY_PATH
的方法,而是定义了环境变量MY_RPATH
,使用 cmake
编译时,自动加入-Wl,-rpath=
相应选项,确保基于 cmake
和高版本 gcc 编译的程序可以找到正确的动态库,对 gcc
版本敏感的动态库主要有两个:libstdc++.so.6
和libgcc_s.so.1
,对于二进制程序可以使用
ldd
查看使用的对应动态库。
注意:
- vscode remote 的环境变量加载逻辑不一样,remote server
不会因为窗口关闭而关闭,服务进程会持续存在,无法及时基于
.bashrc
等进行更新,需要彻底重启 vscode-server 服务,可以执行命令Kill VS Code Server on Host
,参考VSCode Remote环境变量加载。 - 可以考虑加上
stty -ixon
,避免 tmux 分屏时的终端假死现象,参考这篇博客,但是加上后别的地方也会出现问题,故移除。
软件安装
因为普通用户没有 root 用户权限,服务器还不联网,不能使用傻瓜式的安装,只能在用户家目录下使用源码编译的方式,非常硬核地安装软件,比较复杂,网上教程也不太好找。
git
安装过程主要参考这篇博客
- 在官网或者 github 的 git 仓库下载 git-2.34.8.tar.gz(默认 git 只有 1.8,版本太老了)
- ftp
传到
~/software/tmp
目录下,解压tar -zxvf git-2.34.8.tar.gz
,得到~/software/tmp/git-2.34.8
子目录 - 切换到软件安装目录
~/software
,建立安装目录~/software/git
- 进入
~/software/tmp/git-2.34.8
子目录,make all
和make install
走起,需要指定安装目录
1 | make all |
- 安装完成,接下来把需要的路径添加到
PATH,这里我们在
.my_bashrc
中实现
1 | # git version 2.34.8 |
最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source
命令执行相关脚本,最后测试一下 1
2git --version
which git
使用git之前还需进行必要的配置,我们只关注安装过程,因此略去。
cmake
安装过程主要参考这篇博客
- 在官网下载 cmake-3.24.2.tar.gz(默认 cmake 只有 2.8.12,版本有点低)
- ftp
传到
~/software/tmp
目录下,解压tar -zxvf cmake-3.24.2.tar.gz
,得到~/software/tmp/cmake-3.24.2
子目录 - 切换到软件安装目录
~/software
,建立安装目录~/software/cmake
- 进入
~/software/tmp/cmake-3.24.2
子目录,- 执行
./bootstrap
,好像是引导之类的作用 - 执行 configure 命令,指定安装目录
./configure --prefix=/home/username/software/cmake
make all
和make install
走起,上一步已经指定了安装目录
- 执行
1 | ./bootstrap |
- 安装完成,接下来把需要的路径添加到
PATH,这里我们在
.my_bashrc
中实现
1 | # cmake version 3.24.2 |
最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下
1 | cmake --version |
gcc
gcc 的非 root 用户离线编译安装比其他的软件的源码安装都要复杂:因为它有依赖,无法通过联网下载,要提前下载依赖的压缩包,并且它的编译时间长达好几个小时。
- 先在官网或者镜像网站下载 gcc-11.2.0.tar.gz(默认 gcc 版本 4.8.5,太老了)
- ftp
传到
~/software/tmp
目录下,解压tar -zxvf gcc-11.2.0.tar.bz
,得到~/software/tmp/gcc-11.2.0
子目录 - 进入
~/software/tmp/gcc-11.2.0
子目录,下载依赖- 有网络时,直接执行自带的下载依赖的脚本
./contrib/download_prerequisites
- 无网络时,vim 查看上述脚本,找到需要的 gmp,mpfr,mpc,isl
四个依赖的具体版本,在脚本中提供的链接里下载对应的压缩包,用 ftp
传到
~/software/tmp/gcc-11.2.0
目录之下,例如 gcc-11.2.0 需要的四个依赖版本及其下载地址如下
- 有网络时,直接执行自带的下载依赖的脚本
1 | gmp='gmp-6.1.0.tar.bz2' |
- 无网络时,把脚本中下载命令对应的行删除,然后再执行这个脚本
./contrib/download_prerequisites
,因为脚本在下载压缩包之后好像还干了别的事 - 返回上一层,在
~/software/tmp
下建立编译目录~/software/tmp/gcc-11.2.0-build
,进入这个子目录 - 在编译目录中,执行 configure 命令,命令如下
1 | ../gcc-11.2.0/configure --enable-checking=release --enable-languages=c,c++ --disable-multilib |
- 在编译目录中,执行编译命令:
make
(编译过程非常漫长,可能四五个小时,并且不断有信息输出到控制台) - 切换到软件安装目录
~/software
,建立安装目录~/software/gcc
- 在编译目录中,执行安装命令,注意需要使用 DESTDIR 选项指定安装位置,命令如下
1 | make DESTDIR=/home/username/software/gcc install |
- 安装完成,接下来把需要的路径添加到 PATH,才能让高版本 gcc 发挥作用,但是因为两个版本共存的现状无法改变,没有进行任何环境变量的设置。
在没有版本冲突等问题时,需要修改下面的环境变量来完成gcc的安装。
最基本的可以把 gcc 本身的路径加入 PATH 1
2# gcc version 11.2.0
export PATH=~/software/gcc/usr/local/bin:~/software/gcc/usr/local/lib64:$PATH
为了让环境变量生效,可以退出 shell 重新登录,或者用 source
命令执行相关脚本,可以测试一下,找到正确的高版本 gcc 1
2gcc -v
which gcc
(但是这会影响低版本gcc的使用,我关掉了)
如果这个傻缺的 cmake 找不到高版本的 gcc,总是用默认的
gcc,可以在这里指定一下 1
2export CC=~/software/gcc/usr/local/bin/gcc
export CXX=~/software/gcc/usr/local/bin/g++
为了避免对make
等的额外影响,可以改成 1
2export MY_CC=~/software/gcc/usr/local/bin/gcc
export MY_CXX=~/software/gcc/usr/local/bin/g++
此时cmake可以如下使用 1
cmake -S . -B build -DCMAKE_C_COMPILER=$MY_CC -DCMAKE_CXX_COMPILER=$MY_CXX
同时还需要通过-wl,-rpath=$MY_RPATH
修改程序优先查找的动态库,对应在配置文件中的定义
1
export MY_RPATH=~/software/gcc/usr/local/lib/gcc/x86_64-pc-linux-gnu/11.2.0:~/software/gcc/usr/local/lib64
根据第二篇参考博客,还需要添加一些环境变量(在 PATH 设置之后),比如
1 | # gcc/g++等程序本身的路径 |
但是针对当前的系统,我现在并没有设置这些,只是记录一下。
tmux
tmux 是一个 terminal multiplexer(终端复用器),它可以启动一系列终端会话。 它的主要作用是解绑了会话和终端窗口:关闭终端窗口再打开,会话并不终止,而是继续运行在执行,将会话与终端窗后彻底分离。
系统自带了一个 tmux,不过版本只有 1.8 看着有点低,顺手装一个更新版的。安装过程主要参考这篇博客
- 在官网下载 tmux 和它的依赖 libevent,ncurses,这里通过 ftp 实现
1 | wget -c https://github.com/tmux/tmux/releases/download/3.0a/tmux-3.0a.tar.gz |
- ftp
传到
~/software/tmp
目录下,解压三个包,得到~/software/tmp/tmux-3.0a
等三个子目录
1 | tar -zxvf tmux-3.0a.tar.gz |
- 切换到软件安装目录
~/software
,建立 tmux 依赖的安装目录~/software/tmux_depend/libevent
和~/software/tmux_depend/ncurses
,注意两个依赖将分别安装在 tmux_depend 的下一级目录,而 tmux 无需单独的安装目录 - 安装两个依赖(以第一个为例)
- 进入
~/software/tmp/libevent-2.1.11-stable
子目录 - 执行 configure 命令,指定安装位置
- make, make install 走起
- 进入
1 | cd libevent-2.1.11-stable |
- 安装 tmux
- 进入
~/software/tmp/tmux-3.0a
子目录 - 执行 configure 命令,指定安装位置等选项
- make,这里不需要 install,只要确保可执行文件tmux所在路径可以被找到即可
- 进入
1 | cd tmux-3.0a |
- 安装完成,接下来把需要的路径添加到
PATH,这里我们在
.my_bashrc
中实现
1 | # tmux 3.0a |
最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下
1 | tmux -V |
关于tmux的配置可能有很多问题,例如tmux-256color
不识别,可行的做法是将ncurses提供的lib/terminfo
目录赋值给环境变量$TERMINFO
。
fish
fish比原本的bash舒服多了,这里选择源码安装一下。
- 从官网下载fish的源码包fish-3.3.1.tar.xz,这里并没有采用最新版本,而是采用了ubuntu22所采用的稳定版。
- ftp
传到
~/software/tmp
目录下,解压tar -Jxvf fish-3.3.1.tar.xz
,得到~/software/tmp/fish-3.3.1
子目录,切换到软件安装目录~/software
,建立安装目录~/software/fish
- 进入
~/software/tmp/fish-3.3.1
,fish源码是cmake项目,因此cmake命令直接走起,注意修改一下安装目录即可
1 | cmake -S . -B build -DCMAKE_INSTALL_PREFIX=~/software/fish |
- 安装完成,接下来把需要的路径添加到
PATH,这里我们在
.my_bashrc
中实现
1 | # fish 3.3.1 |
最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下
1 | fish -v |
因为fish本身是基于C++11实现的,我们直接使用系统自带的gcc/g++编译即可,并且不需要修改动态库路径。
ninja
CMake还是搭配ninja比较舒服。
- 直接下载njina的源码压缩包
1 | curl -LJO https://github.com/ninja-build/ninja/archive/refs/tags/v1.11.1.tar.gz |
- ftp
传到
~/software/tmp
目录下,解压tar -zxvf ninja-v1.11.1.tar.gz
,得到~/software/tmp/ninja-1.11.1
子目录,切换到软件安装目录~/software
,建立安装目录~/software/ninja
- 进入
~/software/tmp/ninja-1.11.1
,ninja源码是cmake项目,因此cmake命令直接走起,注意修改一下安装目录即可
1 | cmake -S . -B build -DCMAKE_INSTALL_PREFIX=~/software/ninja |
- 安装完成,接下来把需要的路径添加到
PATH,这里我们在
.my_bashrc
中实现
1 | # ninja |
最后,为了让环境变量生效,可以退出 shell 重新登录,或者用 source 命令执行相关脚本,最后测试一下
1 | ninja --version |
ninja实际使用的C++标准很低,可以直接使用系统自带的gcc/g++编译器。如果需要改成高版本的gcc/g++编译器,还需要手动修改CMakeLists.txt,通过添加
-wl,rpath=
命令来修改动态库的RPATH,否则会找到错误的动态库,运行报错。
Anaconda
使用root用户为服务器的所有用户安装Anaconda,记录一下安装过程。
首先,下载Anaconda的离线安装脚本,大约1个G,下载链接为
https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh
。将安装脚本上传到服务器上,使用root用户执行
1
bash Anaconda3-2024.06-1-Linux-x86_64.sh
在安装过程中需要选择安装位置,默认是当前用户的家目录下,将其修改为/opt/anaconda3-2024
。
在base
环境中,除了自带的库,还额外安装了CPU版本的pytorch,安装命令如下(联网安装)
1
conda install pytorch torchvision torchaudio cpuonly -c pytorch
至此,root用户安装配置完成。
对于每一个用户(无论是普通用户还是root用户),在使用前还需要进行基础配置:
执行
conda init
,conda
会在~/.bashrc
的最后添加一段conda
所需要的启动命令。由于目前系统还找不到conda
,这个命令中必须使用它的完整路径1
/opt/anaconda3-2024/bin/conda init
退出shell并重新登陆,使上述修改生效,此时
which conda
可以找到正确的路径,一般的conda
命令也可以正常使用为了避免
conda
在shell中自动激活环境,可以执行下面的操作,此后只有手动执行conda activate
才会激活环境1
conda config --set auto_activate_base False
上述配置是针对
bash
的,针对fish
的配置需要使用conda init fish
,对应会修改~/.condig/fish/config.fish
配置文件。
补充
我其实还需要一个clangd,但是这个搞起来很麻烦:
- 尝试直接下载的编译好的二进制程序,发现程序依赖的glibc版本要求
GLIBC_2.18
,比系统上的glibc版本更高,程序无法启动; clangd
是LLVM的一个组件,直接拉取整个LLVM项目的源码并编译其中的clangd
,过于繁琐(还有更多的依赖和版本问题),很费时;- 在本地编译一个比系统版本略高的
glibc
,提供给clangd
使用,参考这篇博客。
感觉clangd其实并不是必要的,并且这种问题在版本稍微高一点的系统中就压根不存在,不值得专门去鼓捣这种问题。
PBS本地自动化
下面是我为PBS作业提交加上的一些自动化脚本。
生成项目快照
因为PBS脚本执行时间很长,在执行过程中修改源代码可能会产生影响,
我们必须拷贝整个项目(例如名为demo
)到其它位置(例如~/pbshome/
)中,在拷贝的快照中提交作业,这样我们对代码的后续修改和现有作业的执行不会产生相互影响。
如果当前项目是一个干净的Git项目,也可以选择直接进行本地仓库的克隆,因为.gitignore
的存在,两种行为并不是等价的。
在生成项目快照时,我们可以记录一些关键信息,例如:
- 设置快照名称,自动加上时间戳作为拷贝后的文件夹名称,放置在
~/pbshome/demo/
位置下- 不提供名称时,文件夹名称形如:
snapsho-2024-06-18-11-03
- 提供名称并且不是git克隆行为时,文件夹名称形如:
snapshot-testmail-2024-06-18-11-03
- 提供名称并且是git克隆行为时,还会加上哈希值,文件夹名称形如:
snapshot-testmail-2024-06-18-11-03-bc9716f
- 不提供名称时,文件夹名称形如:
- 在拷贝文件夹中创建专门的日志文件
pbs.log
:(如果日志文件已经存在,则不会做任何修改)- 记录生成快照的拷贝/克隆行为
- 记录作业的描述,目标
通过create_snapshot
脚本实现,最简单的调用命令如下
1
2create_snapshot
create_snapshot -N name
还可以加上作业的描述和目标 1
create_snapshot -N name --desc desc_string --todo todo_string
create_snapshot
脚本放在fenglielie/scripts仓库,便于版本控制。
为了便于可视化操作(查看图片),选择将~/pbshome
通过ssh挂载到vlab
上(要先创建~/pbshome
目录)
1
2
3sudo apt install sshfs
sshfs ustc:~/pbshome ~/pbshome
取消挂载 1
fusermount -u <path>
生成PBS脚本
我们可以使用脚本自动化生成PBS脚本,只需要通过选项或者交互式地传递一些关键信息即可,这些信息包括:
- 作业名称(对应自动生成的PBS脚本名为
<作业名称>.job
) - 队列名称
- 使用的节点数(会自动占满每一个节点的所有核)
- 执行命令
其中:
- 前几个选项如果不通过命令行传入,会交互式地提示用户填写;
- 执行命令选项是可选的,如果不在命令行中提供执行命令,会在最后提示用户必须在PBS脚本中手动添加执行命令。
通过create_pbs
脚本实现,最简单的调用命令如下
1
create_pbs
可以直接加上可选参数 1
create_pbs -N <jobname> -q <queue_name> -l <nodes_num> -r <command>
例如 1
create_pbs -N testmail -q cu2 -l 1 -r "./a.out"
create_pbs
脚本放在fenglielie/scripts仓库,便于版本控制。
PBS自动化邮件通知
PBS作业完成时的自动邮件通知的完整实现方案如下。
本地作业记录和自检
第一部分,在服务器上维护一个简单的作业记录系统:
- 包括管理脚本
~/scripts/pbs_manager
和记录文件~/scripts/pbs_records.txt
(需要将pbs_manager
所在路径添加到PATH
) - 记录文件中的条目包括作业id(纯数字)和作业根目录(绝对路径)
- 提交作业后,需要手动执行脚本将作业id和作业根目录添加到作业记录文件中,例如
pbs_manager add 12223 -d .
,这里-d
选项指定目录,缺省时默认使用执行命令时的当前目录,在添加记录时会检查作业id的唯一性和目录的合法性 - 可以手动查询当前的所有记录:
pbs_manager list
- 可以移除特定的记录,提供对应的作业id即可:
pbs_manager del 12223
- 无参数调用
pbs_manager
会进行自检
自检的逻辑如下:
- 在shell中调用
qstat
命令,获取并检查返回的字符串,正常情况下,记录文件中的所有作业id都应该在qstat
的返回值中出现,如果没有出现,说明作业已经结束 - 对于已经结束的作业,我们需要处理记录文件中的对应条目:
- 在作业根目录下检索以作业id结尾的文件,它们是PBS系统的标准输出和错误输出文件,例如
demo.o12223
和demo.e12223
- 将检索得到的两个作业输出文件通过
scp
传递到vlab
的固定位置~/pbsdata
- 通过
ssh
在vlab
中执行发送通知邮件的任务(具体细节见邮件发送环节) - 在记录文件中删除此条目
- 在作业根目录下检索以作业id结尾的文件,它们是PBS系统的标准输出和错误输出文件,例如
注意:因为下一个环节的crontab
在自动执行脚本时会缺少相关的环境变量,因此这里在脚本中的qstat
必须使用完整命令形式。
pbs_manager
脚本放在fenglielie/scripts仓库,便于版本控制。
定时任务
第二部分,我们需要使用crontab
定时调用pbs_manager
进行自检,具体做法如下:
使用crontab -e
编辑定时任务,向其中加入两行
1
2* * * * * /bin/bash -c '~/scripts/pbs_manager 2>&1 | while IFS= read -r line; do echo "$(date +\%Y-\%m-\%d\ \%H:\%M:\%S) $line"; done >> ~/scripts/pbs_manager.log'
5 12 * * 2 /bin/bash -c 'cat /dev/null > ~/scripts/pbs_manager.log'
解释一下,第一个定时任务每分钟执行一次,每次无参数调用pbs_manager
,将这个命令的所有输出加上时间戳,以追加方式输出到定时任务的日志文件~/scripts/pbs_manager.log
,在绝大部分时间的记录形如
1
2
32024-06-18 11:32:01 No records found for checking.
2024-06-18 11:33:01 No records found for checking.
2024-06-18 11:34:01 No records found for checking.
在自检发现任务结束并触发邮件发送行为时的记录形如 1
2
3
4
5
62024-06-18 11:19:01 Welcome to Vlab
2024-06-18 11:19:02 Welcome to Vlab
2024-06-18 11:19:02 Welcome to Vlab
2024-06-18 11:19:03 Email sent successfully
2024-06-18 11:19:03 Processed record: 24408
2024-06-18 11:19:03 Record deleted.
第二个定时任务会在每周二中午12:05触发,自动清空日志文件。
发送邮件
因为服务器本身的网络受限,我选择了通过
ssh
将必要数据传递给vlab
服务器,并且在vlab
上调用脚本发送邮件的间接方案。
第三部分,在vlab
上的邮件生成与发送
- 发送邮件的脚本为
~/scripts/send_mail.py
(Python3) - 发送邮件涉及的配置文件为
~/scripts/config.ini
(存储发件邮箱,收件邮箱,授权密码等)
脚本的使用方式例如(这里执行命令所在的位置是用户家目录,即ssh登陆后的默认位置)
1
python3 scripts/send_mail.py --subject "PBS-NOTICE" --body_start "PBS-Job-Finished" --config scripts/config.ini --files file1.txt file2.txt
其中:
--subject
是必选的邮件标题(不能含有空格,否则解析错误)--body_start
是可选的正文开头部分(不能含有空格,否则解析错误)--config
是可选的,指定发送邮件使用的配置文件--files
是可选的,用于生成邮件正文的文本文件- 至多支持三个文件
- 对每个文件的长度有限制,超过限制的文件中间部分会被省略
- 文件不存在或者打开失败不影响邮件的发送,会在邮件正文最后保留错误记录
在第一部分中,脚本在自检发现任务结束后,就会通过ssh
登陆到vlab
并调用上面形式的命令来发送邮件,注意这里的文件也是预先通过scp
传递到~/pbsdata
的,不能使用原本的路径。
send_mail.py
脚本放在fenglielie/scripts仓库,便于版本控制。
USTC LaTeX 使用
USTC LaTeX 是主要支持在线使用的LaTeX平台,基于Overelaf开源版进行的开发,直接支持通过Git仓库同步的功能。 使用Git仓库时,我们可以利用本地的代码编辑器,这比使用浏览器上的编辑器要方便得多,因此记录一下对应的做法。
首先,从网站获取Git仓库链接,通常形如https://latex.ustc.edu.cn/git/xxxxxxx.git
,主分支名称为master
(这个似乎不可以修改)。
然后将其克隆到本地,并且重新取一个仓库名,例如 1
git clone https://latex.ustc.edu.cn/git/xxxxxxx.git latex_test
由于项目的文件在平台上随时有可能被更改,在本地仓库对代码进行修改之后,远程推送很可能会出现推送失败的情况,对应的处理措施如下:
- 第一步,我们需要使用其它分支指向本地仓库的最新版本(确保本地的修改不会丢失)
- 第二步,执行如下命令,确保本地仓库与远程仓库的主分支最新版本保持一致
1 | git fetch --all |
- 第三步,在本地尝试合并分支,然后重新推送
由于平台提供的是HTTPS协议URL,我们在远程操作时需要提供USTC
LaTeX平台的用户名和密码, 可以使用下面的命令选择将身份验证信息保存到本地
1
git config credential.helper store
在配置完成后,我们可能需要再执行一次远程操作并输入身份验证信息,Git会将其保存到~/.git-credentials
文件中,在下一次远程操作时自动应用。
如果希望改变凭证的存储位置,也可以使用下面的命令将其存储到本地仓库中(显然还需要通过.gitignore
将其忽略)
1
git config credential.helper 'store --file=.git-credentials'
注意:
- 平台的Git仓库不支持
force push
和force pull
; - 不建议将多个分支推送到远程仓库,因为平台上无法切换Git分支,只会显示主分支的版本;
- 平台对于通过Git仓库上传的以
.
开头的隐藏文件有安全隔离措施(允许通过Git仓库上传,但是在平台上无法查看和使用其内容,只允许下载),在平台上直接创建的隐藏文件是可以查看的,但是一旦通过Git仓库修改,也会被隔离。 - 有时我们需要改变对这种特殊仓库推送时使用的用户名和邮箱,直接修改仓库内的配置文件即可。
- 对于Overlaef的git功能操作也是类似的,不过它会直接生成一个token用于登录。
USTC HomePage 使用
直接在Windows的文件浏览器路径栏输入ftp://home.ustc.edu.cn
,输入登录名和密码,登录名是邮件帐号@
之前的部分,密码与邮件系统一样。
希望对外提供个人主页服务时,必须先创建子目录public_html/
,
这个目录里的所有文件均可以通过http://home.ustc.edu.cn/~YourID
来访问。在public_html/
中存放index.html
文件就可以提供默认首页,希望访问其它网页时,在URL中加上相对路径即可。