Learning Debian
- 1: 介绍
- 2: 安装
- 2.1: 下载debian
- 2.2: 物理机安装
- 2.3: pve安装
- 2.4: raid安装
- 2.5: 安装完成后的基本配置
- 2.6: 内核配置
- 2.7: 克隆后的配置
- 2.7.1: 修改hostname
- 2.7.2: 静态IP地址
- 3: 网络
- 3.1: 使用qbittorrent
- 3.2: linux bridge 软交换
- 3.3: open vSwitch
- 3.3.1: open vSwitch 安装
- 3.3.2: open vSwitch 简单软交换
- 3.3.3: TODO
- 3.4: nfs 网络文件系统
- 3.5: nfs rdma 支持
- 4: 存储
- 4.1: 用虚拟机实现的SSD NAS存储
- 4.2: [归档]用物理机实现的SSD NAS存储
- 4.3: [归档]用虚拟机实现的SSD NAS存储
- 5: 开发
- 5.1: 开发工具
- 5.2: 编程语言
- 5.2.1: Java 编程语言
- 5.2.2: Golang 编程语言
- 5.2.3: Rust编程语言
- 5.2.4: Python 编程语言
- 5.2.5: Nodejs 编程语言
- 5.3: 构建模板
- 5.3.1: 构建 basic 模板
- 5.3.1.1: 构建 basic 模板
- 5.3.1.2: 创建虚拟机
- 5.3.2: 构建 dev 模板
- 5.3.3: 构建 devserver 模板
1 - 介绍
1.1 - debian介绍
2 - 安装
2.1 - 下载debian
debian 的安装文件分为两种
- netinst : 小型安装镜像,安装过程中需要网络连接
- cd/dvd: 完整的安装镜像,文件较大,包含更好的软件包,可以没有网络连接时安装。
安装目前(2024年11月)最新的 debian 12.8 。
下载 netinst
打开 debian 官网
https://www.debian.org/distrib/
下载最新的版本:
https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.8.0-amd64-netinst.iso
文件大小 662M。
下载 dvd
https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/
下载 debian-12.8.0-amd64-DVD-1.iso 文件,大小为 3.7G。
2.2 - 物理机安装
准备工作
安装版本
更新时间是 2024-09-16, 安装的当时的最新版本 debian 12.7。
制作U盘
用下载下来的 iso 文件制作启动 u 盘。
windows 下一般用 refus 软件。
安装
启动后进入 debian 安装界面,选择 “Graphical install”
- select language: english
- select your location: other -> Asia -> China
- configure locales: United States en_US.UTF-8
- keyboard: American English
配置网络:
- hostname: debian12.local
配置用户和密码:
- password of root:
- 创建新用户
- full name: Sky Ao
- username: sky
- password:
硬盘分区,选择 Guided - use entire disk -> all files in one partition, 等默认分区方案出来之后, 先删除除了 esp 分区之后的分区,然后在空闲空间上选择 create a new partition,大小为空闲空间 - 50g左右(留给 timeshift 做备份), mount 为 /
。剩下的约 50g 空间继续分区,mount 为 /var/timeshift
。
“Finish partitioning and write changes to disk” , 选下一步,会提示没有 swap 空间,询问要不要退回去,选择 no。
确认分区,然后开始安装 base system。
configure the package manager, 选 “china” -> “mirrors.ustc.edu.cn”。
software selection,这是选择要继续安装的内容:
- debian desktop environment: 桌面,我当服务器用就不需要了,取消勾选
- 选择 ssh server 和 standard system utilities
等待安装完成,重启。
小结
安装比较简单,而且过程中可以配置包管理器,这样避免了从国外拉包的麻烦,用国内的服务器速度还是非常好的,因此推荐用网络安装的方式,这样安装完成之后系统和各个包都是最新版本了。
2.3 - pve安装
准备工作
创建虚拟机
General:
- name: debian12
OS:
- iso image: 选 netinst.iso
- type: linux
- version: 6.x - 2.6 kernel
System:
- Graphic card: default
- Machine: q35 (直通时必须)
- SCSI controller: Virtio SCSI single
- qemu agent: 勾选
- bios: OVMF(UEFI) (直通时必须)
- EFI storage: local
- Format: qemu image format(qcow2)
Disk:
- bus/device: SCSI
- SCSI Controller: 自动选择 Virtio SCSI single
- Cache: default
- IO Thread: 勾选
- Storage: local
- format: QEMU image format(qcow2)
- 高级选项中:勾选 backup
- side: 512g
cpu:
- Type:host (暂时不用担心迁移的问题)
- Socket:1
- Cores: 4
Memory:
- memory: 8192
- minimum memory: 2048
Network:
- bridage: vmbr0
- model: virtIO
确认之后,先别启动,在虚拟机属性中,找到 boot order ,去掉 net0,保留 csi0 和 ide2 光盘启动。
备注:一定要保留硬盘启动并且在光盘前,否则安装完成后重启又进入安装流程了。而 pve 有bug,这种情况下无法关机,只能把整机重启,非常烦人。
安装
启动并开始安装
启动后进入 debian 安装界面,选择 “Graphical install”
- select language: english
- select your location: other -> Asia -> China
- configure locales: United States en_US.UTF-8
- keyboard: American English
配置网络:
- hostname: debian12.local
配置用户和密码:
- password of root:
- 创建新用户
- full name: Sky Ao
- username: sky
- password:
硬盘分区,选择 Guided - use entire disk -> all files in one partition, 等默认分区方案出来之后, 先删除除了 esp 分区之后的分区,然后在空闲空间上选择 create a new partition,大小为空闲空间 - 50g左右(留给 timeshift 做备份), mount 为 /
。剩下的约 50g 空间继续分区,mount 为 /timeshift
。
“Finish partitioning and write changes to disk” , 选下一步,会提示没有 swap 空间,询问要不要退回去,选择 no。
确认分区,然后开始安装 base system。
安装完成后,询问要不要扫描更多的媒体,选择 no。
configure the package manager, 选 “china” -> “mirrors.ustc.edu.cn”。
software selection,这是选择要继续安装的内容:
- debian desktop environment: 桌面,我当服务器用就不需要了,取消勾选
- 选择 ssh server 和 standard system utilities
等待安装完成,重启。
2.4 - raid安装
先准备好两块硬盘,重新分区,并保持两个硬盘的分区方案一致。
第一块硬盘,先后分区为:
- 512 MB: 分区选择 “EFI System Partition”
- 剩余空间-30g:分区选择不使用该分区(use as:“do not use”),准备 raid 后给 “/” 用
- 30g:分区选择不使用该分区(use as:“do not use”),准备 raid 后给 “/timeshift” 用
第二块硬盘和第一块硬盘保持一致,先后分区为:
- 512 MB: 分区选择不使用该分区(use as:“do not use”)
- 剩余空间-30g:分区选择不使用该分区(use as:“do not use”),准备 raid 后给 “/” 用
- 30g:分区选择不使用该分区(use as:“do not use”),准备 raid 后给 “/timeshift” 用
然后选择 “Configure software RAID”, 将两块大的分区和两块小的分区分别创建 raid0 。
这样就得到两个 raid0 device,大小分别为 1.7t 和 60g。
分别格式化为 ext4,挂载为 “/” 和 “/timeshift” 。
然后正常安装 debian12。
2.5 - 安装完成后的基本配置
2.5.1 - timeshift
备注:安装完成之后,第一时间安装 timeshift 进行备份,后续操作中出现任何失误都可以通过 timeshift 来选择性的恢复到中间状态,避免出错后需要重新安装。
具体操作参考:
https://skyao.io/learning-ubuntu-server/docs/installation/timeshift/
安装
先 su 到 root,再进行安装:
su root
apt install timeshift
配置
找到 timeshift 分区的 UUID:
lsblk -f
例如这个机器有三块硬盘, /var/timeshift
所在的分区 UUDI 为 3c5ad47e-4318-4797-8342-7e602ac524d2
:
$ lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
nvme1n1
`-nvme1n1p1 ext4 1.0 ccae6bf3-d4cd-422d-b67a-b5b8dfe83fc6 782.2G 0% /var/data2
nvme0n1
`-nvme0n1p1 ext4 1.0 eff3a45e-be5e-4f5e-a969-0998a8a10e33 782.2G 0% /var/data
nvme2n1
|-nvme2n1p1 vfat FAT32 C4B5-2470 505.1M 1% /boot/efi
|-nvme2n1p2 ext4 1.0 41949492-a351-4770-80f6-d4c7dc5b23bc 171.2G 1% /
`-nvme2n1p3 ext4 1.0 3c5ad47e-4318-4797-8342-7e602ac524d2 48G 0% /var/timeshift
然后设置 backup_device_uuid ,注意 timeshift 在第一次使用时会读取 default.json 文件:
vi /etc/timeshift/default.json
验证一下:
timeshift --list
这个时候还没有进行备份,没有 snapshot:
timeshift --list
First run mode (config file not found)
Selected default snapshot type: RSYNC
Mounted '/dev/nvme2n1p3' at '/run/timeshift/3424/backup'
Device : /dev/nvme2n1p3
UUID : 3c5ad47e-4318-4797-8342-7e602ac524d2
Path : /run/timeshift/3424/backup
Mode : RSYNC
Status : No snapshots on this device
First snapshot requires: 0 B
No snapshots found
此时会自动创建配置文件 /etc/timeshift/timeshift.json
,后续修改配置就要修改这个文件。
配置 excludes
除了基本的 backup_device_uuid 外,还需要配置 excludes 以排除不需要 timeshift 进行备份的内容。
{
"backup_device_uuid" : "3c5ad47e-4318-4797-8342-7e602ac524d2",
......
"exclude" : [
"/root/**",
"/home/**",
"/timeshift/**",
"/var/data/**",
"/var/data2/**",
"/var/data3/**"
],
......
}
需要排除的内容通常包括用户目录(/root/
和 /home/
),以及资料存储如我这里的 "/var/data/
等几块用来存储的硬盘,以及 timeshift 自身所在目录 /timeshift/
(取决于安装debian时选择的timeshift分区的挂载路径)。
配置自动备份
设置每天/每周/每月的自动备份:
{
......
"schedule_monthly" : "true",
"schedule_weekly" : "true",
"schedule_daily" : "true",
......
"count_monthly" : "2",
"count_weekly" : "3",
"count_daily" : "5",
......
}
创建快照
先不做任何操作,在操作系统安装完成之后,第一时间进行备份:
timeshift --create --comments "first backup after install"
第一次备份大概要消耗2.3g的存储空间。
2.5.2 - path修改
问题描述
debian 12 默认的 PATH 路径有点少:
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/games
很多常见的命令都会因为不包含在 PATH 中而无法使用,报错 “command not found”:
$ usermod -aG sudo sky
bash: usermod: command not found
打开 /etc/profile
文件看到:
if [ "$(id -u)" -eq 0 ]; then
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
else
PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
fi
export PATH
看上去像是没有自动 source /etc/profile
,比如我用 su 到 root 账号后执行 source,那就正常的得到上面的 PATH:
$ su root
Password:
$ id
uid=0(root) gid=0(root) groups=0(root)
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/games
$ source /etc/profile
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
普通账号的修复
对于普通账号,比如我安装时建立的 sky 账号,只要简单在 .zshrc 中加入:
# If you come from bash you might have to change your $PATH.
# export PATH=$HOME/bin:/usr/local/bin:$PATH
export PATH=$HOME/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
重新登录 sky 账号,验证即可:
$ echo $PATH
/home/sky/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
这个需要先安装 zsh 和 oh-my-zsh,bash 应该类似,只是我目前基本只用 zsh。
root 账号的修复
貌似没有找到解决不自动 source /etc/profile
的办法,所以只能手工执行
source /etc/profile
来解决。或者,类似 sky 账号那样,安装 zsh 和 oh-my-zsh,但发现 root 账号不能改成默认使用 zsh,只能在 su 到 root 账号之后,手工执行 zsh
来从 bash 换到 zsh。
2.5.3 - sudo设置
安装
先 su 到 root 账号,安装 sudo:
apt install sudo
问题
安装时默认的 sky 账号是没有 sudo 权限的:
$ id
uid=1000(sky) gid=1000(sky) groups=1000(sky),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev)
$ sudo ls
[sudo] password for sky:
sky is not in the sudoers file.
解决方案
先 su 为 root,然后为 sky 账号加入 sudo:
# 如果没有修复 path 的问题,则会报错找不到 usermod
# export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
usermod -aG sudo sky
退出 sky 账号,再次登录就可以 sudo 了:
$ ls
[sudo] password for sky:
bin debian12 temp work
$ id
uid=1000(sky) gid=1000(sky) groups=1000(sky),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev)
2.5.4 - git
直接 apt 安装:
apt install git
检查版本:
$ git version
git version 2.39.5
配置代理
mkdir -p ~/.ssh/
vi ~/.ssh/config
增加内容为:
# for github
Host github.com
HostName github.com
User git
# for HTTP proxy
#ProxyCommand socat - PROXY:192.168.0.1:%h:%p,proxyport=7890
#ProxyCommand socat - PROXY:192.168.2.1:%h:%p,proxyport=7890
#ProxyCommand socat - PROXY:192.168.3.1:%h:%p,proxyport=7890
#ProxyCommand socat - PROXY:192.168.5.1:%h:%p,proxyport=7890
# for socks5 proxy
#ProxyCommand nc -v -x 192.168.0.1:7891 %h %p
#ProxyCommand nc -v -x 192.168.2.1:7891 %h %p
#ProxyCommand nc -v -x 192.168.3.1:7891 %h %p
#ProxyCommand nc -v -x 192.168.5.1:7891 %h %p
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_github
其他设置参考: https://skyao.io/learning-git/docs/installation/initial/
2.5.5 - zsh
安装配置 zsh
安装zsh
首先安装 zsh:
sudo apt install zsh zsh-doc
安装 Oh my zsh!
在 zsh 终端执行:
# 如果被墙则增加代理设置
# export all_proxy=socks5://192.168.2.1:7891
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
DNS 污染问题:
如果遇到 DNS 污染,导致 raw.githubusercontent.com 被解析到 127.0.0.1 或者 0.0.0.1 导致无法访问。需要修改 hosts 文件:
sudo vi /etc/hosts
增加一行:
199.232.68.133 raw.githubusercontent.com
中途询问是否把zsh作为默认 shell 时选择Y:
Do you want to change your default shell to zsh? [Y/n] Y
Changing the shell...
安装字体和主题
在这里下载并安装几个字体
https://github.com/romkatv/powerlevel10k#meslo-nerd-font-patched-for-powerlevel10k
- MesloLGS NF Regular.ttf
- MesloLGS NF Bold.ttf
- MesloLGS NF Italic.ttf
- MesloLGS NF Bold Italic.ttf
mkdir -p ~/.fonts
wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf -O ~/.fonts/MesloLGS_NF_Regular.ttf
wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf -O ~/.fonts/MesloLGS_NF_Bold.ttf
wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf -O ~/.fonts/MesloLGS_NF_Italic.ttf
wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf -O ~/.fonts/MesloLGS_NF_Bold_Italic.ttf
执行
$ ls ~/.fonts
可以看到下载好的字体文件:
MesloLGS_NF_Bold_Italic.ttf MesloLGS_NF_Bold.ttf MesloLGS_NF_Italic.ttf MesloLGS_NF_Regular.ttf
执行
fc-cache -f -v
可以看到字体缓存成功:
Font directories:
/root/.local/share/fonts
/usr/local/share/fonts
/usr/share/fonts
/root/.fonts
......
/root/.fonts: caching, new cache contents: 4 fonts, 0 dirs
......
fc-cache: succeeded
下载安装 Powerlevel10k 主题:
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
修改
vi ~/.zshrc
增加内容:
ZSH_THEME="powerlevel10k/powerlevel10k"
POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(history)
POWERLEVEL9K_SHORTEN_DIR_LENGTH=1
# User configuration
export LS_COLORS="rs=0:no=00:mi=00:mh=00:ln=01;36:or=01;31:di=01;34:ow=04;01;34:st=34:tw=04;34:pi=01;33:so=01;33:do=01;33:bd=01;33:cd=01;33:su=01;35:sg=01;35:ca=01;35:ex=01;32:"
安装插件
安装 wd 插件:
sh -c "$(curl -fsSL https://github.com/mfaerevaag/wd/raw/master/install.sh)"
配置以下插件:
git clone https://github.com/zsh-users/zsh-autosuggestions.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
git clone https://github.com/zsh-users/zsh-history-substring-search.git $ZSH_CUSTOM/plugins/history-substring-search
git clone https://github.com/Pilaton/OhMyZsh-full-autoupdate.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/ohmyzsh-full-autoupdate
修改 zsh 配置
vi ~/.zshrc
注释掉这一行:
DISABLE_MAGIC_FUNCTIONS="true"
修改 plugins 为
plugins=(
git
golang
rust
docker
docker-compose
kubectl
npm
node
mvn
sudo
helm
redis-cli
wd
zsh-autosuggestions
zsh-syntax-highlighting
history-substring-search
ohmyzsh-full-autoupdate
)
# User configuration
ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern cursor root line)
ZSH_HIGHLIGHT_PATTERNS=('rm -rf *' 'fg=white,bold,bg=red')
重启 zsh。
Updating plugins and themes Oh My ZSH
--------------------------------------
Updating Plugin — ohmyzsh-full-autoupdate -> https://github.com/Pilaton/OhMyZsh-full-autoupdate
Already up to date.
Updating Plugin — zsh-autosuggestions -> https://github.com/zsh-users/zsh-autosuggestions
Already up to date.
Updating Plugin — zsh-syntax-highlighting -> https://github.com/zsh-users/zsh-syntax-highlighting
Already up to date.
Updating Theme — powerlevel10k -> https://github.com/romkatv/powerlevel10k
Already up to date.
备注: 这个自动更新可能会因为 github.com 被墙无法访问而失败。可以修改 .zshrc 的设置,默认开启代理避免更新时被墙:
# auto start proxy on
export all_proxy=socks5://192.168.2.1:7891;export http_proxy=http://192.168.2.1:7890;export https_proxy=http://192.168.2.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16
然后手工更新 ohmyzsh:
# proxyon
omz update
执行完 ohmyzsh 的更新之后,关闭所有的终端,再重新打开,就会触发 zsh plugins 的自动更新。
配置网络代理
修改 zsh 配置
vi ~/.zshrc
增加以下内容:
# set proxy for different locations
alias proxyon-nansha='export all_proxy=socks5://192.168.0.1:7891;export http_proxy=http://192.168.0.1:7890;export https_proxy=http://192.168.0.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
alias proxyon-tianhe='export all_proxy=socks5://192.168.2.1:7891;export http_proxy=http://192.168.2.1:7890;export https_proxy=http://192.168.2.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
alias proxyon-fenghu='export all_proxy=socks5://192.168.3.1:7891;export http_proxy=http://192.168.3.1:7890;export https_proxy=http://192.168.3.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
alias proxyon-local='export all_proxy=socks5://127.0.0.1:7897;export http_proxy=http://127.0.0.1:7897;export https_proxy=http://127.0.0.1:7897;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
# set default proxy by this line
alias proxyon='proxyon-local'
alias proxyoff='unset all_proxy http_proxy https_proxy no_proxy'
# uncomment next line to enable proxy by default when zsh is opened
# proxyon
2.5.6 - 网络代理
设置网络代理
我通常在 openwrt 上安装 openclash,支持 socks5 和 http 代理,因此设置很简单:
vi ~/.zshrc
加入以下内容:
# set proxy for different locations
alias proxyon-nansha='export all_proxy=socks5://192.168.0.1:7891;export http_proxy=http://192.168.0.1:7890;export https_proxy=http://192.168.0.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
alias proxyon-tianhe='export all_proxy=socks5://192.168.2.1:7891;export http_proxy=http://192.168.2.1:7890;export https_proxy=http://192.168.2.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
alias proxyon-fenhu='export all_proxy=socks5://192.168.3.1:7891;export http_proxy=http://192.168.3.1:7890;export https_proxy=http://192.168.3.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
alias proxyon-qingpu='export all_proxy=socks5://192.168.5.1:7891;export http_proxy=http://192.168.5.1:7890;export https_proxy=http://192.168.5.1:7890;export no_proxy=127.0.0.1,localhost,local,.local,.lan,192.168.0.0/16,10.0.0.0/16'
# set default proxy by this line
alias proxyon='proxyon-nansha'
alias proxyoff='unset all_proxy http_proxy https_proxy no_proxy'
# uncomment next line to enable proxy by default when zsh is opened
# proxyon
开启网络代理
需要开启代理时,输入 proxyon 命令就设置好代理了。不使用时 proxyoff 关闭。
为 sudo 开启代理
出于安全考虑,sudo 默认会重置环境变量(如 http_proxy、https_proxy),防止用户通过环境变量传递潜在的危险参数或越权操作,然后就导致前面的代理设置(本质上是设置环境变量 http_proxy、https_proxy)失效。
但有时我们又不得不使用 sudo 来执行某些需要使用代理的命令,这时就需要为 sudo 开启代理。
此时可以在 sudo 命令前加上 -E
参数,表示保留当前用户的环境变量,如:
sudo -E apt-get update
# 安装 docker 时有时会遇到 download.docker.com 的连接问题,此时可以设置代理
sudo -E apt-get install docker-ce
如果想永久生效,可以修改 sudo 的配置文件:
sudo visudo
在文件中找到下面的内容:
# This preserves proxy settings from user environments of root
# equivalent users (group sudo)
#Defaults:%sudo env_keep += "http_proxy https_proxy ftp_proxy all_proxy no_proxy"
将 #Defaults:%sudo env_keep
这一行的注释去掉,然后 contrl + o
保存退出(备注:这个文件的名字就是 /etc/sudoers.tmp ,不要以为是保存错了)。
此时再使用 sudo 时,就会自动保留当前用户的环境变量,不需要再收工加 -E 参数。
2.5.7 - 安装其他软件
系统类
linux-headers
安装 dkms 和用于 pve 的 linux-headers:
sudo apt install -y gcc make dkms
sudo apt install -y linux-headers-$(uname -r)
sudo apt install --fix-broken
工具类
sudo apt install htop unzip zip curl
修复 locale 报错
默认安装之后经常在执行各种命令时看到如下的警告:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LANGUAGE = (unset),
LC_ALL = (unset),
LC_CTYPE = "UTF-8",
LANG = "en_US.UTF-8"
are supported and installed on your system.
perl: warning: Falling back to a fallback locale ("en_US.UTF-8").
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
可以通过执行 locale
命令来重现这个警告:
解决方案,
vi ~/.zshrc
增加内容:
export LC_CTYPE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
执行
source ~/.zshrc
验证结果。
参考:
网络类
iperf
sudo apt install -y net-tools iperf iperf3
Iperf3 安装时会询问是否系统服务(自动启动),选择 yes,这样方便需要时排查网络。
nc
debian 12 自带的 nc 是 netcat-traditional 包提供的版本:
$ nc -h
[v1.10-47]
connect to somewhere: nc [-options] hostname port[s] [ports] ...
listen for inbound: nc -l -p port [-options] [hostname] [port]
而我一直在 ubuntu / linux mint 中用的 nc 是 netcat-openbsd 包提供的版本:
$ nc -h
OpenBSD netcat (Debian patchlevel 1.226-1ubuntu2)
usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl]
[-m minttl] [-O length] [-P proxy_username] [-p source_port]
[-q seconds] [-s sourceaddr] [-T keyword] [-V rtable] [-W recvlimit]
[-w timeout] [-X proxy_protocol] [-x proxy_address[:port]]
[destination] [port]
而我在设置 git 代理时,通常会使用 nc
来设置,类似:
ProxyCommand nc -v -x 192.168.3.1:7891 %h %p
这个命令在 netcat-traditional 下会报错:
nc: invalid option -- 'x'
nc -h for help
因此需要将默认的 netcat-traditional
包替换为 netcat-openbsd
包:
sudo apt remove -y netcat-traditional
sudo apt install -y netcat-openbsd
安装 socat
debian12 下没有 socat 命令(用于 git http代理),需要安装:
sudo apt install -y socat
sftp server
pve 默认是关闭 sftp 的,需要手动开启:
sudo vi /etc/ssh/sshd_config
找到 Subsystem sftp /usr/lib/openssh/sftp-server
这一行,注释掉,然后新加一行内容:
# Subsystem sftp /usr/lib/openssh/sftp-server
Subsystem sftp internal-sftp
重启 ssh 服务:
sudo /etc/init.d/ssh restart
之后用支持 sftp 的客户端连接即可
nfs client
sudo apt install nfs-common
smb server
安装 samba 服务:
sudo apt install samba
假设要共享的目录是 /mnt/data/shared
, 则需要先创建该目录:
sudo mkdir -p /mnt/data/shared
设置目录权限:
sudo chmod -R 777 /mnt/data/shared
设置目录所有者:
sudo chown -R nobody:nogroup /mnt/data/shared
配置 samba 服务:
sudo vi /etc/samba/smb.conf
在文件末尾添加以下内容:
[shared]
comment = Shared Folder
path = /mnt/data/shared
browseable = yes
read only = no
guest ok = yes
create mask = 0777
directory mask = 0777
并删除这个文件中 [home] 和 [printers] 这两段内容,否则在smb 共享文件列表中会出现 nobody 和 printers 两个目录。
启动 samba 服务并设置为开机启动:
sudo systemctl start smbd
sudo systemctl enable smbd
之后就可以访问了,路径为:
- linux 系统:
smb://192.168.3.175
- windows 系统:
\\192.168.3.175
2.6 - 内核配置
2.6.1 - 查看内核版本
查看当前 debian 内核的版本:
$ uname -r
6.1.0-31-amd64
$ uname -v
#1 SMP PREEMPT_DYNAMIC Debian 6.1.128-1 (2025-02-07)
$ uname -a
Linux debian12 6.1.0-31-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.128-1 (2025-02-07) x86_64 GNU/Linux
这说明安装时的内核版本为 6.1.0-31-amd64,当前已经更新到 6.1.0-31-amd64 版本(debian 12.9,更新时间 2025-02-07)。
其他方式:
$ cat /proc/version
Linux version 6.1.0-31-amd64 (debian-kernel@lists.debian.org) (gcc-12 (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #1 SMP PREEMPT_DYNAMIC Debian 6.1.128-1 (2025-02-07)
dmesg 命令:
$ sudo dmesg | grep Linux
[ 0.000000] Linux version 6.1.0-31-amd64 (debian-kernel@lists.debian.org) (gcc-12 (Debian 12.2.0-14) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #1 SMP PREEMPT_DYNAMIC Debian 6.1.128-1 (2025-02-07)
......
dpkg 命令:
$ dpkg --list | grep linux-image
ii linux-image-6.1.0-31-amd64 6.1.128-1 amd64 Linux 6.1 for 64-bit PCs (signed)
ii linux-image-amd64 6.1.128-1 amd64 Linux for 64-bit PCs (meta-package)
$ dpkg --list | grep -Ei 'linux-image|linux-headers|linux-modules'
ii linux-image-6.1.0-31-amd64 6.1.128-1 amd64 Linux 6.1 for 64-bit PCs (signed)
ii linux-image-amd64 6.1.128-1 amd64 Linux for 64-bit PCs (meta-package)
2.6.2 - 更新内核
自动更新内核
可以单独更新 linux 内核:
$ sudo apt update
$ sudo apt install linux-image-amd64
也可以使用 apt upgrade
更新所有内容,期间如果有内核更新则自动安装:
$ sudo apt update
$ sudo apt upgrade
这个方式会自动更新 linux 内核,但是是安装 debian 12 的设定,比如目前即使是 debian 12.9 版本,也只会使用 linux 6.1.x 内核,不会使用更新的内核版本。
手工更新内核
如果要更新为比默认的 linux 6.1.x 更新的内核版本,则需要手工更新内核。
apt list -a linux-image-amd64
输出为:
Listing... Done
linux-image-amd64/stable-backports 6.12.12-1~bpo12+1 amd64
linux-image-amd64/stable-security 6.1.133-1 amd64
linux-image-amd64/stable 6.1.129-1 amd64
可以看到有多个版本,通常自动更新时只会选择最新的 stable 或者 stable-security 版本,如果需要选择其他版本,则需要手工更新。
比如这里的 stable-backports 6.12.12-1~bpo12+1 版本,手工安装命令为:
sudo apt install -t stable-backports linux-image-amd64=6.12.12-1~bpo12+1
这里的 -t stable-backports
参数表示从 stable-backports 仓库安装软件包,linux-image-amd64=6.12.12-1~bpo12+1
指定了要安装的内核版本。
安装完成后,重启系统:
sudo reboot
重启后,查看内核版本:
uname -r
输出为:
6.12.12+bpo-amd64
可以看到已经更新为 6.12.12 版本。
2.6.3 - 删除内核
多次升级之后,系统内就会累计有多个内核版本,可以考虑删除旧的不用的内核。
参考:
https://askubuntu.com/questions/1253347/how-to-easily-remove-old-kernels-in-ubuntu-20-04-lts
vi remove_old_kernels.sh
新建一个文件内容如下:
#!/bin/bash
# Run this script without any param for a dry run
# Run the script with root and with exec param for removing old kernels after checking
# the list printed in the dry run
uname -a
IN_USE=$(uname -a | awk '{ print $3 }')
if [[ $IN_USE == *-generic ]]
then
IN_USE=${IN_USE::-8}
fi
echo "Your in use kernel is $IN_USE"
OLD_KERNELS=$(
dpkg --list |
grep -v "$IN_USE" |
grep -v "linux-headers-generic" |
grep -v "linux-image-generic" |
grep -Ei 'linux-image|linux-headers|linux-modules' |
awk '{ print $2 }'
)
echo "Old Kernels to be removed:"
echo "$OLD_KERNELS"
if [ "$1" == "exec" ]; then
for PACKAGE in $OLD_KERNELS; do
yes | apt purge "$PACKAGE"
done
fi
执行
bash ./remove_old_kernels.sh
看查看到要删除的内核版本和相关的包,确认没有问题之后再通过
sudo bash ./remove_old_kernels.sh exec
进行实际删除。
之后重启,再检查现有的内核是否符合预期。
2.7 - 克隆后的配置
在使用 pve 等虚拟化软件时,为了方便重用,会将配置好的 debian 系统制作成模版,然后使用时从模版克隆出来。
这样就会有一些特殊的配置需要在克隆之后进行。
2.7.1 - 修改hostname
可以通过 hostnamectl 来修改 hostname,避免 hostname 重复:
sudo hostnamectl set-hostname newNameHere
完成后再额外修改一下 hosts 文件中的 hostname:
sudo vi /etc/hosts
完成后重启即可:
sudo reboot
2.7.2 - 静态IP地址
每个克隆后的虚拟机都应该有自己固定的ip地址,但是通过 dhcp 来修改不合适,毕竟这些经常变化。
因此需要设置静态 ip 地址,每次克隆之后虚拟机就自行设置。
设置静态ip
修改前先备份:
sudo cp /etc/network/interfaces /etc/network/interfaces.bak
看一下目前的网络适配器情况,enp6s18 是正在使用的网卡:
$ ip addr
2: enp6s18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether bc:24:11:97:c4:00 brd ff:ff:ff:ff:ff:ff
inet 192.168.20.228/24 brd 192.168.20.255 scope global dynamic enp6s18
修改网络设置:
sudo vi /etc/network/interfaces
将 enp6s18 原有的配置:
# The primary network interface
allow-hotplug enp6s18
iface enp6s18 inet dhcp
修改为:
# The primary network interface
allow-hotplug enp6s18
# iface enp6s18 inet dhcp
iface enp6s18 inet static
address 192.168.20.25
netmask 255.255.255.0
gateway 192.168.20.1
dns-nameservers 192.168.20.1
保存后重启网络:
sudo systemctl restart networking
之后就可以用新的 ip 地址访问了。
参考资料
3 - 网络
3.1 - 使用qbittorrent
选择版本
让我们快速了解一下 qBittorrent 安装方法之间的一些基本区别:
-
qBittorrent 桌面优势:
- 用户友好界面: 提供直观且易于浏览的图形界面。
- 简洁的体验: 作为开源软件,它没有广告和不必要的捆绑软件。
- 功能丰富:包括顺序下载、带宽调度等功能。
-
qBittorrent-nox 的优势:
- 专为无头系统优化: 专为最小化资源占用而设计,是受限系统的理想选择。
- 网络接口: 允许通过基于网络的界面进行操作。
- 远程管理: 通过网络接口方便管理服务器和远程系统。
自动安装
我用的debian是服务器版本,没有UI界面,因此选择安装 qbittorrent-nox (无图形界面版本):
sudo apt install qbittorrent-nox
为 qBittorrent 创建专用系统用户和组:
sudo adduser --system --group qbittorrent-nox
sudo adduser sky qbittorrent-nox
为 qBittorrent-nox 创建 Systemd 服务文件
sudo vi /etc/systemd/system/qbittorrent-nox.service
内容如下:
[Unit]
Description=qBittorrent Command Line Client
After=network.target
[Service]
Type=forking
User=qbittorrent-nox
Group=qbittorrent-nox
UMask=007
ExecStart=/usr/bin/qbittorrent-nox -d --webui-port=8080
Restart=on-failure
[Install]
WantedBy=multi-user.target
重启 daemon-reload:
sudo systemctl daemon-reload
启动
启动 qbittorrent-nox 准备必要的目录:
sudo mkdir /home/qbittorrent-nox
sudo chown qbittorrent-nox:qbittorrent-nox /home/qbittorrent-nox
sudo usermod -d /home/qbittorrent-nox qbittorrent-nox
启动:
sudo systemctl start qbittorrent-nox
查看启动状态:
sudo systemctl status qbittorrent-nox
看到信息如下:
qbittorrent-nox.service - qBittorrent Command Line Client
Loaded: loaded (/etc/systemd/system/qbittorrent-nox.service; enabled; preset: enabled)
Active: active (running) since Sun 2024-05-05 01:09:48 EDT; 3h 7min ago
Process: 768 ExecStart=/usr/bin/qbittorrent-nox -d --webui-port=8080 (code=exited, status=0/SUCCESS)
Main PID: 779 (qbittorrent-nox)
Tasks: 21 (limit: 9429)
Memory: 6.4G
CPU: 5min 23.810s
CGroup: /system.slice/qbittorrent-nox.service
└─779 /usr/bin/qbittorrent-nox -d --webui-port=8080
May 05 01:09:48 skynas3 systemd[1]: Starting qbittorrent-nox.service - qBittorrent Command Line Client...
May 05 01:09:48 skynas3 systemd[1]: Started qbittorrent-nox.service - qBittorrent Command Line Client.
设置开机自动启动:
sudo systemctl enable qbittorrent-nox
管理
访问 http://192.168.20.2:8080/ ,默认登录用户/密码为 admin
和 adminadmin
。
-
下载
- 默认保存路径:"/mnt/storage2/download"
-
连接
- 用于传入连接的端口:在路由器上增加这个端口的端口映射
-
Web-ui
- 语言:用户语言界面选择"简体中文"
- 修改用户密码
- 勾选 “对本地主机上的客户端跳过身份验证”
- 勾选 “对 IP 子网白名单中的客户端跳过身份验证”:
192.168.0.0/24,192.168.192.0/24
-
高级
- 勾选 “允许来自同一 IP 地址的多个连接”
- 勾选 “总是向同级的所有 Tracker 汇报”
参考资料
手工安装
安装依赖包
先安装依赖包:
sudo apt update
sudo apt install build-essential pkg-config automake libtool git libgeoip-dev python3 python3-dev
sudo apt install libboost-dev libboost-system-dev libboost-chrono-dev libboost-random-dev libssl-dev
sudo apt install qtbase5-dev qttools5-dev-tools libqt5svg5-dev zlib1g-dev
安装 libtorrent 1.2.19
安装libtorrent 1.2.19:
wget https://github.com/arvidn/libtorrent/releases/download/v1.2.19/libtorrent-rasterbar-1.2.19.tar.gz
tar xf libtorrent-rasterbar-1.2.19.tar.gz
cd libtorrent-rasterbar-1.2.19
./configure --disable-debug --enable-encryption --with-libgeoip=system CXXFLAGS=-std=c++14
make -j$(nproc)
sudo make install
sudo ldconfig
如果遇到错误:
checking whether g++ supports C++17 features with -std=c++17... yes
checking whether the Boost::System library is available... no
configure: error: Boost.System library not found. Try using --with-boost-system=lib
需要先安装 libboost-system-dev :
sudo apt install libboost-system-dev
如果遇到错误:
checking whether compiling and linking against OpenSSL works... no
configure: error: OpenSSL library not found. Try using --with-openssl=DIR or disabling encryption at all.
需要先安装 libssl-dev :
sudo apt install libssl-dev
安装 qbittorrent
不敢用太新的版本,还是找个稍微久一点的,继续沿用参考文档里面用的 4.3.9 版本:
wget https://github.com/qbittorrent/qBittorrent/archive/refs/tags/release-4.3.9.tar.gz
tar xf release-4.3.9.tar.gz
cd qBittorrent-release-4.3.9
./configure --disable-gui --disable-debug
make -j$(nproc)
sudo make install
设置开机自启
sudo vi /etc/systemd/system/qbittorrent.service
输入以下内容:
[Unit]
Description=qBittorrent Daemon Service
After=network.target
[Service]
LimitNOFILE=512000
User=root
ExecStart=/usr/local/bin/qbittorrent-nox
ExecStop=/usr/bin/killall -w qbittorrent-nox
[Install]
WantedBy=multi-user.target
启用开机自启:
sudo systemctl enable qbittorrent.service
第一次启动
先手工启动第一次:
sudo qbittorrent-nox
*** Legal Notice ***
qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.
No further notices will be issued.
Press 'y' key to accept and continue...
按 Y 后,Ctrl+C退出。
用 systemctl 后台启动 qbittorrent:
sudo systemctl start qbittorrent.service
参考资料
3.2 - linux bridge 软交换
准备工作
安装好网卡驱动,如 cx3 / cx4 / cx5 的驱动。
搭建软交换
新建 linux bridge
安装 bridge 工具包:
sudo apt install bridge-utils -y
查看当前网卡情况:
$ ip addr
2: enp6s18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether bc:24:11:97:c4:00 brd ff:ff:ff:ff:ff:ff
inet 192.168.20.25/24 brd 192.168.20.255 scope global enp6s18
3: enp1s0f0np0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether b8:ce:f6:0b:ff:7c brd ff:ff:ff:ff:ff:ff
4: enp1s0f1np1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether b8:ce:f6:0b:ff:7d brd ff:ff:ff:ff:ff:ff
enp6s18 是对外的网卡(wan),enp1s0f0np0 和 enp1s0f1np1 准备用来连接其他机器(lan)。
修改 network interfaces,删除所有和 enp6s18 / 是对外的网卡(wan),enp1s0f0np0 / enp1s0f1np1 有关的内容:
sudo vi /etc/network/interfaces
最后保留的内容应该非常少,类似于:
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
然后新建一个 br0 文件来创建网桥:
sudo vi /etc/network/interfaces.d/br0
内容为:
auto br0
iface br0 inet static
address 192.168.20.2
broadcast 192.168.20.255
netmask 255.255.255.0
gateway 192.168.20.1
bridge_ports enp6s18 enp1s0f0np0 enp1s0f1np1
bridge_stp off
bridge_waitport 0
bridge_fd 0
注意这里要把所有需要加入网桥的网卡都列举在 bridge_ports 中(包括 wan 和 lan, 会自动识别) 保存后重启网络:
sudo systemctl restart networking
或者直接重启机器。(如果之前有配置wan口网卡的ip地址,并且新网桥的ip地址和wan的ip地址一致,就必须重启机器而不是重启网路。)
查看改动之后的网络:
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: enp6s18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
link/ether bc:24:11:97:c4:00 brd ff:ff:ff:ff:ff:ff
3: enp1s0f0np0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether b8:ce:f6:0b:ff:7c brd ff:ff:ff:ff:ff:ff
4: enp1s0f1np1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether b8:ce:f6:0b:ff:7d brd ff:ff:ff:ff:ff:ff
6: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 6e:38:a0:77:09:dc brd ff:ff:ff:ff:ff:ff
inet 192.168.20.2/24 brd 192.168.20.255 scope global br0
valid_lft forever preferred_lft forever
检查网络是否可以对外/对内访问。如果没有问题,说明第一步成功,网桥创建好了。
$ brctl show
bridge name bridge id STP enabled interfaces
br0 8000.6e38a07709dc no enp1s0f0np0
enp1s0f1np1
enp6s18
$ bridge link
2: enp6s18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
3: enp1s0f0np0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 1
3: enp1s0f0np0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 hwmode VEB
4: enp1s0f1np1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 1
4: enp1s0f1np1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br0 hwmode VEB
网卡另一头接上其他电脑,通过 dhcp 自动获取了IP地址,而且内外可以互通,测度测试也正常。
软交换就这么搭建好了。
小结和对比
上面这个方案,比之前在 ubuntu server 用的方案要简单很多,当时也用了 linux bridge,但需要建立子网,安装 dnsmaxq 做 dhcp 服务器端,配置内核转发,还要设置静态路由规则。
这个方案什么都不用做,就需要建立一个最简单的 linux bridge 就可以了。
开启内核转发
备注: 发现不做这个设置,也可以正常转发。不过还是加上吧。
sudo vi /etc/sysctl.conf
把这两行注释取消,打开配置:
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
让改动生效:
sudo sysctl --load /etc/sysctl.conf
设置 MTU
默认 mtu 为 1500,为了最大化发挥网卡的能力,需要修改 mtu 为 9000.
对于机器 B / C,只要执行下面的命令即可:
sudo ip link set enp6s16np0 mtu 9000
对于软交换所在的 A 机器,需要将 linux bridge 和相关的网卡都设置为 mut 9000:
sudo ip link set dev br0 mtu 9000
sudo ip link set dev enp1s0f0np0 mtu 9000
sudo ip link set dev enp1s0f1np1 mtu 9000
这个方式只能临时生效,一旦机器重启就会恢复成默认的 mtu 1500。解决的方法是修改 rc.local
参考资料:
性能测试
cx3测试
cx4测试
25g网卡连接速度25g,用 iperf2 测试出来的带宽有23.5g,接近25g的理论值。
忘了有没有改 mtu了,下次再测试看看。
cx5测试
以 cx5 网卡为例,软交换机器 A (ip 为 192.168.0.100)上一块 cx5 双口网卡,另外两台测试机器 B (ip 为 192.168.0.125) / C (ip 为 192.168.0.127) 上一块单口网卡,用 100G dac线材连接。三台机器都安装好 iperf 和 iperf3。
iperf2 测试
在软交换机器 A 上启动 iperf 服务器端:
iperf -s -p 10001
在 B/C 两台机器上分别启动 iperf 客户端:
iperf -c 192.168.0.100 -P 3 -t 10 -p 10001 -i 1
测试直连速度: 达到 99.0 Gits/sec, 非常接近 100G 的理论最大值。
备注: 如果不设置为 mtu 9000, 采用默认的 mtu 1500,只能达到约 94 G 。
[SUM] 0.0000-10.0001 sec 115 GBytes 99.0 Gbits/sec
测试转发速度: 在其中一台机器 B 上启动 iperf 服务器端,然后从另外一台机器 C 上测试连接机器 B, 速度可以达到 76.9 G,和 100G 理论最大值相比损失还是挺大的。
iperf -c 192.168.0.125 -P 2 -t 10 -p 10001 -i 1
[SUM] 0.0000-6.9712 sec 62.4 GBytes 76.9 Gbits/sec
注意:-P 2
也就是启动两个线程,可以测试出最大值,继续增加线程反而会下降。
特别注意的是,网络速度测试时,在软交换机器 A 上,用 top 命令看似乎几乎没有任何性能消耗:
但实际上,在 pve 虚拟机上,显示占用了块两个核心:
可见此时并没有实现我们期待的在进行软交换时启用 rdma 来减少 cpu 消耗的目的。因此,需要继续考虑如何开启 rdma
iperf3 测试
类似的,测试出来 iperf3 下软交换的速度大概是 63.9 G:
$ iperf3 -c 192.168.0.125 -P 2 -t 10 -i 1
......
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 37.2 GBytes 31.9 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 37.2 GBytes 31.9 Gbits/sec receiver
[ 7] 0.00-10.00 sec 37.2 GBytes 31.9 Gbits/sec 0 sender
[ 7] 0.00-10.00 sec 37.2 GBytes 31.9 Gbits/sec receiver
[SUM] 0.00-10.00 sec 74.4 GBytes 63.9 Gbits/sec 0 sender
[SUM] 0.00-10.00 sec 74.4 GBytes 63.9 Gbits/sec receiver
top下依然看到 cpu 占用极低,但 pve 页面显示有 5% 的 cpu。
增加 -Z
参数开启 iperf3 的 zero copy 功能再测试,速度大幅提升达到 77.8 G:
iperf3 -c 192.168.0.125 -P 2 -t 10 -i 1 -Z
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 45.3 GBytes 38.9 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 45.3 GBytes 38.9 Gbits/sec receiver
[ 7] 0.00-10.00 sec 45.3 GBytes 38.9 Gbits/sec 0 sender
[ 7] 0.00-10.00 sec 45.3 GBytes 38.9 Gbits/sec receiver
[SUM] 0.00-10.00 sec 90.6 GBytes 77.8 Gbits/sec 0 sender
[SUM] 0.00-10.00 sec 90.6 GBytes 77.8 Gbits/sec receiver
此时 top 下依然看到 cpu 占用极低,但 pve 页面显示有 6.59% 的 cpu。
参考资料
3.3 - open vSwitch
3.3.1 - open vSwitch 安装
用 apt 安装
sudo apt install openvswitch-switch
查看Open vSwitch(OVS)的版本:
$ sudo ovs-vsctl show
cb860a93-1368-4d4f-be38-5cb9bbe5273d
ovs_version: "3.1.0"
从源码开始编译安装
参考官方文档:
https://github.com/openvswitch/ovs/blob/main/Documentation/intro/install/debian.rst
https://docs.openvswitch.org/en/stable/intro/install/debian/
下载源码
mkdir -p ~/temp/
cd ~/temp/
git clone https://github.com/openvswitch/ovs.git
cd ovs
git checkout v3.5.0
准备编译
apt-get install build-essential fakeroot
打开 ovs 源码文件中的 debian/control.in
文件,找到 Build-Depends:
这一段,将这里列出来的依赖都用 apt 安装一遍。
sudo apt install autoconf automake bzip2 debhelper-compat dh-exec dh-python dh-sequence-python3 dh-sequence-sphinxdoc graphviz iproute2 libcap-ng-dev
sudo apt install libdbus-1-dev libnuma-dev libpcap-dev libssl-dev libtool libunbound-dev openssl pkg-config procps python3-all-dev python3-setuptools python3-sortedcontainers python3-sphinx
sudo apt install libdpdk-dev
准备编译:
$ ./boot.sh && ./configure --with-dpdk=shared && make debian
检查依赖是否都满足要求:
$ dpkg-checkbuilddeps
dpkg-checkbuilddeps: error: Unmet build dependencies: libdpdk-dev (>= 24.11)
但 apt 能安装的最新版本也就是 22.11.7 版本:
apt list -a libdpdk-dev
Listing... Done
libdpdk-dev/stable,stable-security,now 22.11.7-1~deb12u1 amd64 [installed]
只好删除这个版本:
sudo apt remove libdpdk-dev
然后手工安装最新版本的 libdpdk-dev
安装 libdpdk-dev
下载页面:
https://core.dpdk.org/download/
找到 DPDK 24.11.2 (LTS) 这个版本,下载下来:
cd ~/temp/
wget https://fast.dpdk.org/rel/dpdk-24.11.2.tar.xz
tar xvf dpdk-24.11.2.tar.xz
cd dpdk-stable-24.11.2
参考文档: https://github.com/openvswitch/ovs/blob/main/Documentation/intro/install/debian.rst 以及参考 deepseek 的安装指导。
sudo apt install build-essential meson ninja-build python3-pyelftools libnuma-dev pkg-config
meson build
ninja -C build
cd build
sudo ninja install
# 更新动态链接库
sudo ldconfig
安装完成之后,验证一下:
pkg-config --modversion libdpdk
输出为:
24.11.2
继续安装
准备编译:
# 进入 ovs 源码目录
cd ovs
$ ./boot.sh && ./configure --with-dpdk=shared && make debian
检查依赖是否都满足要求:
$ dpkg-checkbuilddeps
dpkg-checkbuilddeps: error: Unmet build dependencies: libdpdk-dev (>= 24.11)
这里要求的是 libdpdk-dev,但前面源码安装出来的是 libdpdk
找到编译出来的 libdpdk.pc 文件:
sudo find / -name "libdpdk.pc" 2>/dev/null
/home/sky/temp/dpdk-stable-24.11.2/build/meson-private/libdpdk.pc
/usr/local/lib/x86_64-linux-gnu/pkgconfig/libdpdk.pc
将 libdpdk.pc 文件复制到 /usr/share/pkgconfig/ 目录:
sudo mkdir -p /usr/share/pkgconfig/
sudo cp /usr/local/lib/x86_64-linux-gnu/pkgconfig/libdpdk.pc /usr/share/pkgconfig/
更新 PKG_CONFIG_PATH:
export PKG_CONFIG_PATH=/usr/share/pkgconfig:$PKG_CONFIG_PATH
备注:如果想永久生效,可添加到 ~/.zshrc
sudo mkdir -p /usr/include/dpdk
sudo ln -s /usr/local/include/* /usr/include/dpdk/
sudo ldconfig
继续编译:
make debian-deb
报错:
dpkg-shlibdeps: error: no dependency information found for /usr/local/lib/x86_64-linux-gnu/librte_vhost.so.25 (used by debian/openvswitch-switch-dpdk/usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk)
Hint: check if the library actually comes from a package.
dh_shlibdeps: error: dpkg-shlibdeps -Tdebian/openvswitch-switch-dpdk.substvars debian/openvswitch-switch-dpdk/usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk returned exit code 255
dh_shlibdeps: error: Aborting due to earlier error
make[1]: *** [debian/rules:8: binary] Error 255
make[1]: Leaving directory '/home/sky/temp/ovs'
make: *** [Makefile:7300: debian-deb] Error 2
报错的原因是 dpkg-shlibdeps 是 Debian 打包工具的一部分,用于自动检测二进制文件的动态库依赖。由于我们通过源码安装了 DPDK,dpkg 不知道 librte_vhost.so.25 属于哪个包,因此报错。
考虑到生成 deb 包不是必须,我们可以直接安装 OVS(不打包成 .deb),这样就不触发 dpkg-shlibdeps 检查。
sudo make install
检查安装之后的版本:
$ ovs-vswitchd --version
ovs-vswitchd (Open vSwitch) 3.5.0
DPDK 24.11.2
安装不带 dpdk
不带 dpdk 会简单很多:
https://cloudspinx.com/build-open-vswitch-from-source-on-debian-and-ubuntu/
sudo dpkg -i ./openvswitch-common_3.5.0-1_amd64.deb sudo dpkg -i ./openvswitch-common-dbgsym_3.5.0-1_amd64.deb sudo dpkg -i ./openvswitch-switch_3.5.0-1_amd64.deb sudo dpkg -i ./openvswitch-switch-dbgsym_3.5.0-1_amd64.deb
sudo apt install libxdp1 libxdp-dev sudo apt install libfdt1 libfdt-dev
ovs-vsctl show ovs-vsctl: unix:/usr/local/var/run/openvswitch/db.sock: database connection failed (No such file or directory)
3.3.2 - open vSwitch 简单软交换
背景
前面用 linux bridge 做软交换,功能没问题,性能看似还行,但其实有不少问题:
- 跑不到网卡极限
- cpu占用较高
- rdma 之类的高级特性缺失
cx5 介绍
https://www.nvidia.com/en-us/networking/ethernet/connectx-5/
NVIDIA® Mellanox® ConnectX®-5适配器提供先进的硬件卸载功能,可减少CPU资源消耗,并实现极高的数据包速率和吞吐量。这提高了数据中心基础设施的效率,并为Web 2.0、云、数据分析和存储平台提供了最高性能和最灵活的解决方案。
这里提到的 “先进的硬件卸载功能,可减少CPU资源消耗”,正是我需要的。
实现最高效率的主要特性:
-
NVIDIA RoCE技术封装了以太网上的数据包传输,并降低了CPU负载,从而为网络和存储密集型应用提供高带宽和低延迟的网络基础设施。
-
突破性的 NVIDIA ASAP² 技术通过将 Open vSwitch 数据路径从主机CPU卸载到适配器,提供创新的 SR-IOV 和 VirtIO 加速,从而实现极高的性能和可扩展性。
-
ConnectX 网卡利用 SR-IOV 来分离对虚拟化环境中物理资源和功能的访问。这减少了I/O开销,并允许网卡保持接近非虚拟化的性能。
关键特性:
- 每个端口最高可达100 Gb/s以太网
- 可靠传输上的自适应路由
- NVMe over Fabric(NVMf)目标卸载
- 增强的vSwitch / vRouter卸载
- NVGRE和VXLAN封装流量的硬件卸载
- 端到端QoS和拥塞控制
cx5 网卡资料:
https://network.nvidia.com/files/doc-2020/pb-connectx-5-en-card.pdf
硬件加速的基本知识
NVIDIA DPU白皮书:SR-IOV vs. VirtIO加速性能对比
https://aijishu.com/a/1060000000228117
搭建 open vswitch 软交换
安装 open vswitch
sudo apt install openvswitch-switch
查看Open vSwitch(OVS)的版本:
$ sudo ovs-vsctl show
cb860a93-1368-4d4f-be38-5cb9bbe5273d
ovs_version: "3.1.0"
和 openvswitch 模块的信息:
$ sudo modinfo openvswitch
filename: /lib/modules/6.1.0-33-amd64/kernel/net/openvswitch/openvswitch.ko
alias: net-pf-16-proto-16-family-ovs_ct_limit
alias: net-pf-16-proto-16-family-ovs_meter
alias: net-pf-16-proto-16-family-ovs_packet
alias: net-pf-16-proto-16-family-ovs_flow
alias: net-pf-16-proto-16-family-ovs_vport
alias: net-pf-16-proto-16-family-ovs_datapath
license: GPL
description: Open vSwitch switching datapath
depends: nf_conntrack,nsh,nf_nat,nf_defrag_ipv6,nf_conncount,libcrc32c
retpoline: Y
intree: Y
name: openvswitch
vermagic: 6.1.0-33-amd64 SMP preempt mod_unload modversions
sig_id: PKCS#7
signer: Debian Secure Boot CA
sig_key: 32:A0:28:7F:84:1A:03:6F:A3:93:C1:E0:65:C4:3A:E6:B2:42:26:43
sig_hashalgo: sha256
signature: 7E:3C:EA:A0:18:FE:81:6D:2C:A8:08:8A:1D:BD:D5:13:F1:5D:FE:C4:
06:2C:3B:4B:B2:4A:6D:1E:30:AD:65:CC:DB:87:73:F4:D7:D5:30:76:
D6:FF:E2:77:28:0A:AA:17:92:C4:C5:DF:EC:E8:E5:95:88:B4:62:36:
AF:BF:58:96:D0:C1:ED:A3:6D:23:18:DD:A0:CF:A6:2C:6E:71:B2:83:
AD:45:F0:59:8D:FB:6D:8C:FB:9D:80:4D:0A:16:0A:9B:CE:A3:61:60:
BC:85:9D:EE:70:4D:5A:62:6E:E3:33:C1:58:2B:C4:CE:36:27:C9:A5:
BB:6C:7D:F3:B5:74:C8:FA:C3:5F:E5:1B:28:46:55:7E:26:0E:2A:7A:
54:4B:DD:74:E8:EA:40:43:2B:62:F6:DC:13:A6:A3:C6:EA:BF:1B:41:
2B:0A:92:01:2D:57:02:EA:0A:24:C9:75:EB:F3:34:41:35:D7:31:67:
65:96:9B:3B:65:47:1B:2E:60:97:E9:C3:40:10:9F:C6:91:EB:C4:DB:
0C:D5:5D:9C:99:ED:DF:3C:CA:B3:DB:61:44:A9:A0:C5:1D:1D:C8:CF:
01:39:D6:F3:FE:81:2D:43:2C:DE:F7:A1:06:E5:EE:79:31:DC:41:83:
59:BC:30:42:BB:68:C8:27:AF:AE:69:30:51:2E:02:6A
检查 openvswitch 模块的正确加载:
$ lsmod | grep openvswitch
openvswitch 192512 0
nsh 16384 1 openvswitch
nf_conncount 24576 1 openvswitch
nf_nat 57344 1 openvswitch
nf_conntrack 188416 3 nf_nat,openvswitch,nf_conncount
nf_defrag_ipv6 24576 2 nf_conntrack,openvswitch
libcrc32c 16384 3 nf_conntrack,nf_nat,openvswitch
查看 openvswitch-switch 服务的运行情况:
$ sudo systemctl status openvswitch-switch
● openvswitch-switch.service - Open vSwitch
Loaded: loaded (/lib/systemd/system/openvswitch-switch.service; enabled; preset: enabled)
Active: active (exited) since Tue 2025-04-29 14:39:38 CST; 1min 54s ago
Process: 1816 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
Main PID: 1816 (code=exited, status=0/SUCCESS)
CPU: 340us
Apr 29 14:39:38 debian12 systemd[1]: Starting openvswitch-switch.service - Open vSwitch...
Apr 29 14:39:38 debian12 systemd[1]: Finished openvswitch-switch.service - Open vSwitch.
查看 ovsdb-server 服务:
$ sudo systemctl status ovsdb-server
● ovsdb-server.service - Open vSwitch Database Unit
Loaded: loaded (/lib/systemd/system/ovsdb-server.service; static)
Active: active (running) since Tue 2025-04-29 14:39:38 CST; 2min 28s ago
Process: 1718 ExecStart=/usr/share/openvswitch/scripts/ovs-ctl --no-ovs-vswitchd --no-monito>
Main PID: 1761 (ovsdb-server)
Tasks: 1 (limit: 19089)
Memory: 2.2M
CPU: 38ms
CGroup: /system.slice/ovsdb-server.service
└─1761 ovsdb-server /etc/openvswitch/conf.db -vconsole:emer -vsyslog:err -vfile:inf>
Apr 29 14:39:38 debian12 systemd[1]: Starting ovsdb-server.service - Open vSwitch Database Unit.>
Apr 29 14:39:38 debian12 ovs-ctl[1718]: Backing up database to /etc/openvswitch/conf.db.backup8.>
Apr 29 14:39:38 debian12 ovs-ctl[1718]: Compacting database.
Apr 29 14:39:38 debian12 ovs-ctl[1718]: Converting database schema.
Apr 29 14:39:38 debian12 ovs-ctl[1718]: Starting ovsdb-server.
Apr 29 14:39:38 debian12 ovs-vsctl[1762]: ovs|00001|vsctl|INFO|Called as ovs-vsctl --no-wait -- >
Apr 29 14:39:38 debian12 ovs-vsctl[1767]: ovs|00001|vsctl|INFO|Called as ovs-vsctl --no-wait set>
Apr 29 14:39:38 debian12 ovs-ctl[1718]: Configuring Open vSwitch system IDs.
Apr 29 14:39:38 debian12 ovs-ctl[1718]: Enabling remote OVSDB managers.
Apr 29 14:39:38 debian12 systemd[1]: Started ovsdb-server.service - Open vSwitch Database Unit.
查看 ovs-vswitchd 服务:
$ sudo systemctl status ovs-vswitchd
● ovs-vswitchd.service - Open vSwitch Forwarding Unit
Loaded: loaded (/lib/systemd/system/ovs-vswitchd.service; static)
Active: active (running) since Tue 2025-04-29 14:39:38 CST; 3min 28s ago
Process: 1771 ExecStart=/usr/share/openvswitch/scripts/ovs-ctl --no-ovsdb-server --no-monito>
Main PID: 1810 (ovs-vswitchd)
Tasks: 1 (limit: 19089)
Memory: 2.1M
CPU: 17ms
CGroup: /system.slice/ovs-vswitchd.service
└─1810 ovs-vswitchd unix:/var/run/openvswitch/db.sock -vconsole:emer -vsyslog:err ->
Apr 29 14:39:38 debian12 systemd[1]: Starting ovs-vswitchd.service - Open vSwitch Forwarding Uni>
Apr 29 14:39:38 debian12 ovs-ctl[1771]: Starting ovs-vswitchd.
Apr 29 14:39:38 debian12 ovs-ctl[1771]: Enabling remote OVSDB managers.
Apr 29 14:39:38 debian12 systemd[1]: Started ovs-vswitchd.service - Open vSwitch Forwarding Unit.
创建网桥
创建网桥前,先查看当前的网络接口:
ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: enp6s18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether bc:24:11:1c:d5:48 brd ff:ff:ff:ff:ff:ff
inet 192.168.3.227/24 brd 192.168.3.255 scope global dynamic enp6s18
valid_lft 43156sec preferred_lft 43156sec
inet6 fdfb:ddbe:c71b:0:be24:11ff:fe1c:d548/64 scope global dynamic mngtmpaddr
valid_lft forever preferred_lft forever
inet6 240e:3a1:5055:c180:be24:11ff:fe1c:d548/64 scope global dynamic mngtmpaddr
valid_lft 6989sec preferred_lft 2523sec
inet6 fe80::be24:11ff:fe1c:d548/64 scope link
valid_lft forever preferred_lft forever
3: enp1s0f0np0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1c:34:da:5a:1f:ec brd ff:ff:ff:ff:ff:ff
4: enp1s0f1np1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1c:34:da:5a:1f:ed brd ff:ff:ff:ff:ff:ff
当前有 3 个网口,分别是 enp6s18, enp1s0f0np0, enp1s0f1np1。enp6s18 是 cx4 25g 网卡,接交换机,enp1s0f0np0 和 enp1s0f1np1 是 cx5 100g 双头网卡,准备接另外两台机器。
创建 ovs 网桥:
sudo ovs-vsctl add-br br0
此时执行 ip addr
可以看到 ovs-system 和 br0:
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: enp6s18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether bc:24:11:1c:d5:48 brd ff:ff:ff:ff:ff:ff
inet 192.168.3.227/24 brd 192.168.3.255 scope global dynamic enp6s18
valid_lft 43027sec preferred_lft 43027sec
inet6 fdfb:ddbe:c71b:0:be24:11ff:fe1c:d548/64 scope global dynamic mngtmpaddr
valid_lft forever preferred_lft forever
inet6 240e:3a1:5055:c180:be24:11ff:fe1c:d548/64 scope global dynamic mngtmpaddr
valid_lft 6860sec preferred_lft 2394sec
inet6 fe80::be24:11ff:fe1c:d548/64 scope link
valid_lft forever preferred_lft forever
3: enp1s0f0np0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1c:34:da:5a:1f:ec brd ff:ff:ff:ff:ff:ff
4: enp1s0f1np1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1c:34:da:5a:1f:ed brd ff:ff:ff:ff:ff:ff
5: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 46:39:3e:eb:b0:0b brd ff:ff:ff:ff:ff:ff
6: br0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 8a:1f:49:5c:10:4d brd ff:ff:ff:ff:ff:ff
注意: 此时网桥的 mac 地址 8a:1f:49:5c:10:4d 和其他三个网卡都不一样。
目前网桥下还没有配置任何端口:
sudo ovs-vsctl show
cb860a93-1368-4d4f-be38-5cb9bbe5273d
Bridge br0
Port br0
Interface br0
type: internal
ovs_version: "3.1.0"
查看 br0 的详细信息:
sudo ovs-vsctl list br br0
_uuid : a345132c-00d9-4196-bb2c-2489c3669b47
auto_attach : []
controller : []
datapath_id : "00002e1345a39641"
datapath_type : ""
datapath_version : "<unknown>"
external_ids : {}
fail_mode : []
flood_vlans : []
flow_tables : {}
ipfix : []
mcast_snooping_enable: false
mirrors : []
name : br0
netflow : []
other_config : {}
ports : [1e053d35-c79f-4b5b-88cc-f5cba9519ca0]
protocols : []
rstp_enable : false
rstp_status : {}
sflow : []
status : {}
stp_enable : false
先修改 /etc/network/interfaces 文件,安全起见备份一份:
sudo cp /etc/network/interfaces /etc/network/interfaces.bak
sudo vi /etc/network/interfaces
内容为:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
#allow-hotplug enp6s18
#iface enp6s18 inet dhcp
# Open vSwitch Configuration
# active br0 interface
auto br0
allow-ovs br0
# config IP for interface br0
iface br0 inet static
address 192.168.3.227
netmask 255.255.255.0
gateway 192.168.3.1
ovs_type OVSBridge
ovs_ports enp6s18
# attach enp6s18 to bridge br0
allow-br0 enp6s18
iface enp6s18 inet manual
ovs_bridge br0
ovs_type OVSPort
然后给网桥中添加端口,先加 enp6s18:
sudo ovs-vsctl add-port br0 enp6s18
执行完成后网络就不能用了。只能在 pve 控制台继续控制。
加入 enp6s18 后,网桥的 mac 地址变为 enp6s18 的 mac 地址:
sudo ovs-vsctl show
cb860a93-1368-4d4f-be38-5cb9bbe5273d
Bridge br0
Port br0
Interface br0
type: internal
Port enp6s18
Interface enp6s18
ovs_version: "3.1.0"
重启网络:
sudo systemctl restart networking
此时虚拟机的网络应该恢复了,可以重新 ssh 连接。查看此时网口信息:
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: enp6s18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master ovs-system state UP group default qlen 1000
link/ether bc:24:11:1c:d5:48 brd ff:ff:ff:ff:ff:ff
inet6 fe80::be24:11ff:fe1c:d548/64 scope link
valid_lft forever preferred_lft forever
3: enp1s0f0np0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1c:34:da:5a:1f:ec brd ff:ff:ff:ff:ff:ff
4: enp1s0f1np1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 1c:34:da:5a:1f:ed brd ff:ff:ff:ff:ff:ff
9: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 46:39:3e:eb:b0:0b brd ff:ff:ff:ff:ff:ff
10: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether bc:24:11:1c:d5:48 brd ff:ff:ff:ff:ff:ff
inet 192.168.3.227/24 brd 192.168.3.255 scope global br0
valid_lft forever preferred_lft forever
inet6 fdfb:ddbe:c71b:0:be24:11ff:fe1c:d548/64 scope global dynamic mngtmpaddr
valid_lft forever preferred_lft forever
inet6 240e:3a1:5055:c180:be24:11ff:fe1c:d548/64 scope global dynamic mngtmpaddr
valid_lft 6477sec preferred_lft 2874sec
inet6 fe80::be24:11ff:fe1c:d548/64 scope link
valid_lft forever preferred_lft forever
注意: 此时 br0 的 mac 地址变为 enp6s18 的 mac 地址 bc:24:11:1c:d5:48。
检查一下是否可以访问外网:
ping 192.168.3.1
ping www.baidu.com
如果可以访问外网,则说明网络配置成功, openvswitch 网桥建立并可以工作。
往网桥中加入其他网口
目前网桥中只有 enp6s18 一个网口,只能用于访问外部访问,需要继续加入其他网口。
......
# config IP for interface br0
iface br0 inet static
address 192.168.3.227
netmask 255.255.255.0
gateway 192.168.3.1
ovs_type OVSBridge
ovs_ports enp6s18 enp1s0f0np0 enp1s0f1np1
# attach enp6s18 to bridge br0
allow-br0 enp6s18
iface enp6s18 inet manual
ovs_bridge br0
ovs_type OVSPort
# attach enp1s0f0np0 to bridge br0
allow-br0 enp1s0f0np0
iface enp1s0f0np0 inet manual
ovs_bridge br0
ovs_type OVSPort
# attach enp1s0f1np1 to bridge br0
allow-br0 enp1s0f1np1
iface enp1s0f1np1 inet manual
ovs_bridge br0
ovs_type OVSPort
重启网络
sudo systemctl restart networking
之后查看网桥信息:
sudo ovs-vsctl show
cb860a93-1368-4d4f-be38-5cb9bbe5273d
Bridge br0
Port br0
Interface br0
type: internal
Port enp1s0f0np0
Interface enp1s0f0np0
Port enp6s18
Interface enp6s18
Port enp1s0f1np1
Interface enp1s0f1np1
ovs_version: "3.1.0"
此时网桥中已经有三个网口,可以用来连接其他机器扮演交换机的角色了。
在另外一台机器的虚拟机中,直通 cx5 网卡,网线直连接到前面这台机器的 cx5 双头网卡上。注意去掉虚拟机的 vmbr 网卡,只使用 cx5 网卡。
修改网络配置文件:
sudo vi /etc/network/interfaces
添加如下内容(dhcp或者静态地址二选一):
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
allow-hotplug enp1s0np0
iface enp1s0np0 inet dhcp
#iface enp1s0np0 inet static
#address 192.168.3.130
#netmask 255.255.255.0
#gateway 192.168.3.1
#dns-nameservers 192.168.3.1
重启网络:
sudo systemctl restart networking
检查此时是否可以正常连接网络。
简单性能测试
用 iperf 简单测试一下性能:
# 在服务器端运行
iperf -s
# 在客户端运行
iperf -c 192.168.3.227 -i 1 -t 20 -P 4
测试结果:
[SUM] 11.0000-11.7642 sec 8.37 GBytes 94.1 Gbits/sec
[SUM] 0.0000-11.7642 sec 129 GBytes 94.1 Gbits/sec
可以看到,服务器端和客户端的带宽都达到了 94.1 Gbits/sec,接近 100G 的理论极限。
设置 MTU
目前网桥的 MTU 是 1500,可以设置为 9000:
sudo ip link set br0 mtu 9000
sudo ip link set enp1s0f0np0 mtu 9000
sudo ip link set enp1s0f1np1 mtu 9000
sudo ip link set enp6s18 mtu 9000
注意: 三块网卡都要设置,如果只设置 enp1s0f0np0 和 enp1s0f1np1, 没有设置 enp6s18, 速度不会有提升。
客户端也要设置 MTU:
sudo ip link set enp1s0np0 mtu 9000
重新测试,这次 iperf 测试出来的速度从 94.1 Gbits/sec 提升到了 98.8 Gbits/sec, 提升还是比较明显的。
[SUM] 0.0000-20.0004 sec 230 GBytes 98.8 Gbits/sec
当这个方式重启之后就 MTU 又回复成 1500 了。
修改网络配置文件:
sudo vi /etc/network/interfaces
服务器端修改,将 3 个网卡都设置为 mtu 9000 即可:
# attach enp6s18 to bridge br0
allow-br0 enp6s18
iface enp6s18 inet manual
ovs_bridge br0
ovs_type OVSPort
mtu 9000
# attach enp1s0f0np0 to bridge br0
allow-br0 enp1s0f0np0
iface enp1s0f0np0 inet manual
ovs_bridge br0
ovs_type OVSPort
mtu 9000
# attach enp1s0f1np1 to bridge br0
allow-br0 enp1s0f1np1
iface enp1s0f1np1 inet manual
ovs_bridge br0
ovs_type OVSPort
mtu 9000
客户端修改:
allow-hotplug enp1s0np0
iface enp1s0np0 inet static
address 192.168.3.205
netmask 255.255.255.0
gateway 192.168.3.1
dns-nameservers 192.168.3.1
mtu 9000
特别注意: 测试中发现,如果用 static 静态地址, 这样设置 MTU 9000 可以生效。但是如果用 dhcp 动态地址, 这样设置 MTU 9000 不会生效,会继续使用 1500。估计是 dhcp 动态地址获取的 MTU 是 1500。
重启网络:
sudo systemctl restart networking
sudo reboot
开启硬件卸载
sudo ovs-vsctl set Open_vSwitch . other_config:hw-offload=true
sudo systemctl restart networking
sudo systemctl restart openvswitch-switch
https://infoloup.no-ip.org/openvswitch-debian12-creation/
➜ ~ sudo ip link set br0 mtu 9000 ➜ ~ sudo ip link set enp1s0f1np1 mtu 9000 ➜ ~ sudo ip link set enp1s0f0np0 mtu 9000 ➜ ~ sudo ip link set enp6s18 mtu 9000
https://docs.openstack.org/neutron/latest/admin/config-ovs-offload.html
https://www.openvswitch.org/support/ovscon2019/day2/0951-hw_offload_ovs_con_19-Oz-Mellanox.pdf
https://docs.nvidia.com/doca/archive/doca-v2.2.0/switching-support/index.html
3.3.3 - TODO
文档
https://docs.nvidia.com/doca/archive/doca-v2.2.0/switching-support/index.html
Hardware Offload
3.4 - nfs 网络文件系统
nfs 服务器端
安装 nfs server
sudo apt install nfs-kernel-server -y
准备硬盘和分区
直通一块 3.84T 的 KIOXIA CD6 pcie4 SSD 进来虚拟机。查看这块 ssd 硬盘:
lspci | grep Non-Volatile
02:00.0 Non-Volatile memory controller: KIOXIA Corporation NVMe SSD Controller Cx6 (rev 01)
硬盘分区:
sudo fdisk /dev/nvme0n1
g 转为 GPT partition table p 打印分区表 n 创建新分区,这里就只创建一个大分区。
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 512G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 465.7G 0 part /
└─sda3 8:3 0 45.8G 0 part /timeshift
nvme0n1 259:0 0 3.5T 0 disk
└─nvme0n1p1 259:1 0 3.5T 0 part
将硬盘格式化为 ext4 文件系统:
sudo mkfs.ext4 /dev/nvme0n1p1
查看 ssd 分区的 uuid:
$ sudo lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1 vfat FAT32 BE75-FC62 505.1M 1% /boot/efi
├─sda2 ext4 1.0 81fdaf25-6712-48ee-bb53-1c4a78c8ef9f 430.4G 1% /
└─sda3 ext4 1.0 4b922cfb-2123-48ce-b9fe-635e73fb6aa8 39G 8% /timeshift
nvme0n1
└─nvme0n1p1 ext4 1.0 1dee904a-aa51-4180-b65b-9449405b841f
准备挂载这块硬盘
sudo vi /etc/fstab
增加以下内容:
# data storage was on /dev/nvme0n1p1(3.84T)
UUID=1dee904a-aa51-4180-b65b-9449405b841f /mnt/data ext4 defaults 0 2
重启之后再看:
$ sudo lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1 vfat FAT32 BE75-FC62 505.1M 1% /boot/efi
├─sda2 ext4 1.0 81fdaf25-6712-48ee-bb53-1c4a78c8ef9f 430.4G 1% /
└─sda3 ext4 1.0 4b922cfb-2123-48ce-b9fe-635e73fb6aa8 39G 8% /timeshift
nvme0n1
└─nvme0n1p1 ext4 1.0 1dee904a-aa51-4180-b65b-9449405b841f 3.3T 0% /mnt/data
准备伪文件系统
为了方便后续的管理,采用伪文件系统:
sudo mkdir -p /mnt/data/shared
sudo chown -R nobody:nogroup /mnt/data/shared
cd /mnt/data
创建 export 目录:
sudo mkdir -p /exports/shared
sudo chown -R nobody:nogroup /exports
修改 /etc/fstab
文件来 mount 伪文件系统和 exports :
sudo vi /etc/fstab
增加如下内容:
# nfs exports
/mnt/data/shared /exports/shared none bind
配置 nfs export
sudo vi /etc/exports
增加以下内容:
/exports/shared 192.168.0.0/16(rw,sync,no_subtree_check,no_root_squash)
重启 nfs-kernel-server,查看 nfs-kernel-server 的状态:
sudo systemctl restart nfs-kernel-server
sudo systemctl status nfs-kernel-server
验证:
ps -ef | grep nfs
输出为:
root 918 1 0 01:25 ? 00:00:00 /usr/sbin/nfsdcld
root 1147 2 0 01:26 ? 00:00:00 [nfsd]
root 1148 2 0 01:26 ? 00:00:00 [nfsd]
root 1149 2 0 01:26 ? 00:00:00 [nfsd]
root 1150 2 0 01:26 ? 00:00:00 [nfsd]
root 1151 2 0 01:26 ? 00:00:00 [nfsd]
root 1152 2 0 01:26 ? 00:00:00 [nfsd]
root 1153 2 0 01:26 ? 00:00:00 [nfsd]
root 1154 2 0 01:26 ? 00:00:00 [nfsd]
查看当前挂载情况:
$ sudo showmount -e
Export list for debian12:
/exports/shared 192.168.0.0/16
设置 nfs 版本支持
查看目前服务器端支持的 nfs 版本:
sudo cat /proc/fs/nfsd/versions
默认情况下,nfs server 支持的 nfs 版本为:
+3 +4 +4.1 +4.2
通常我们只需要保留 nfs 4.2 版本,其他版本都删除:
sudo vi /etc/nfs.conf
将默认的 nfsd:
[nfsd]
# debug=0
# threads=8
# host=
# port=0
# grace-time=90
# lease-time=90
# udp=n
# tcp=y
# vers3=y
# vers4=y
# vers4.0=y
# vers4.1=y
# vers4.2=y
# rdma=n
# rdma-port=20049
修改为:
[nfsd]
# debug=0
threads=32
# host=
# port=0
# grace-time=90
# lease-time=90
# udp=n
# tcp=y
vers3=n
vers4=y
vers4.0=n
vers4.1=n
vers4.2=y
# rdma=n
# rdma-port=20049
顺便把 nfs 线程数量从默认的 8 修改为 32。
重启 nfs-kernel-server:
sudo systemctl restart nfs-kernel-server
然后验证 nfs 版本:
sudo cat /proc/fs/nfsd/versions
输出为:
-3 +4 -4.0 -4.1 +4.2
注意: +4 是必须保留的,只有先设置 +4 版本,才能设置 4.0/4.1/4.2 版本,如果 -4 则 4.0/4.1/4.2 版本都会不支持。
也可以通过 rpcinfo 命令查看 nfs 版本:
rpcinfo -p localhost
输出为:
program vers proto port service
......
100003 4 tcp 2049 nfs
这里的 4 代表 nfs 4.x 版本,但是没法区分 4.0/4.1/4.2 版本。
nfs 客户端
安装 nfs-common
然后安装 nfs-common 作为 nfs client:
sudo apt-get install nfs-common
配置 nfs 访问
准备好挂载点:
cd /mnt
sudo mkdir -p nfs
不带 nfsrdma 方式的挂载 nfs:
sudo mount -t nfs 192.168.3.227:/exports/shared /mnt/nfs
挂载成功后,测试一下读写速度:
cd nfs
# nfs 写入10G数据,速度大概在 610 MB/s
sudo dd if=/dev/zero of=./test-10g.img bs=1G count=10 oflag=dsync
10737418240 bytes (11 GB, 10 GiB) copied, 17.6079 s, 610 MB/s
# nfs 读取100G数据,速度大概在 1.1 GB/s
sudo dd if=./test-100g.img of=/dev/null bs=1G count=100 iflag=dsync
107374182400 bytes (107 GB, 100 GiB) copied, 96.5171 s, 1.1 GB/s
对比一下在 nfs server 端直接硬盘读写 100G 数据的速度:
# 直接硬盘写入100G数据,速度大概在 1.3 GB/s
sudo dd if=/dev/zero of=./test-100g.img bs=1G count=100 oflag=dsync
107374182400 bytes (107 GB, 100 GiB) copied, 82.5747 s, 1.3 GB/s
# 直接硬盘读取100G数据,速度大概在 4.0 GB/s
sudo dd if=./test-100g.img of=/dev/null bs=1G count=100 iflag=dsync
107374182400 bytes (107 GB, 100 GiB) copied, 26.9138 s, 4.0 GB/s
写入性能差异很大(1.3 GB/s 降低到 610 MB/s),估计是用 pve vmbr 的网卡,导致写入性能下降。读取的性能有更大的差异(4.0 GB/s 降低到 1.1 GB/s)。
现在 nfs 服务器端和客户端之间的网络共享配置完成。
3.5 - nfs rdma 支持
准备工作
前置条件
- 已经配置好 nfs 服务器和客户端:参考上一章
- 已经配置好硬盘:参考上一章
安装 MLNX_OFED 驱动
cx-5 100g网卡参考: https://skyao.io/learning-computer-hardware/nic/cx5-huawei-sp350/driver/debian12/
nfs 服务器和客户端都要安装网卡驱动。
网卡直连
为了避免 linux bridge 或者 ovs 的桥接,直接使用dac线连接100G网卡的网口,以直连的方式连接两台服务器(后续再尝试openvswitch)。
服务器端设置网卡地址:
sudo vi /etc/network/interfaces
增加内容:
allow-hotplug enp1s0f1np1
# iface enp1s0f1np1 inet dhcp
iface enp1s0f1np1 inet static
address 192.168.119.1
netmask 255.255.255.0
gateway 192.168.3.1
dns-nameservers 192.168.3.1
重启网卡:
sudo systemctl restart networking
客户端设置网卡地址:
sudo vi /etc/network/interfaces
增加内容:
allow-hotplug enp1s0np0
# iface enp1s0np0 inet dhcp
iface enp1s0np0 inet static
address 192.168.119.2
netmask 255.255.255.0
gateway 192.168.119.1
dns-nameservers 192.168.119.1
重启网卡:
sudo systemctl restart networking
验证两台机器可以互联:
ping 192.168.119.1
ping 192.168.119.2
验证两台机器之间的网速,服务器端自动 iperf 服务器端:
iperf -s 192.168.119.1
客户端 iperf 测试:
iperf -c 192.168.119.1 -i 1 -t 20 -P 4
测试出来的速度大概是 94.1 Gbits/sec,比较接近100G网卡的理论最大速度了:
[ 4] 0.0000-20.0113 sec 39.2 GBytes 16.8 Gbits/sec
[ 2] 0.0000-20.0111 sec 70.1 GBytes 30.1 Gbits/sec
[ 3] 0.0000-20.0113 sec 70.8 GBytes 30.4 Gbits/sec
[ 1] 0.0000-20.0111 sec 39.2 GBytes 16.8 Gbits/sec
[SUM] 0.0000-20.0007 sec 219 GBytes 94.1 Gbits/sec
此时 nfs 服务器端和客户端之间的网络连接已经没有问题了,可以开始配置 nfs 了。
由于启用了两块网卡,有时默认网络路由会出问题,导致无法访问外网。此时需要检查网络路由:
$ ip route
default via 192.168.3.1 dev enp1s0f1np1 onlink
192.168.3.0/24 dev enp6s18 proto kernel scope link src 192.168.3.227
192.168.119.0/24 dev enp1s0f1np1 proto kernel scope link src 192.168.119.1
可以看到默认路由是 192.168.3.1, 但使用的网卡是 enp1s0f1np1, 而不是 enp6s18。
此时需要手动设置默认路由:
sudo ip route del default
sudo ip route add default dev enp6s18
安装 nfsrdma
sudo cp ./mlnx-nfsrdma-dkms_24.10.OFED.24.10.2.1.8.1-1_all.deb /tmp/
cd /tmp
sudo apt-get install ./mlnx-nfsrdma-dkms_24.10.OFED.24.10.2.1.8.1-1_all.deb
输出为:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Note, selecting 'mlnx-nfsrdma-dkms' instead of './mlnx-nfsrdma-dkms_24.10.OFED.24.10.2.1.8.1-1_all.deb'
The following NEW packages will be installed:
mlnx-nfsrdma-dkms
0 upgraded, 1 newly installed, 0 to remove and 2 not upgraded.
Need to get 0 B/71.2 kB of archives.
After this operation, 395 kB of additional disk space will be used.
Get:1 /home/sky/temp/mlnx-nfsrdma-dkms_24.10.OFED.24.10.2.1.8.1-1_all.deb mlnx-nfsrdma-dkms all 24.10.OFED.24.10.2.1.8.1-1 [71.2 kB]
Selecting previously unselected package mlnx-nfsrdma-dkms.
(Reading database ... 74820 files and directories currently installed.)
Preparing to unpack .../mlnx-nfsrdma-dkms_24.10.OFED.24.10.2.1.8.1-1_all.deb ...
Unpacking mlnx-nfsrdma-dkms (24.10.OFED.24.10.2.1.8.1-1) ...
Setting up mlnx-nfsrdma-dkms (24.10.OFED.24.10.2.1.8.1-1) ...
Loading new mlnx-nfsrdma-24.10.OFED.24.10.2.1.8.1 DKMS files...
First Installation: checking all kernels...
Building only for 6.1.0-31-amd64
Building for architecture x86_64
Building initial module for 6.1.0-31-amd64
Done.
Forcing installation of mlnx-nfsrdma
rpcrdma.ko:
Running module version sanity check.
- Original module
- Installation
- Installing to /lib/modules/6.1.0-31-amd64/updates/dkms/
svcrdma.ko:
Running module version sanity check.
- Original module
- Installation
- Installing to /lib/modules/6.1.0-31-amd64/updates/dkms/
xprtrdma.ko:
Running module version sanity check.
- Original module
- Installation
- Installing to /lib/modules/6.1.0-31-amd64/updates/dkms/
depmod...
如果安装时最后有如下报错:
N: Download is performed unsandboxed as root as file '/home/sky/temp/mlnx-nfsrdma-dkms_24.10.OFED.24.10.2.1.8.1-1_all.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
最后的 Permission denied 提示是因为 _apt 用户无法直接访问下载的 .deb 文件(比如位于 /home/sky/temp/),需要先复制到 /tmp/ 目录下。
重启。
检查 DKMS 状态
确认 DKMS 模块已注册:
sudo dkms status | grep nfsrdma
输出:
mlnx-nfsrdma/24.10.OFED.24.10.2.1.8.1, 6.1.0-31-amd64, x86_64: installed
配置 nfs server(rdma)
为了确保安全,尤其是升级内核之后,先安装内核头文件并重新编译 nfsrdma 模块:
sudo apt install linux-headers-$(uname -r)
sudo dkms autoinstall
检查 RDMA 相关模块是否已加载
运行以下命令检查模块是否已加载:
lsmod | grep -E "rpcrdma|svcrdma|xprtrdma|ib_core|mlx5_ib"
预计输出:
xprtrdma 16384 0
svcrdma 16384 0
rpcrdma 94208 0
rdma_cm 139264 2 rpcrdma,rdma_ucm
mlx5_ib 495616 0
ib_uverbs 188416 2 rdma_ucm,mlx5_ib
ib_core 462848 9 rdma_cm,ib_ipoib,rpcrdma,iw_cm,ib_umad,rdma_ucm,ib_uverbs,mlx5_ib,ib_cm
sunrpc 692224 18 nfsd,rpcrdma,auth_rpcgss,lockd,nfs_acl
mlx5_core 2441216 1 mlx5_ib
mlx_compat 20480 15 rdma_cm,ib_ipoib,mlxdevm,rpcrdma,mlxfw,xprtrdma,iw_cm,svcrdma,ib_umad,ib_core,rdma_ucm,ib_uverbs,mlx5_ib,ib_cm,mlx5_core
如果没有,手动加载模块(实际操作下来发现不手工加载也可以,系统会自动加载):
sudo modprobe rpcrdma
sudo modprobe svcrdma
sudo modprobe xprtrdma
sudo modprobe ib_core
sudo modprobe mlx5_ib
确认 DKMS 模块已注册:
sudo dkms status | grep nfsrdma
输出:
mlnx-nfsrdma/24.10.OFED.24.10.2.1.8.1, 6.1.0-31-amd64, x86_64: installed
检查内核日志:
sudo dmesg | grep rdma
[ 178.512334] RPC: Registered rdma transport module.
[ 178.512336] RPC: Registered rdma backchannel transport module.
[ 178.515613] svcrdma: svcrdma is obsoleted, loading rpcrdma instead
[ 178.552178] xprtrdma: xprtrdma is obsoleted, loading rpcrdma instead
测试 RDMA 连接
在服务器端执行:
ibstatus
我这里开启了一个网卡 mlx5_1:
Infiniband device 'mlx5_0' port 1 status:
default gid: fe80:0000:0000:0000:1e34:daff:fe5a:1fec
base lid: 0x0
sm lid: 0x0
state: 1: DOWN
phys state: 3: Disabled
rate: 100 Gb/sec (4X EDR)
link_layer: Ethernet
Infiniband device 'mlx5_1' port 1 status:
default gid: fe80:0000:0000:0000:1e34:daff:fe5a:1fed
base lid: 0x0
sm lid: 0x0
state: 4: ACTIVE
phys state: 5: LinkUp
rate: 100 Gb/sec (4X EDR)
link_layer: Ethernet
或者执行 ibdev2netdev 显示:
$ ibdev2netdev
mlx5_0 port 1 ==> enp1s0f0np0 (Down)
mlx5_1 port 1 ==> enp1s0f1np1 (Up)
因此在 mlx5_1 上启动 ib_write_bw 测试:
ib_write_bw -d mlx5_1 -p 18515
显示:
************************************
* Waiting for client to connect... *
************************************
在客户端执行:
ibstatus
显示为:
Infiniband device 'mlx5_0' port 1 status:
default gid: fe80:0000:0000:0000:8e2a:8eff:fe88:a136
base lid: 0x0
sm lid: 0x0
state: 4: ACTIVE
phys state: 5: LinkUp
rate: 100 Gb/sec (4X EDR)
link_layer: Ethernet
因此在 mlx5_0 上启动 ib_write_bw 测试:
ib_write_bw -d mlx5_0 -p 18515 192.168.119.1
客户端显示测试结果为:
---------------------------------------------------------------------------------------
RDMA_Write BW Test
Dual-port : OFF Device : mlx5_0
Number of qps : 1 Transport type : IB
Connection type : RC Using SRQ : OFF
PCIe relax order: ON Lock-free : OFF
ibv_wr* API : ON Using DDP : OFF
TX depth : 128
CQ Moderation : 1
Mtu : 1024[B]
Link type : Ethernet
GID index : 3
Max inline data : 0[B]
rdma_cm QPs : OFF
Data ex. method : Ethernet
---------------------------------------------------------------------------------------
local address: LID 0000 QPN 0x009b PSN 0x57bb8f RKey 0x1fd4bc VAddr 0x007f0e0c8aa000
GID: 00:00:00:00:00:00:00:00:00:00:255:255:192:168:119:02
remote address: LID 0000 QPN 0x0146 PSN 0x860b7f RKey 0x23c6bc VAddr 0x007fb25aea4000
GID: 00:00:00:00:00:00:00:00:00:00:255:255:192:168:119:01
---------------------------------------------------------------------------------------
#bytes #iterations BW peak[MiB/sec] BW average[MiB/sec] MsgRate[Mpps]
65536 5000 11030.78 11030.45 0.176487
---------------------------------------------------------------------------------------
服务器端显示测试结果为:
---------------------------------------------------------------------------------------
RDMA_Write BW Test
Dual-port : OFF Device : mlx5_1
Number of qps : 1 Transport type : IB
Connection type : RC Using SRQ : OFF
PCIe relax order: ON Lock-free : OFF
ibv_wr* API : ON Using DDP : OFF
CQ Moderation : 1
Mtu : 1024[B]
Link type : Ethernet
GID index : 3
Max inline data : 0[B]
rdma_cm QPs : OFF
Data ex. method : Ethernet
---------------------------------------------------------------------------------------
local address: LID 0000 QPN 0x0146 PSN 0x860b7f RKey 0x23c6bc VAddr 0x007fb25aea4000
GID: 00:00:00:00:00:00:00:00:00:00:255:255:192:168:119:01
remote address: LID 0000 QPN 0x009b PSN 0x57bb8f RKey 0x1fd4bc VAddr 0x007f0e0c8aa000
GID: 00:00:00:00:00:00:00:00:00:00:255:255:192:168:119:02
---------------------------------------------------------------------------------------
#bytes #iterations BW peak[MiB/sec] BW average[MiB/sec] MsgRate[Mpps]
65536 5000 11030.78 11030.45 0.176487
---------------------------------------------------------------------------------------
测试成功,说明 RDMA 网络就绪。
开启 nfs server 的 RDMA 支持
nfs server 需要开启 rdma 支持:
sudo vi /etc/nfs.conf
修改 /etc/nfs.conf 文件的 [nfsd] 部分(备注:尽量要把 nfs 版本那几行也放开,限制为只提供4.2版本):
[nfsd]
# debug=0
# 线程改大一点,默认8太少了
threads=128
# host=
# port=0
# grace-time=90
# lease-time=90
# udp=n
# tcp=y
# 版本这几行一定要设置,注意只保留4.2版本
vers3=n
vers4=y
vers4.0=n
vers4.1=n
vers4.2=y
rdma=y
rdma-port=20049
然后重启 NFS 服务:
sudo systemctl restart nfs-server
然后检查 nfsd 的监听端口,验证 rdma 是否生效:
sudo cat /proc/fs/nfsd/portlist
rdma 20049
rdma 20049
tcp 2049
tcp 2049
如果看到 rdma 20049 端口,说明 rdma 配置成功。反之如果没有看到 rdma 20049 端口,说明 rdma 配置失败,需要检查前面的配置。
配置 nfs client(rdma)
检查 rdma 模块
确保客户端和 rdma 相关的模块都已经加载:
lsmod | grep -E "rpcrdma|svcrdma|xprtrdma|ib_core|mlx5_ib"
如果没有,手动加载模块(实际操作下来发现不手工加载也可以,系统会自动加载):
sudo modprobe rpcrdma
sudo modprobe svcrdma
sudo modprobe xprtrdma
sudo modprobe ib_core
sudo modprobe mlx5_ib
确认 DKMS 模块已注册:
sudo dkms status | grep nfsrdma
预计输出:
mlnx-nfsrdma/24.10.OFED.24.10.2.1.8.1, 6.1.0-31-amd64, x86_64: installed
检查内核日志:
sudo dmesg | grep rdma
预计输出:
[ 3273.613081] RPC: Registered rdma transport module.
[ 3273.613082] RPC: Registered rdma backchannel transport module.
[ 3695.887144] svcrdma: svcrdma is obsoleted, loading rpcrdma instead
[ 3695.923962] xprtrdma: xprtrdma is obsoleted, loading rpcrdma instead
配置 nfs 访问(rdma)
准备挂载点:
cd /mnt
sudo mkdir -p nfs-rdma
带 nfsrdma 方式的挂载 nfs:
sudo mount -t nfs -o rdma,port=20049,vers=4.2,nconnect=16 192.168.119.1:/exports/shared /mnt/nfs-rdma
挂载成功后,测试一下读写速度:
# nfs 写入100G数据,速度大概在 1.0 GB/s
sudo dd if=/dev/zero of=./test-100g.img bs=1G count=100 oflag=dsync
107374182400 bytes (107 GB, 100 GiB) copied, 104.569 s, 1.0 GB/s
# nfs 读取100G数据,速度大概在 2.2 GB/s
sudo dd if=./test-100g.img of=/dev/null bs=1G count=100 iflag=dsync
107374182400 bytes (107 GB, 100 GiB) copied, 47.4093 s, 2.2 GB/s
对比三者的速度,同一块铠侠 cd6 3.84T ssd 硬盘直通到虚拟机:
场景 | 100g 单文件写入 | 100g 单文件读取 |
---|---|---|
直接读写硬盘 | 1.3 GB/s | 4.0 GB/s |
nfs 挂载(non-rdma) | 1.0 GB/s | 2.5 GB/s |
nfs 挂载(rdma) | 1.0 GB/s | 2.2 GB/s |
4 - 存储
4.1 - 用虚拟机实现的SSD NAS存储
构想
devserver91 开发服务器上,需要搭建一个 nfs 服务器,给 pve 和其他方式使用。
准备工作
准备虚拟机
基于 template-debian12-dev 的虚拟机上搭建。
硬盘直通
在开启 pve 直通的基础上,将两块三星 pm983a 900g 的 ssd 硬盘直通到 devserver91 虚拟机中。
能看到这块 ssd 硬盘:
$ lspci | grep Non-Volatile
01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983
02:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983
因为硬盘没有分区,所以看起来是这样:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 512G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 465.7G 0 part /
└─sda3 8:3 0 45.8G 0 part /timeshift
nvme0n1 259:0 0 838.4G 0 disk
nvme1n1 259:1 0 838.4G 0 disk
sda 是虚拟机的磁盘,虚拟了 512g。
nvme0n1 和 nvme1n1 是直通进来的 ssd 硬盘,900G 大小但实际可用大小为 838G。
硬盘分区
sudo fdisk /dev/nvme0n1
g 转为 GPT partition table p 打印分区表 n 创建新分区,这里就只创建一个900g的大分区给 nas 用。
分区完成后查看这块硬盘的情况:
sudo fdisk -l
Disk /dev/nvme0n1: 838.36 GiB, 900185481216 bytes, 219771846 sectors
Disk model: MZ1LB960HBJR-000FB
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 131072 bytes / 131072 bytes
Disklabel type: gpt
Disk identifier: 5BA21D3B-9403-0B4B-9399-E72086BE6F46
Device Start End Sectors Size Type
/dev/nvme0n1p1 256 219771647 219771392 838.4G Linux filesystem
Disk /dev/nvme1n1: 838.36 GiB, 900185481216 bytes, 219771846 sectors
Disk model: MZ1LB960HBJR-000FB
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 131072 bytes / 131072 bytes
Disklabel type: gpt
Disk identifier: 39AFF853-D9C1-7841-93CB-83DD3A83C7F0
Device Start End Sectors Size Type
/dev/nvme1n1p1 256 219771647 219771392 838.4G Linux filesystem
Disk /dev/sda: 512 GiB, 549755813888 bytes, 1073741824 sectors
Disk model: QEMU HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 784AC8F8-8E2A-4A0D-A9AD-D3056175791B
Device Start End Sectors Size Type
/dev/sda1 2048 1050623 1048576 512M EFI System
/dev/sda2 1050624 977612799 976562176 465.7G Linux filesystem
/dev/sda3 977612800 1073739775 96126976 45.8G Linux filesystem
硬盘格式化
将硬盘格式化为 ext4 文件系统:
sudo mkfs.ext4 /dev/nvme0n1p1
sudo mkfs.ext4 /dev/nvme1n1p1
挂载分区
查看 ssd 分区的 uuid:
$ sudo lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1
│ vfat FAT32 BE75-FC62 505.1M 1% /boot/efi
├─sda2
│ ext4 1.0 81fdaf25-6712-48ee-bb53-1c4a78c8ef9f 429G 1% /
└─sda3
ext4 1.0 4b922cfb-2123-48ce-b9fe-635e73fb6aa8 37.7G 11% /timeshift
nvme0n1
└─nvme0n1p1
nvme1n1
└─nvme1n1p1
执行
sudo vi /etc/fstab
查看目前现有的三个分区的挂载情况:
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda2 during installation
UUID=81fdaf25-6712-48ee-bb53-1c4a78c8ef9f / ext4 errors=remount-ro 0 1
# /boot/efi was on /dev/sda1 during installation
UUID=BE75-FC62 /boot/efi vfat umask=0077 0 1
# /timeshift was on /dev/sda3 during installation
UUID=4b922cfb-2123-48ce-b9fe-635e73fb6aa8 /timeshift ext4 defaults 0 2
/dev/sr0 /media/cdrom0 udf,iso9660 user,noauto 0 0
增加两块 ssd 硬盘的挂载,挂载到 “/mnt/data” 和 “/mnt/app”:
# data storage was on /dev/nvme0n1p1(960g)
UUID=be0b8bd0-edf1-49c2-b08d-dfc2d064c5ee /mnt/data ext4 defaults 0 2
# app storage was on /dev/nvme1n1p1(960g)
UUID=64e00394-bc95-4ca6-996d-7827f77e3a0d /mnt/app ext4 defaults 0 2
重启机器。再看一下分区挂载情况:
$ sudo lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1 vfat FAT32 BE75-FC62 505.1M 1% /boot/efi
├─sda2 ext4 1.0 81fdaf25-6712-48ee-bb53-1c4a78c8ef9f 429G 1% /
└─sda3 ext4 1.0 4b922cfb-2123-48ce-b9fe-635e73fb6aa8 37.6G 11% /timeshift
nvme1n1
└─nvme1n1p1 ext4 1.0 64e00394-bc95-4ca6-996d-7827f77e3a0d 782.2G 0% /mnt/app
nvme0n1
└─nvme0n1p1 ext4 1.0 be0b8bd0-edf1-49c2-b08d-dfc2d064c5ee 782.1G 0% /mnt/data
准备共享目录
为了方便后续的管理,采用伪文件系统:
cd /mnt/data
sudo mkdir shared
sudo mkdir pve-shared
sudo chown -R nobody:nogroup /mnt/data/shared
sudo chown -R nobody:nogroup /mnt/data/pve-shared
创建 export 目录:
sudo mkdir -p /exports/{shared,pve-shared}
sudo chown -R nobody:nogroup /exports
修改 /etc/fstab
文件来 mount 伪文件系统和 exports
sudo vi /etc/fstab
增加如下内容:
# nfs exports
/mnt/data/shared /exports/shared none bind
/mnt/data/pve-shared /exports/pve-shared none bind
重启。
搭建 nas
安装 nfs server
# 安装
sudo apt install nfs-kernel-server -y
# 开机自启
sudo systemctl start nfs-kernel-server
sudo systemctl enable nfs-kernel-server
# 验证
sudo systemctl status nfs-kernel-server
Jan 29 20:40:15 skynas3 systemd[1]: Starting nfs-server.service - NFS server and services...
Jan 29 20:40:15 skynas3 exportfs[1422]: exportfs: can't open /etc/exports for reading
Jan 29 20:40:16 skynas3 systemd[1]: Finished nfs-server.service - NFS server and services.
设置 nfs 版本支持
查看目前服务器端支持的 nfs 版本:
sudo cat /proc/fs/nfsd/versions
默认情况下,nfs server 支持的 nfs 版本为:
+3 +4 +4.1 +4.2
通常我们只需要保留 nfs 4.2 版本,其他版本都删除:
sudo vi /etc/nfs.conf
将默认的 nfsd:
[nfsd]
# debug=0
# threads=8
# host=
# port=0
# grace-time=90
# lease-time=90
# udp=n
# tcp=y
# vers3=y
# vers4=y
# vers4.0=y
# vers4.1=y
# vers4.2=y
# rdma=n
# rdma-port=20049
修改为:
[nfsd]
# debug=0
threads=32
# host=
# port=0
# grace-time=90
# lease-time=90
# udp=n
# tcp=y
vers3=n
vers4=y
vers4.0=n
vers4.1=n
vers4.2=y
# rdma=n
# rdma-port=20049
顺便把 nfs 线程数量从默认的 8 修改为 32。
重启 nfs-kernel-server:
sudo systemctl restart nfs-kernel-server
然后验证 nfs 版本:
sudo cat /proc/fs/nfsd/versions
输出为:
-3 +4 -4.0 -4.1 +4.2
注意: +4 是必须保留的,只有先设置 +4 版本,才能设置 4.0/4.1/4.2 版本,如果 -4 则 4.0/4.1/4.2 版本都会不支持。
也可以通过 rpcinfo 命令查看 nfs 版本:
rpcinfo -p localhost
输出为:
program vers proto port service
......
100003 4 tcp 2049 nfs
这里的 4 代表 nfs 4.x 版本,但是没法区分 4.0/4.1/4.2 版本。
配置 nfs export
sudo vi /etc/exports
修改 nfs exports 的内容,这里我们 export shared/pve-shared 目录:
/exports/shared 192.168.0.0/16(rw,sync,no_subtree_check,no_root_squash)
/exports/pve-shared 192.168.0.0/16(rw,sync,no_subtree_check,no_root_squash)
重启 nfs-kernel-server,查看 nfs-kernel-server 的状态:
sudo systemctl restart nfs-kernel-server
sudo systemctl status nfs-kernel-server
输出为:
nfs-server.service - NFS server and services
Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; preset: enabled)
Drop-In: /run/systemd/generator/nfs-server.service.d
└─order-with-mounts.conf
Active: active (exited) since Wed 2024-03-20 23:09:19 EDT; 17ms ago
Process: 863 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Process: 864 ExecStart=/usr/sbin/rpc.nfsd (code=exited, status=0/SUCCESS)
Main PID: 864 (code=exited, status=0/SUCCESS)
CPU: 7ms
Mar 20 23:09:19 skynas3 systemd[1]: Starting nfs-server.service - NFS server and services...
Mar 20 23:09:19 skynas3 systemd[1]: Finished nfs-server.service - NFS server and services.
验证:
ps -ef | grep nfs
输出为:
ps -ef | grep nfs
root 714 1 0 23:04 ? 00:00:00 /usr/sbin/nfsdcld
root 866 2 0 23:09 ? 00:00:00 [nfsd]
root 867 2 0 23:09 ? 00:00:00 [nfsd]
root 868 2 0 23:09 ? 00:00:00 [nfsd]
root 869 2 0 23:09 ? 00:00:00 [nfsd]
root 870 2 0 23:09 ? 00:00:00 [nfsd]
root 871 2 0 23:09 ? 00:00:00 [nfsd]
root 872 2 0 23:09 ? 00:00:00 [nfsd]
root 873 2 0 23:09 ? 00:00:00 [nfsd]
查看当前挂载情况:
$ sudo showmount -e
Export list for devserver91:
/exports/pve-shared 192.168.0.0/16
/exports/shared 192.168.0.0/16
nfs客户端
安装 nfs client:
sudo apt install nfs-common
准备目录:
sudo mkdir /mnt/shared91
sudo mount -t nfs4 192.168.3.91:/exports/shared /mnt/shared91
这样就能手工将远程 /exports/shared
目录挂载到本地目录。
暂时不采用开机自动挂载的方式,避免减缓开机的速度,增加鼓掌概率,需要 mount 时手工挂载就是。
方便起见,准备一个 mount_shared91 脚本:
sudo vi /mnt/mount_shared91.zsh
内容为:
#!/usr/bin/env zsh
# 定义变量
NFS_SERVER="192.168.3.91"
NFS_EXPORT="/exports/shared"
MOUNT_POINT="/mnt/shared91"
# 检查挂载点是否存在,不存在则创建
if [[ ! -d "$MOUNT_POINT" ]]; then
echo "创建挂载点目录: $MOUNT_POINT"
sudo mkdir -p "$MOUNT_POINT"
sudo chown "$USER:$USER" "$MOUNT_POINT" # 可选:设置当前用户为所有者
fi
# 检查是否已挂载
if mount | grep -q "$MOUNT_POINT"; then
echo "⚠️ $MOUNT_POINT 已经挂载"
else
echo "正在挂载 NFS: $NFS_SERVER:$NFS_EXPORT → $MOUNT_POINT"
sudo mount -t nfs4 "$NFS_SERVER:$NFS_EXPORT" "$MOUNT_POINT"
# 检查挂载是否成功
if [[ $? -eq 0 ]]; then
echo "✅ 挂载成功"
df -h | grep "$MOUNT_POINT" # 显示磁盘使用情况
else
echo "❌ 挂载失败,请检查:"
echo "1. NFS 服务器是否在线?"
echo "2. 客户端是否安装 nfs-common? (sudo apt install nfs-common)"
echo "3. 防火墙是否放行 NFS 端口?"
fi
fi
再准备一个 unmount_shared91 脚本:
sudo vi /mnt/unmount_shared91.zsh
内容为:
#!/usr/bin/env zsh
# 定义变量
NFS_SERVER="192.168.3.91"
NFS_EXPORT="/exports/shared"
MOUNT_POINT="/mnt/shared91"
if mount | grep -q "$MOUNT_POINT"; then
sudo umount -l "$MOUNT_POINT"
echo "✅ 已卸载 $MOUNT_POINT"
else
echo "⚠️ $MOUNT_POINT 未挂载"
fi
增加可执行权限:
sudo chmod +x /mnt/mount_shared91.zsh
sudo chmod +x /mnt/unmount_shared91.zsh
之后只要执行相应的命令就可以手工挂载和卸载 nfs shared 目录。
pve nfs storage
在 pve 下,点击 “datacenter” -> “storage” -> “Add”
完成这个设置之后,该集群内的任何一台机器上,都会出现一个 /mnt/pve/nfs91
目录,mount 到 上面的 nfs exports。之后就可以通过这个目录像访问本地文件夹一样访问nfs。
参考资料
4.2 - [归档]用物理机实现的SSD NAS存储
归档说明: 为了方便还是安装为 pve 虚拟机了。
构想
在前面实现的软交换的基础上,顺便实现一个SSD NAS,方便其他机器存储资料,如 pve 相关的虚拟机备份/模版/iso等。
这样就实现了 56g 网络 + 高速 SSD 的 NAS。
备注:因为兼容性原因,56g的 hp544+ 这块 cx3 pro 的网卡无法直通多块网卡给单个虚拟机(可以直通一块卡,两块就报错,换cx4以上就正常),所以这台机器使用的是物理机安装 debian 12.7。
准备工作
准备物理机
软交换机器为了性能和兼容采用的是物理机方式安装 debian,插了四块 hp544+ 网卡,实现了 40g/56g 软交换。
基于 40g/56g 网卡的高速网络已经满足。
硬盘情况
机器上目前是一块256g的三星pm981a用来安装 debian 操作系统,两块三星pm983a 1t 用来做 nas,lspci 能看到这三块 ssd 硬盘:
$ lspci | grep Non-Volatile
03:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983
04:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983
07:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983
还有一块东芝 mg08 14t 的机械硬盘,准备用来做资料备份。
分区情况:
$ sudo lsblk -l
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 12.7T 0 disk
sda1 8:1 0 12.7T 0 part /var/data3
nvme1n1 259:0 0 838.4G 0 disk
nvme0n1 259:1 0 838.4G 0 disk
nvme1n1p1 259:2 0 838.4G 0 part /var/data2
nvme0n1p1 259:3 0 838.4G 0 part /var/data
nvme2n1 259:4 0 238.5G 0 disk
nvme2n1p1 259:5 0 512M 0 part /boot/efi
nvme2n1p2 259:6 0 186.3G 0 part /
nvme2n1p3 259:7 0 51.7G 0 part /var/timeshift
用 fdisk 看更清晰一些:
$ sudo fdisk -l
Disk /dev/nvme1n1: 838.36 GiB, 900185481216 bytes, 1758174768 sectors
Disk model: MZ1LB960HBJR-000FB
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 131072 bytes / 131072 bytes
Disklabel type: gpt
Disk identifier: B724F254-A8C9-4FDD-B030-B68A85D4F6FD
Device Start End Sectors Size Type
/dev/nvme1n1p1 2048 1758173183 1758171136 838.4G Linux filesystem
Disk /dev/nvme0n1: 838.36 GiB, 900185481216 bytes, 1758174768 sectors
Disk model: MZ1LB960HBJR-000FB
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 131072 bytes / 131072 bytes
Disklabel type: gpt
Disk identifier: D495383E-8798-4B53-BED6-4CB6BBA29B74
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 1758173183 1758171136 838.4G Linux filesystem
Disk /dev/nvme2n1: 238.47 GiB, 256060514304 bytes, 500118192 sectors
Disk model: SAMSUNG MZVLB256HBHQ-000L7
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: F33C8916-7384-11EF-A4EE-8B1FC28B9DC5
Device Start End Sectors Size Type
/dev/nvme2n1p1 2048 1050623 1048576 512M EFI System
/dev/nvme2n1p2 1050624 391675903 390625280 186.3G Linux filesystem
/dev/nvme2n1p3 391675904 500117503 108441600 51.7G Linux filesystem
Disk /dev/sda: 12.73 TiB, 14000519643136 bytes, 27344764928 sectors
Disk model: TOSHIBA MG08ACA1
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: D64050D6-6671-0C41-9881-3E1CECCD24C1
Device Start End Sectors Size Type
/dev/sda1 2048 27344762879 27344760832 12.7T Linux filesystem
准备使用 /dev/nvme1n1p1
/ /dev/nvme0n1p1
/ /dev/sda1
这三个分区来存放 nfs 共享文件。在根目录下建立 “/data” 目录:
sudo mkdir /data
修改 timeshift 配置,将 /data
加入到 excludes 。
搭建 nas 服务器端
安装 nfs server
# 安装
sudo apt install nfs-kernel-server -y
# 开机自启
sudo systemctl start nfs-kernel-server
sudo systemctl enable nfs-kernel-server
# 验证
sudo systemctl status nfs-kernel-server
● nfs-server.service - NFS server and services
Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; preset: enabled)
Active: active (exited) since Tue 2024-09-17 04:06:44 CST; 28s ago
Main PID: 1901 (code=exited, status=0/SUCCESS)
CPU: 6ms
Sep 17 04:06:42 switch99 systemd[1]: Starting nfs-server.service - NFS server and services...
Sep 17 04:06:42 switch99 exportfs[1900]: exportfs: can't open /etc/exports for reading
Sep 17 04:06:44 switch99 systemd[1]: Finished nfs-server.service - NFS server and services.
配置 nfs v4
sudo vi /etc/default/nfs-common
修改内容如下
NEED_STATD="no"
NEED_IDMAPD="yes"
继续修改 nfs-kernel-server 的配置:
sudo vi /etc/default/nfs-kernel-server
修改内容:
# 这行新增
RPCNFSDOPTS="-N 2 -N 3"
# 这行已经存在,修改内容
RPCMOUNTDOPTS="--manage-gids -N 2 -N 3"
# 其他不动
重启 nfs-server
sudo systemctl restart nfs-server
配置 UFW 防火墙
安装 nfs 之后必须配置防火墙。先安装 ufw:
sudo apt install ufw -y
安装完成之后第一个必须执行的步骤就是开放 ssh 登录:
sudo ufw allow ssh
sudo ufw enable
然后是容许访问 nfs
sudo ufw allow from 192.168.0.0/16 to any port nfs
重启 ufw 并查看 ufw 状态:
sudo ufw reload
sudo ufw status
可以看到 2049 端口开放给 nfs 了。
$ sudo ufw status
[sudo] password for sky:
Firewall reloaded
Status: active
To Action From
-- ------ ----
22/tcp ALLOW Anywhere
2049 ALLOW 192.168.0.0/16
22/tcp (v6) ALLOW Anywhere (v6)
备注:暂时不知道为什么 ufw 开启之后就无法访问 nfs 了,上面的 allow rule 没能生效。只好暂时先 sudo ufw disable
关闭防火墙先。
准备共享目录
为了方便后续的管理,采用伪文件系统
sudo mkdir -p /data/{share,pve-share}
sudo chown -R nobody:nogroup /data/share
sudo chown -R nobody:nogroup /data/pve-share
创建 export 目录:
sudo mkdir -p /exports/{share,pve-share}
sudo chown -R nobody:nogroup /exports
修改 /etc/fstab
文件来 mount 伪文件系统和 exports
sudo vi /etc/fstab
增加如下内容:
# nfs exports
/data/share /exports/share none bind
/data/pve-share /exports/pve-share none bind
配置 nfs export
sudo vi /etc/exports
修改 nfs exports 的内容:
/exports/share 192.168.0.0/16(rw,no_root_squash,no_subtree_check,crossmnt,fsid=0)
/exports/pve-share 192.168.0.0/16(rw,no_root_squash,no_subtree_check,crossmnt,fsid=0)
重启 nfs-kernel-server,查看 nfs-kernel-server 的状态:
sudo systemctl restart nfs-kernel-server
sudo systemctl status nfs-kernel-server
输出为:
nfs-server.service - NFS server and services
Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; preset: enabled)
Drop-In: /run/systemd/generator/nfs-server.service.d
└─order-with-mounts.conf
Active: active (exited) since Mon 2024-03-18 21:11:34 CST; 21ms ago
Process: 6678 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Process: 6679 ExecStart=/usr/sbin/rpc.nfsd (code=exited, status=0/SUCCESS)
Main PID: 6679 (code=exited, status=0/SUCCESS)
CPU: 7ms
Mar 18 21:11:34 switch99 systemd[1]: Starting nfs-server.service - NFS server and services...
Mar 18 21:11:34 switch99 systemd[1]: Finished nfs-server.service - NFS server and services.
验证:
ps -ef | grep nfs
输出为:
root 4438 1 0 20:24 ? 00:00:00 /usr/sbin/nfsdcld
root 6682 2 0 21:11 ? 00:00:00 [nfsd]
root 6683 2 0 21:11 ? 00:00:00 [nfsd]
root 6684 2 0 21:11 ? 00:00:00 [nfsd]
root 6685 2 0 21:11 ? 00:00:00 [nfsd]
root 6686 2 0 21:11 ? 00:00:00 [nfsd]
root 6687 2 0 21:11 ? 00:00:00 [nfsd]
root 6688 2 0 21:11 ? 00:00:00 [nfsd]
root 6689 2 0 21:11 ? 00:00:00 [nfsd]
查看当前挂载情况:
sudo showmount -e
输出为:
Export list for switch99:
/exports 192.168.0.0/255.255.0.0
nfs客户端
pve nfs storage
在 pve 下,点击 “datacenter” -> “storage” -> “Add”
备注: nfs version 这里无法选择 4 / 4.1 / 4.2,只能选择 default 。后续再看。
完成这个设置之后,该集群内的任何一台机器上,都会出现一个 /mnt/pve/nfs99
目录,mount 到 上面的 nfs exports。之后就可以通过这个目录像访问本地文件夹一样访问nfs。
清理 /mnt/pve
目录
如果多次操作 nfs 存储,比如添加后再删除,则在 /mnt/pve/nfs99
目录下会残留一些数据,如:
ls -la
ls: cannot access 'nfs-test11': Stale file handle
total 12
drwxr-xr-x 4 root root 4096 Mar 18 22:26 .
drwxr-xr-x 3 root root 4096 Mar 18 22:23 ..
drwxr-xr-x 7 nobody nogroup 4096 Mar 18 22:26 nfs99
d????????? ? ? ? ? ? nfs-test11
这个 nfs-test11 就是删除之后的残余,不能直接删除:
rm -rf nfs-test11
rm: cannot remove 'nfs-test11': Is a directory
而是要使用 umount 命令:
$ sudo umount nfs-test11
$ ls -la
total 16
drwxr-xr-x 4 root root 4096 Mar 18 22:26 .
drwxr-xr-x 3 root root 4096 Mar 18 22:23 ..
drwxr-xr-x 7 nobody nogroup 4096 Mar 18 22:26 nfs99
drwxr-xr-x 2 root root 4096 Mar 18 22:23 nfs-test11
$ sudo rm -rf nfs-test11
复制 pve 文件
在 pve 页面上查看 backup 里面需要复制的备份,主要看虚拟机 id 和时间。
对于已经加入 pve 集群的机器,本地已经 mount 了 /mnt/pve/nfs99
目录,因此可以直接执行 cp 命令复制到 nfs 上:
cp /var/lib/vz/dump/vzdump-qemu-101-2024_02_12-16_13_09.* /mnt/pve/nfs99/dump
对于还没有加入 pve 集群的机器,需要先手工 mount nfs 到本地:
sudo mkdir -p /mnt/pve/nfs
sudo mount.nfs 192.168.0.99:/exports/pve-share /mnt/pve/nfs
# mount.nfs4 会报错,暂时不清楚问题出在哪里,mount.nfs 就可以正常使用
# sudo mount.nfs4 192.168.0.99:/exports/pve-share /mnt/pve/nfs
然后再复制 backup 文件:
cp /var/lib/vz/dump/vzdump-qemu-101-2024_02_12-16_13_09.* /mnt/pve/nfs/dump
为了方便备份各个机器独有的文件(而不是模版等可以共享的文件),在这个 nfs 目录下新建一个 node-backup 目录,并为每个节点建立一个子目录:
mkdir -p /mnt/pve/nfs/node-backup/skyserver4/dump
然后就可以复制
cp xxxx /mnt/pve/nfs/node-backup/skyserver4/dump
参考资料
4.3 - [归档]用虚拟机实现的SSD NAS存储
归档说明: nfs on rdma 没能搞定,nfs 访问的速度很一般,放弃。
构想
在前面实现的软交换的基础上,直通一块 4t 的国产 pcie4 ssd 进入(型号为爱国者 p7000z),实现一个小型的纯 SSD NAS。
未来可能会陆续加入多块 ssd 进行扩容。
这样就实现了 25g 网络 + 高速 SSD 的 NAS。
准备工作
准备虚拟机
之前的利用 linux bridge 实现软交换的解决方案中,已经建立了一个名为 skynas3 的虚拟机。
基于 25g 网卡的高速网络已经满足。
硬盘直通
在开启 pve 直通的基础上,将硬盘直通到 skynas3 虚拟机中。
能看到这块 ssd 硬盘:
$ lspci | grep Non-Volatile
03:00.0 Non-Volatile memory controller: MAXIO Technology (Hangzhou) Ltd. NVMe SSD Controller MAP1602 (rev 01)
因为硬盘没有分区,所以看起来是这样:
lsblk -l
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 512G 0 disk
sda1 8:1 0 512M 0 part /boot/efi
sda2 8:2 0 465.7G 0 part /
sda3 8:3 0 45.8G 0 part /timeshift
sr0 11:0 1 3.7G 0 rom
nvme0n1 259:0 0 3.7T 0 disk
sda 是虚拟机的磁盘,虚拟了 512g。
nvme0n1 是直通进来的 ssd 硬盘,4t 大小但实际为 3.7 T。
用 fdisk 看更清晰一些:
$ sudo fdisk -l
[sudo] password for sky:
Disk /dev/sda: 512 GiB, 549755813888 bytes, 1073741824 sectors
Disk model: QEMU HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: D53AE25D-B704-4192-A436-54BD53A9DAC0
Device Start End Sectors Size Type
/dev/sda1 2048 1050623 1048576 512M EFI System
/dev/sda2 1050624 977612799 976562176 465.7G Linux filesystem
/dev/sda3 977612800 1073739775 96126976 45.8G Linux filesystem
Disk /dev/nvme0n1: 3.73 TiB, 4096805658624 bytes, 8001573552 sectors
Disk model: aigo NVMe SSD P7000Z 4TB
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 9F1409D0-DA10-5446-8662-4ADAFBF1128F
硬盘分区
sudo fdisk /dev/nvme0n1
g 转为 GPT partition table p 打印分区表 n 创建新分区,这里就只创建一个4t的大分区给 nas 用。
参考:
分区完成后查看这块硬盘的情况:
$ sudo fdisk -l
Disk /dev/nvme0n1: 3.73 TiB, 4096805658624 bytes, 8001573552 sectors
Disk model: aigo NVMe SSD P7000Z 4TB
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: BCA9FF34-B3F2-B44D-B385-041E061B8F52
Device Start End Sectors Size Type
/dev/nvme0n1p1 2048 8001572863 8001570816 3.7T Linux filesystem
将这个分区格式化为 ext4 格式:
sudo mkfs.ext4 /dev/nvme0n1p1
mke2fs 1.47.0 (5-Feb-2023)
Discarding device blocks: done
Creating filesystem with 1000196352 4k blocks and 250052608 inodes
Filesystem UUID: 1b50172f-44fd-46a3-8499-b169d7d91eac
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000, 214990848, 512000000, 550731776, 644972544
Allocating group tables: done
Writing inode tables: done
Creating journal (262144 blocks): done
Writing superblocks and filesystem accounting information: done
挂载分区
查看 ssd 分区的 uuid:
sudo lsblk -f
[sudo] password for sky:
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1 vfat FAT32 80D7-F301 505.1M 1% /boot/efi
├─sda2 ext4 1.0 59bbb3ad-27e7-4e1e-b40e-0e6a8a8386cc 430.8G 1% /
└─sda3 ext4 1.0 d5aaad4b-8382-4153-adfc-f7c797e74ee5 38.6G 9% /timeshift
nvme0n1
└─nvme0n1p1 ext4 1.0 b4e82288-5290-4d64-a45e-94c4ef657611
执行
sudo vi /etc/fstab
查看目前现有的三个分区的挂载情况:
# / was on /dev/sda2 during installation
UUID=59bbb3ad-27e7-4e1e-b40e-0e6a8a8386cc / ext4 errors=remount-ro 0 1
# /boot/efi was on /dev/sda1 during installation
UUID=80D7-F301 /boot/efi vfat umask=0077 0 1
# /timeshift was on /dev/sda3 during installation
UUID=d5aaad4b-8382-4153-adfc-f7c797e74ee5 /timeshift ext4 defaults 0 2
增加第一块 ssd 硬盘的挂载,挂载到 “/mnt/storage1”:
# /storage1 was on /dev/nvme0n1p1(aigo p7000z 4t)
UUID=b4e82288-5290-4d64-a45e-94c4ef657611 /mnt/storage1 ext4 defaults 0 2
重启机器。再看一下分区挂载情况:
$ sudo lsblk -f
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
├─sda1 vfat FAT32 80D7-F301 505.1M 1% /boot/efi
├─sda2 ext4 1.0 59bbb3ad-27e7-4e1e-b40e-0e6a8a8386cc 430.7G 1% /
└─sda3 ext4 1.0 d5aaad4b-8382-4153-adfc-f7c797e74ee5 38.6G 9% /timeshift
nvme0n1
└─nvme0n1p1 ext4 1.0 b4e82288-5290-4d64-a45e-94c4ef657611 3.5T 0% /mnt/storage1
准备共享目录
为了方便后续的管理,采用伪文件系统:
cd /mnt/storage1
sudo mkdir share
sudo mkdir pve-share
sudo chown -R nobody:nogroup /mnt/storage1/share
sudo chown -R nobody:nogroup /mnt/storage1/pve-share
创建 export 目录:
sudo mkdir -p /exports/{share,pve-share}
sudo chown -R nobody:nogroup /exports
修改 /etc/fstab
文件来 mount 伪文件系统和 exports
sudo vi /etc/fstab
增加如下内容:
# nfs exports
/mnt/storage1/share /exports/share none bind
/mnt/storage1/pve-share /exports/pve-share none bind
重启。
搭建 nas
安装 nfs server
# 安装
sudo apt install nfs-kernel-server -y
# 开机自启
sudo systemctl start nfs-kernel-server
sudo systemctl enable nfs-kernel-server
# 验证
sudo systemctl status nfs-kernel-server
Jan 29 20:40:15 skynas3 systemd[1]: Starting nfs-server.service - NFS server and services...
Jan 29 20:40:15 skynas3 exportfs[1422]: exportfs: can't open /etc/exports for reading
Jan 29 20:40:16 skynas3 systemd[1]: Finished nfs-server.service - NFS server and services.
配置 nfs v4
sudo vi /etc/default/nfs-common
修改内容如下
NEED_STATD="no"
NEED_IDMAPD="yes"
继续修改 nfs-kernel-server 的配置:
sudo vi /etc/default/nfs-kernel-server
修改内容:
# 这行新增
RPCNFSDOPTS="-N 2 -N 3"
# 这行已经存在,修改内容
RPCMOUNTDOPTS="--manage-gids -N 2 -N 3"
# 其他不动
配置 nfs export
sudo vi /etc/exports
修改 nfs exports 的内容,这里我们先 export 第一块4t ssd 硬盘的 share/pve-share 目录:
/exports/share 192.168.0.0/16(rw,no_root_squash,no_subtree_check,crossmnt,fsid=0)
/exports/pve-share 192.168.0.0/16(rw,no_root_squash,no_subtree_check,crossmnt,fsid=0)
重启 nfs-kernel-server,查看 nfs-kernel-server 的状态:
sudo systemctl restart nfs-kernel-server
sudo systemctl status nfs-kernel-server
输出为:
nfs-server.service - NFS server and services
Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; preset: enabled)
Drop-In: /run/systemd/generator/nfs-server.service.d
└─order-with-mounts.conf
Active: active (exited) since Wed 2024-03-20 23:09:19 EDT; 17ms ago
Process: 863 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
Process: 864 ExecStart=/usr/sbin/rpc.nfsd (code=exited, status=0/SUCCESS)
Main PID: 864 (code=exited, status=0/SUCCESS)
CPU: 7ms
Mar 20 23:09:19 skynas3 systemd[1]: Starting nfs-server.service - NFS server and services...
Mar 20 23:09:19 skynas3 systemd[1]: Finished nfs-server.service - NFS server and services.
验证:
ps -ef | grep nfs
输出为:
ps -ef | grep nfs
root 714 1 0 23:04 ? 00:00:00 /usr/sbin/nfsdcld
root 866 2 0 23:09 ? 00:00:00 [nfsd]
root 867 2 0 23:09 ? 00:00:00 [nfsd]
root 868 2 0 23:09 ? 00:00:00 [nfsd]
root 869 2 0 23:09 ? 00:00:00 [nfsd]
root 870 2 0 23:09 ? 00:00:00 [nfsd]
root 871 2 0 23:09 ? 00:00:00 [nfsd]
root 872 2 0 23:09 ? 00:00:00 [nfsd]
root 873 2 0 23:09 ? 00:00:00 [nfsd]
查看当前挂载情况:
sudo showmount -e
输出为:
Export list for skynas3:
/exports/pve-share 192.168.0.0/16
/exports/share 192.168.0.0/16
nfs客户端
pve nfs storage
在 pve 下,点击 “datacenter” -> “storage” -> “Add”
备注: nfs version 这里无法选择 4 / 4.1 / 4.2,只能选择 default 。后续再看。
完成这个设置之后,该集群内的任何一台机器上,都会出现一个 /mnt/pve/nfs99
目录,mount 到 上面的 nfs exports。之后就可以通过这个目录像访问本地文件夹一样访问nfs。
遇到的问题
nfs 残余数据
期间遇到一个问题,我先创建了一个 nfs storage,指向了 share 目录。后来发现需要 export 两个目录,普通 share 和 pve 专用的 pve-share,避免将两者的文件混合起来。
然后就遇到问题:旧的 nfs storage 删除之后,再创建同名的 nfs storage 指向新的 pve-share,但实际操作的依然是旧的 share。反复尝试过各种方法都无效。
- 清理
/mnt/pve/
目录 - 清理
/var/lib/rrdcached/db/pve2-storage/
目录
sudo find / -type f -exec grep "nfs02" {} \;
grep: /var/log/journal/4ba9084c7be94c57a943bf7c2aa034a5/system.journal: binary file matches
update /var/lib/rrdcached/db/pve2-storage/skyaio2/nfs02 1710992038:4031332220928:0
只好在清理完这些信息之后,再用一个新的名字重新创建 nfs storage,比如 nfs02-ssd 。
参考资料
5 - 开发
5.1 - 开发工具
5.1.1 - 编译工具
系统类
常用的编译工具:
sudo apt install -y cmake make gcc g++
sudo apt install -y clang libclang-dev
zlib / bzip2 / ncurses / libffi / readline / libssl / sqlite3 / lzma 等依赖库:
sudo apt install zlib1g-dev libbz2-dev libncurses-dev libffi-dev libreadline-dev libssl-dev libsqlite3-dev liblzma-dev
5.1.2 - Nexus
Nexus Repository Manager 是一个强大的仓库管理工具,支持多种仓库类型,包括 Maven、go module 等。它提供了一个集中的存储库,用于存储和管理软件包,并提供了一个安全的访问控制机制。
备注: 之所以选择 nexus 而不是 artifactory,是因为 nexus 是开源的,而 artifactory 是闭源+收费的。
以下以 nexus 3.79.1-04 为例,介绍如何安装和配置 nexus。
参考官方文档: https://help.sonatype.com/en/sonatype-nexus-repository.html
准备
创建 nexus 用户专门用于运行 nexus:
sudo useradd -M -d /mnt/data/nexus -s /bin/zsh -r nexus
创建 nexus 目录:
sudo mkdir -p /mnt/data/nexus
sudo chown -R nexus:nexus /mnt/data/nexus
下载
从下面地址找到 nexus 安装包:
https://help.sonatype.com/en/download-archives---repository-manager-3.html
从官方下载 nexus 安装包 nexus-3.79.1-04:
cd /mnt/data/nexus
sudo wget https://download.sonatype.com/nexus/3/nexus-3.79.1-04-linux-x86_64.tar.gz
备注: 这个版本是自带 jdk 的,因此不需要单独安装 jdk。自带的 jdk 在
nexus/jdk/temurin_17.0.13_11_linux_x86_64
目录下。
解压安装包:
sudo tar -xzf nexus-3.79.1-04-linux-x86_64.tar.gz -C /mnt/data/nexus
sudo rm -rf nexus-3.79.1-04-linux-x86_64.tar.gz
sudo chown -R nexus:nexus /mnt/data/nexus
重命名 nexus 目录去掉版本信息(方便以后升级版本):
sudo mv nexus-3.79.1-04 nexus
得到如下目录:
$ ls -la
drwxr-xr-x 8 nexus nexus 4096 Apr 7 10:32 nexus
drwxr-xr-x 3 nexus nexus 4096 Mar 29 04:56 sonatype-work
安装
参考官方文档:
https://help.sonatype.com/en/install-nexus-repository.html
cd nexus/bin
这个目录下的 nexus
是启动脚本,nexus.vmoptions
是 jvm 配置文件。
查看 nexus.vmoptions
文件,可以看到默认的数据和日志目录:
-XX:LogFile=../sonatype-work/nexus3/log/jvm.log
-Dkaraf.home=.
-Dkaraf.base=.
-Dkaraf.data=../sonatype-work/nexus3
-Dkaraf.log=../sonatype-work/nexus3/log
-Djava.io.tmpdir=../sonatype-work/nexus3/tmp
配置系统服务:
sudo vi /etc/systemd/system/nexus.service
添加如下内容:
[Unit]
Description=Nexus Repository Manager
After=network.target
[Service]
Type=forking
User=nexus
Group=nexus
ExecStart=/mnt/data/nexus/nexus/bin/nexus start
ExecStop=/mnt/data/nexus/nexus/bin/nexus stop
Restart=on-failure
RestartSec=30
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
启用并启动服务:
sudo systemctl daemon-reload
sudo systemctl enable nexus
sudo systemctl start nexus
检查状态:
$ sudo systemctl status nexus
● nexus.service - Nexus Repository Manager
Loaded: loaded (/etc/systemd/system/nexus.service; enabled; preset: enabled)
Active: active (running) since Mon 2025-04-07 10:32:27 CST; 4min 7s ago
Process: 4495 ExecStart=/opt/nexus/nexus/bin/nexus start (code=exited, status=0/SUCCESS)
Main PID: 4736 (java)
Tasks: 97 (limit: 38379)
Memory: 2.1G
CPU: 1min 34.806s
CGroup: /system.slice/nexus.service
└─4736 /opt/nexus/nexus/jdk/temurin_17.0.13_11_linux_x86_64/jdk-17.0.13+11/bin/java -server -XX:+Un>
Apr 07 10:32:26 debian12 systemd[1]: Starting nexus.service - Nexus Repository Manager...
Apr 07 10:32:27 debian12 nexus[4495]: /opt/nexus/nexus/bin/nexus: 155: [[: not found
Apr 07 10:32:27 debian12 nexus[4495]: Starting nexus
Apr 07 10:32:27 debian12 systemd[1]: Started nexus.service - Nexus Repository Manager.
查看 nexus 进程信息:
$ ps -ef | grep nexus
nexus 19863 1 99 15:30 ? 00:01:12 /mnt/data/nexus/nexus/jdk/temurin_17.0.13_11_linux_x86_64/jdk-17.0.13+11/bin/java -server -XX:+UnlockDiagnosticVMOptions -Xms2703m -Xmx2703m -XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=../sonatype-work/nexus3/log/jvm.log -XX:-OmitStackTraceInFastThrow -Dkaraf.home=. -Dkaraf.base=. -Djava.util.logging.config.file=etc/spring/java.util.logging.properties -Dkaraf.data=../sonatype-work/nexus3 -Dkaraf.log=../sonatype-work/nexus3/log -Djava.io.tmpdir=../sonatype-work/nexus3/tmp -Djdk.tls.ephemeralDHKeySize=2048 --add-reads=java.xml=java.logging --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.naming/javax.naming.spi=ALL-UNNAMED --add-opens java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.http=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.https=ALL-UNNAMED --add-exports=java.base/sun.net.www.protocol.jar=ALL-UNNAMED --add-exports=jdk.xml.dom/org.w3c.dom.html=ALL-UNNAMED --add-exports=jdk.naming.rmi/com.sun.jndi.url.rmi=ALL-UNNAMED --add-exports=java.security.sasl/com.sun.security.sasl=ALL-UNNAMED --add-exports=java.base/sun.security.x509=ALL-UNNAMED --add-exports=java.base/sun.security.rsa=ALL-UNNAMED --add-exports=java.base/sun.security.pkcs=ALL-UNNAMED -jar /mnt/data/nexus/nexus/bin/sonatype-nexus-repository-3.79.0-09.jar
访问
访问地址:
http://192.168.3.91:8081/
第一次启动会比较慢,要耐心等待几十秒中。
登录时使用帐号 admin
和初始管理员密码,初始管理员密码位于:
sudo vi /mnt/data/nexus/sonatype-work/nexus3/admin.password
初始管理员密码会是一个类似这样的字符串:
16fe9704-fd38-4e4c-8077-51db4b2ab8f2
登录后会有一个引导过程,首先需要修改管理员密码。
注意: 设置密码后,admin.password 文件会被删除。
设置匿名访问,我是给我自己用的,所以设置为允许匿名访问:
配置
jvm 内存配置
sudo vi /mnt/data/nexus/nexus/bin/nexus.vmoptions
修改 nexus.vmoptions
文件,增加如下内容:
# 默认Xms/Xmx是2703m/2703m
-Xms2703m
-Xmx2703m
# 增加直接内存大小
-XX:MaxDirectMemorySize=2g
端口配置
默认端口是 8081,可以
sudo vi /mnt/data/nexus/nexus/etc/nexus-default.properties
找到 nexus-default.properties
文件,修改 application-port
端口:
application-port=8081
application-host=0.0.0.0
仓库
nexus 安装后自带的默认仓库:
可以看到 maven 和 nuget 都是准备好了的。
maven 仓库
自带的四个 maven 仓库:
- maven-releases 仓库: 这是一个 hosted 仓库,用于存储发布版本的 jar 包。
- maven-snapshots 仓库: 这是一个 hosted 仓库,用于存储快照版本的 jar 包。
- maven-central 仓库: 这是一个 proxy 仓库,代理了 https://repo1.maven.org/maven2/ 仓库
- maven-public 仓库: 这是一个 group 仓库,将 maven-releases、maven-snapshots 和 maven-central 仓库聚合在一起。
nuget 仓库
自带的三个 nuget 仓库:
- nuget-hosted 仓库: 这是一个 hosted 仓库,用于存储 nuget 包。
- nuget-org-proxy 仓库: 这是一个 proxy 仓库,代理了 https://api.nuget.org/v3/index.json 仓库
- nuget-group 仓库: 这是一个 group 仓库,将 nuget-hosted 和 nuget-org-proxy 仓库聚合在一起。
目前不做 .net 开发,所以 nuget 仓库暂时用不上,都删除。
其他仓库
需要自己创建,参见后面的章节。
- go module 仓库
- rust cargo 仓库
- npm 仓库
- pypi 仓库
准备用户
新建一个 deployment 用户,专门用于部署。
5.1.3 - sdkman
介绍
sdkman 是一个软件包管理工具,可以管理多个版本的软件包,包括 java,golang,python 等。
官方网站:
可以将 sdkman 理解为多个平台上可用的工具包以简化多版本的 SDK 管理。
sdkman 支持的 jdk 列表请见: https://sdkman.io/jdks
sdkman 支持的 sdk 列表请见: https://sdkman.io/sdks
安装
安装方法参考官方文档:
curl -s "https://get.sdkman.io" | bash
安装完成后,关闭当前终端重新打开新的终端,或者在当前终端中执行下面的命令立即更新:
source ~/.sdkman/bin/sdkman-init.sh
验证一下安装的版本:
$ sdk version
SDKMAN!
script: 5.19.0
native: 0.7.4 (linux x86_64)
默认情况下,sdkman 安装在 HOME 下的 .sdkman
子目录中:
$ ls ~/.sdkman
bin candidates contrib etc ext libexec src tmp var
使用
参考官方文档:
常用命令:
# 列出所有支持的软件包
sdk list
# 列出所有支持的 jdk
sdk list java
# 安装 jdk
sdk install java 17.0.14-zulu
# 卸载 jdk
sdk uninstall java 17.0.14-zulu
# 在当前 shell 中使用特定版本的 jdk
sdk use java 17.0.14-zulu
# 设置 jdk 为默认版本
sdk default java 17.0.14-zulu
# 查看当前使用的 jdk 版本
sdk current java
5.2 - 编程语言
5.2.1 - Java 编程语言
5.2.1.1 - 安装JDK
强烈建议使用 sdkman 之类的多版本管理方案来安装 jdk。
安装 JDK
列出当前系统中所有可用的 jdk 版本:
sdk list java
我偏好使用 zulu 的 openjdk 版本,所以这里以 zulu 为例。
jdk24(non-LTS)
追踪一下最新版本的 jdk:
sdk install java 24.0.1-zulu
jdk21(LTS)
虚拟线程正式发布,分代 ZGC、序列集合等新特性。
sdk install java 21.0.7-zulu
jdk17(LTS)
包含密封类(Sealed Classes)、模式匹配等新特性。
sdk install java 17.0.15-zulu
jdk11(LTS)
移除 Java EE 模块,引入 HTTP Client API、局部变量类型推断(var)等
sdk install java 11.0.27-zulu
jdk8(LTS)
jdk8 是最广泛使用的版本,支持 Lambda 表达式、Stream API 等。
sdk install java 8.0.452-zulu
使用 jdk
列出目前已经安装的 jdk 版本:
ls ~/.sdkman/candidates/java/
输出如下:
11.0.26-zulu 17.0.14-zulu 21.0.6-zulu 8.0.442-zulu current
设置默认的 jdk 版本:
sdk default java 17.0.14-zulu
在当前 shell 中使用指定版本的 jdk,可覆盖默认设置:
sdk use java 11.0.26-zulu
查看当前使用的 jdk 版本:
sdk current java
查看 jdk 版本信息:
$ java --version
openjdk 17.0.14 2025-01-21 LTS
OpenJDK Runtime Environment Zulu17.56+15-CA (build 17.0.14+7-LTS)
OpenJDK 64-Bit Server VM Zulu17.56+15-CA (build 17.0.14+7-LTS, mixed mode, sharing)
5.2.1.2 - 安装 Maven
安装
sdkman 安装
列出当前系统中所有可用的 maven 版本:
sdk list maven
输出为:
Available Maven Versions
4.0.0-rc-3 3.9.0 3.5.2
4.0.0-rc-2 3.8.8 3.5.0
4.0.0-rc-1 3.8.7 3.3.9
4.0.0-beta-5 3.8.6 3.3.3
4.0.0-beta-4 3.8.5 3.3.1
4.0.0-beta-3 3.8.4 3.2.5
* 3.9.9 3.8.3 3.2.3
3.9.8 3.8.2 3.2.2
3.9.7 3.8.1 3.2.1
3.9.6 3.6.3 3.1.1
3.9.5 3.6.2 3.1.0
3.9.4 3.6.1 3.0.5
3.9.3 3.6.0 3.0.4
3.9.2 3.5.4
3.9.1 3.5.3
================================================================================
+ - local version
* - installed
> - currently in use
================================================================================
安装指定版本的 maven, 4.0 还是 rc 版本, 先用 3.9 系列:
sdk install maven 3.9.9
输出为:
Downloading: maven 3.9.9
In progress...
########################################################################################################################################### 100.0%
Installing: maven 3.9.9
Done installing!
重启 shell 或者执行下列命令重新加载 sdkman :
source ~/.sdkman/bin/sdkman-init.sh
验证 maven 安装版本:
$ mvn --version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /home/sky/.sdkman/candidates/maven/current
Java version: 17.0.14, vendor: Azul Systems, Inc., runtime: /home/sky/.sdkman/candidates/java/17.0.14-zulu
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.1.0-31-amd64", arch: "amd64", family: "unix"
配置
配置代理服务器
如有需要,配置代理服务器:
export MAVEN_OPTS="-DsocksProxyHost=192.168.0.1 -DsocksProxyPort=7891"
配置 maven 仓库
maven 的 settings.xml 文件可以在多个地方配置,优先级从高到低依次为:
- 用户目录下的
.m2/settings.xml
文件 - 项目根目录下的
pom.xml
文件 - 全局配置文件, 一般在 maven 安装路径下的
conf/settings.xml
文件
在当前用户目录下创建 .m2
目录:
mkdir -p ~/.m2
cd ~/.m2
在 .m2
目录下创建 settings.xml
文件:
vi settings.xml
在 settings.xml
文件中添加如下内容:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>maven-releases</id>
<username>deployment</username>
<password>xxxxxxxx</password>
</server>
<server>
<id>maven-snapshots</id>
<username>deployment</username>
<password>xxxxxxxx</password>
</server>
</servers>
<mirrors>
<mirror>
<id>nexus-mirror</id>
<name>Nexus Repository</name>
<url>http://192.168.3.91:8081/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
<profiles>
<profile>
<id>nexus</id>
<properties>
<altSnapshotDeploymentRepository>maven-snapshots::default::http://192.168.3.91:8081/repository/maven-snapshots/</altSnapshotDeploymentRepository>
<altReleaseDeploymentRepository>maven-releases::default::http://192.168.3.91:8081/repository/maven-releases/</altReleaseDeploymentRepository>
</properties>
<repositories>
<repository>
<id>maven-releases</id>
<url>http://192.168.3.91:8081/repository/maven-releases/</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots>
</repository>
<repository>
<id>maven-snapshots</id>
<url>http://192.168.3.91:8081/repository/maven-snapshots/</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>nexus</activeProfile>
</activeProfiles>
</settings>
验证
验证 nexus 代理仓库的缓存功能
mkdir -p ~/work/code/temp/java-demo
cd ~/work/code/temp/java-demo
git clone https://github.com/dapr/java-sdk.git
cd java-sdk
mvn install -DskipTests -Djacoco.skip=true
第一次运行时,会因为要下载大量的依赖,速度非常慢。
之后检查 nexus 的 maven-public 和 maven-central 仓库,会发现缓存了很多依赖。
验证 nexus 缓存的效果,可以先删除本地已经下载的 maven 依赖:
rm -rf ~/.m2/repository
然后再次执行 maven 命令,会发现速度非常快。
验证 nexus hosted 仓库的上传功能
指定 maven deploy 时要用的分发仓库的方式有三种:
-
在 pom.xml 中配置分发仓库
<distributionManagement> <snapshotRepository> <id>maven-snapshots</id> <url>http://192.168.0.246:8081/repository/maven-snapshots/</url> </snapshotRepository> <repository> <id>maven-releases</id> <url>http://192.168.0.246:8081/repository/maven-releases/</url> </repository> </distributionManagement>
这个方式要在每个项目的 pom.xml 中配置分发仓库,如果项目很多,配置起来比较麻烦。不推荐。
-
在命令行中强制指定仓库
mvn deploy -DaltDeploymentRepository=maven-snapshots::default::http://192.168.0.246:8081/repository/maven-snapshots/
这个方式每次执行 maven deploy 命令时都要指定仓库,也嫌麻烦。不推荐。
-
在 settings.xml 中配置分发仓库
在配置 profile 时,可以设置 altSnapshotDeploymentRepository 和 altReleaseDeploymentRepository 属性,指定分发仓库。
<profiles> <profile> <id>nexus</id> <properties> <altSnapshotDeploymentRepository>maven-snapshots::default::http://192.168.0.246:8081/repository/maven-snapshots/</altSnapshotDeploymentRepository> <altReleaseDeploymentRepository>maven-releases::default::http://192.168.0.246:8081/repository/maven-releases/</altReleaseDeploymentRepository> </properties> <repositories> </repositories> </profile> </profiles>
这样执行 maven deploy 命令时,会使用配置的分发仓库。非常方便。
注意: 要在项目的 pom.xml 中配置使用 maven-deploy-plugin 插件,不要使用 nexus-staging-maven-plugin。
<project>
......
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.4</version>
</plugin>
</plugins>
</build>
</project>
demo 验证
mkdir -p ~/work/code/temp/java-demo
cd ~/work/code/temp/java-demo
# 现在不能直接从 github 下载了?
#wget https://github.com/skyao/learning-debian/blob/main/content/zh-cn/docs/develop/langurage/java/maven/images/maven-deploy-demo.tar
# 先收工下载到本地,再scp 传输文件到 devserver91 机器备用
# scp ./maven-deploy-demo.tar sky@192.168.3.91:/home/sky/work/code/temp/java-demo
# 以后用的时候再从 devserver91 机器下载
scp sky@192.168.3.91:/home/sky/work/code/temp/java-demo/maven-deploy-demo.tar .
tar -xvf maven-deploy-demo.tar
cd maven-deploy-demo
mvn deploy
输出为:
......
Uploading to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/1.0.0-SNAPSHOT/maven-deploy-demo-1.0.0-20250507.023145-1.pom
Uploaded to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/1.0.0-SNAPSHOT/maven-deploy-demo-1.0.0-20250507.023145-1.pom (887 B at 25 kB/s)
Uploading to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/1.0.0-SNAPSHOT/maven-deploy-demo-1.0.0-20250507.023145-1.jar
Uploaded to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/1.0.0-SNAPSHOT/maven-deploy-demo-1.0.0-20250507.023145-1.jar (2.2 kB at 118 kB/s)
Downloading from maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/maven-metadata.xml
Uploading to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/1.0.0-SNAPSHOT/maven-metadata.xml
Uploaded to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/1.0.0-SNAPSHOT/maven-metadata.xml (778 B at 46 kB/s)
Uploading to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/maven-metadata.xml
Uploaded to maven-snapshots: http://192.168.3.91:8081/repository/maven-snapshots/com/example/maven-deploy-demo/maven-metadata.xml (288 B at 19 kB/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 16.809 s
[INFO] Finished at: 2025-05-07T10:32:01+08:00
[INFO] ------------------------------------------------------------------------
在 nexus 的 maven-snapshots 仓库中可以看到刚刚上传的 maven-deploy-demo 的 pom 和 jar 文件:
5.2.2 - Golang 编程语言
参考:
https://skyao.io/learning-golang/docs/develop/installation/
包括安装 golang 并配置 nexus 的 golang proxy 仓库来加速构建。
5.2.4 - Python 编程语言
参考:
https://skyao.io/learning-python/docs/installation/linux/
包括使用 pyevn 管理多个 python 版本,配置 pip 镜像源和使用 nexus 代理仓库。
5.2.5 - Nodejs 编程语言
安装
在以下网站下载nodejs的安装包:
https://nodejs.org/en/download
按照提示进行安装即可:
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash
# in lieu of restarting the shell
\. "$HOME/.nvm/nvm.sh"
# Download and install Node.js:
nvm install 22
# Verify the Node.js version:
node -v # Should print "v22.14.0".
nvm current # Should print "v22.14.0".
# Verify npm version:
npm -v # Should print "10.9.2".
安装完成后验证:
$ node -v
v22.14.0
$ nvm current
v22.14.0
$ npm -v
10.9.2
这里用了 nvm 来进行跨平台的 node 多版本管理。
“nvm” is a cross-platform Node.js version manager
升级 npm
有时会提示 npm 有新版本,可以升级:
npm notice
npm notice New major version of npm available! 10.9.2 -> 11.3.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.3.0
npm notice To update run: npm install -g npm@11.3.0
npm notice
升级:
npm install -g npm@11.3.0
配置 npm 镜像源
查看当前默认的镜像源:
npm config get registry
输出为:
https://registry.npmjs.org/
查看 npm 镜像源的速度
安装 nrm 来测试各源的速度:
npm install -g nrm
列出可用源:
nrm ls
输出为:
npm ---------- https://registry.npmjs.org/
yarn --------- https://registry.yarnpkg.com/
tencent ------ https://mirrors.tencent.com/npm/
cnpm --------- https://r.cnpmjs.org/
taobao ------- https://registry.npmmirror.com/
npmMirror ---- https://skimdb.npmjs.com/registry/
huawei ------- https://repo.huaweicloud.com/repository/npm/
切换源(例如切换到淘宝源):
nrm use taobao
测试各源速度:
nrm test
输出为:
npm ---------- 171 ms
yarn --------- 125 ms
tencent ------ 472 ms
cnpm --------- 175 ms
taobao ------- 113 ms
npmMirror ---- 1516 ms
huawei ------- 461 ms
可以看到淘宝源的速度最快,切换过去:
nrm use taobao
此时打开文件 ~/.npmrc
:
vi ~/.npmrc
可以看到淘宝的 npm 镜像网站 registry.npmmirror.com 已经配置好了:
home=https://npmmirror.com
registry=https://r.cnpmjs.org/
备注: home 现在可以不用设置了。
配置 npm 镜像源
也可以手工修改 ~/.npmrc
文件:
vi ~/.npmrc
添加以下内容:
registry=https://r.cnpmjs.org/
配置 nexus 代理仓库
新建代理仓库
在 nexus 中新建两个 npm proxy 代理仓库:
- npm-proxy-taobao: 代理地址为 https://registry.npmmirror.com
- npm-proxy-cnpm: 代理地址为 https://r.cnpmjs.org
再新建一个名为 npm-public 的 npm group 仓库,将上面两个仓库加入其中,顺序为:
- npm-proxy-taobao
- npm-proxy-cnpm
使用代理仓库
使用代理仓库:
vi ~/.npmrc
设置为以下内容:
registry=http://192.168.3.91:8081/repository/npm-public/
验证代理
安装一些东西:
npm install --save-dev autoprefixer
npm install --save-dev postcss-cli
npm install -D postcss
然后去看 nexus 的代理仓库:
可以看到代理仓库中已经有了这些包。
5.3 - 构建模板
5.3.1.1 - 构建 basic 模板
制作过程
参考 debian12 学习笔记 的 pve 安装文档, 安装 debian 12 操作系统。
然后完成基本配置,内核配置,并通过 timeshift 进行系统备份。
模板内容
- apt 升级到 debian 12.10
- 更新 apt 到最新内核 6.1.0-34
- 安装 timeshift, zsh/ohmyzsh, git, dkms, iperf/iperf3, unzip zip curl
- 添加 proxyon/proxyoff alias for different locations
- 修复 path 不足问题,包括用户 root 和 sky
- 安装 sftp server, nfs server 和 client, samba server
5.3.1.2 - 创建虚拟机
创建虚拟机
为了加速创建,可以先将模板克隆到本地,然后从本地的模板中采用 Linked Clone 方式克隆。
这样从模板 clone 虚拟机, 速度会非常快,而且空间占用也非常小。
修改虚拟机配置
主要是修改虚拟机的 hostname,以及必要时从使用 dhcp 自动获取 ip 地址修改为使用静态 ip 地址。
5.3.2.1 - 创建模板
制作过程-v1
准备虚拟机
从模版 template-debian12-basic-v03 (取最新版本) 克隆一个虚拟机,命名为 template-debian12-dev-v01,VM ID 为 990201.
开发需要的 cpu 和内存稍大,修改虚拟机参数,cpu 修改为 8 核,内存 32g(mini 8192,memory 32768)。
准备 ssh 证书
重新生成一份 ssh 证书,这个是要提交给 github 的,单独用一份。
搭建开发环境
安装 docker
- docker/docker-compose: https://skyao.io/learning-docker/docs/installation/debian12/
- kubectl
安装开发工具
参考本读书笔记中的 开发工具 一节, 安装开发工具:
- sdkman
语言 sdk 和 nexus 私库
参考本读书笔记中的 编程语言 一节, 安装语言 sdk 和对应的 nexus 私库:
- Java: 包括 maven
- golang
- rust
- python
- nodejs
制作过程-v2
v2要放到广州南沙的开发环境, 网段是 192.168.0.0/24, devserver92 的 ip 是 192.168.0.92,因此所有相关的 ip 信息都要修改。
将 dev-v1 的模板传送到广州南沙,然后在这个基础上,按照上面制作 dev-v1 的流程,重头走一边制作流程,注意需要修改 ip 地址的地方,就可以完成 dev-v2 的制作。
5.3.2.2 - 创建实例
准备虚拟机
从模版 template-debian12-dev-vxx 克隆三个虚拟机,命名为 dev111/dev121/dev131,三个开发机备用.
开发需要的 cpu 和内存稍大,修改虚拟机参数,cpu 修改为 16核 (cpu 亲和性设置为 0-15,用大核),内存 32g (8192 MB 到 32768)。
基本配置修改
修改 hostname 和 使用静态 IP 地址。
理论上应该就可以直接拿来用了。后续如果发现有需要修改的地方,再记录下来。
5.3.3.1 - 创建模板
准备工作
准备虚拟机
从模版 template-debian12-basic-v03 (取最新版本) 克隆一个虚拟机,命名为 template-debian12-devserver-v01,VM ID 为 990301.
开发需要的 cpu 和内存稍大,修改虚拟机参数,cpu 修改为 8 核,内存 16g(mini 8192,memory 16384)。
准备磁盘
devserver 预计会有两台实例,用于两个异地的开发环境。
我为每台实例都准备了 2 块三星 pm983a 900G 的 ssd 磁盘,一块用于应用(如数据库,redis,queue等),一块用于数据(如pve需要的nfs,nexus 代理仓库等)。
在 pve 中,将两块 ssd 磁盘直通给到虚拟机,并挂载到 /mnt/data
目录。
在虚拟机中可以看到这两块磁盘:
lspci | grep Non-Volatile
01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983
02:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD Controller SM981/PM981/PM983
参考本读书笔记中的 devserver91 一节, 配置好磁盘并进行分区,然后安装 nfs server。
搭建开发环境
安装 docker 和 habor
- docker/docker-compose: https://skyao.io/learning-docker/docs/installation/debian12/
- habor: https://skyao.io/learning-docker/docs/repository/habor/
安装开发工具
参考本读书笔记中的 开发工具 一节, 安装开发工具:
- sdkman
- nexus
语言 sdk 和 nexus 私库
参考本读书笔记中的 编程语言 一节, 安装语言 sdk 和对应的 nexus 私库:
- Java: 包括 maven
- golang
- rust
- python
- nodejs
5.3.3.2 - 创建虚拟机
创建虚拟机
devserver 模板实际只会有两个虚拟机实例:
- devserver91: ip 192.168.3.91, 用于苏州汾湖的开发环境
- devserver92: ip 192.168.0.92, 用于广州南沙的开发环境
由于两个虚拟机都使用到直通的两块 900g 三星 pm983a ssd,因此无法简单的从模板克隆就能自动恢复所有的数据。
实践中,先按照 devserver91 的配置搭建好虚拟机,然后直接使用直通的 ssd 就能正常工作了。
devserver92 是将模板(去除直通的两块 ssd)传送到广州南沙,然后从模板克隆虚拟机,再直通两块空的 ssd 硬盘。
配置 devserver91
几乎不需要配置。
配置 devserver92
原则上需要按照搭建模板的方式, 重头走一遍所有流程来完成 devserver92 的配置。
中间很多步骤是可以重用之前已有的资料和信息,但是需要检查每一个步骤,看是否有需要改动的地方,最重要的改动就是这个机器的 ip 地址从 devserver91 的 192.168.3.91 修改为 devserver92 的 192.168.0.92。
而这个 ip 地址的修改,散落在很多地方, 为了不疏漏,只能重新走一遍完成的流程,好在大部分操作都还继续有效,只是修改个别配置文件更改 ip 地址即可。