OpenVZ 通过 User-Mode Linux 来安装 BBR

watch-dogs-2013821151855_106b80f.jpg

起源

今天 Ovear 突然想起来,好像很久没有更新博客了,然后打开博客一看。卧槽,上一篇博客已经是半年多一年更新的了,说好的月更也没有做到(:з」∠),还欠了几篇的。吓得 Ovear 懒癌立马退散,赶紧继续更一篇 CDN 系列压压惊。

没错 Ovear 还是管不住自己的手,又剁了台大硬盘 VPS ,可惜是 OpenVZ 的。Ovear 已经特意避开 OpenVZ 的 VPS 好久了,超兽还是其次,主要是自定义空间太小了,完全没办法自己装内核啥的。只能跟母鸡用一个内核,连 swap 和 mount 都不能自由做到。所以 Ovear

一般是不怎么喜欢买啦,但是这次的价格真心棒,忍不住就入了。入了之后,果然线路和性能都不咋地,但是硬盘大啊!鉴于我们大天朝的原因,出国速度想快一点,就只能上无脑 KCPTUN 锐速 BBR 之类的。但是 KCPTUN 的自适应性太差了,正好看见有菊苣在折腾 UML, 刚好就可以在 OpenVZ 上跑 BBR。所以也就学了学,写了这一篇文章。

安装必要工具

在这里先说下,Ovear是被坑惨了,一开始用的 CentOS6 来编译内核,但是死活不通过,简直伤心。还不容易找了台 Ubuntu 编译过了,然后发现那个模板对 iptables nat 支持有问题。只好又换回 Ubuntu 了。理论上 CentOS 应该也是没问题的,所以下面的步骤可能会出现 CentOS 和 Ubuntu 一起的情况,也有可能只有 Ubuntu。

首先安装必须的工具

Centos

yum groupinstall “Development tools”

Ubuntu

apt-get install build-essential libncurses5-dev

编译适合 UML 的内核

因为 BBR 加入 Linux Kernel 分支的时间较短,各大发行版还没有这么激进(Arch之类的除外),所以如果要开启 BBR 一般都要自行编译内核。
具体步骤如下

wget
https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/snapshot/net-next-4.11.tar.gz #这一步可能因为 kernel git 服务器的问题,会卡很久,请耐心等待
tar xvf net-next-4.11.tar.gz
cd net-next-4.11.tar.gz
make defconfig ARCH=um

根据 amayume 菊苣的提醒,也可以直接设置环境变量 export ARCH=um

然后最重要的一步来了,开启 BBR 的内核嵌入

make menuconfig ARCH=um

使用上面的命令,进入图形化的内核配置界面

选择 Networking support -> Networking options -> 找到 TCP: advanced congestion control 按空格让这个选项变为√
然后找到 BBR TCP,按 Y 设置为默认载入内核,然后前面的符号会变成 <*> BBR TCP。再找到下方 Default TCP congestion control 回车选 BBR。然后通过下面的Save,或者Exit到最后,然后保存都可以。

然后使用

make ARCH=um vmlinux

编译内核

注:这里不知道为什么 Ovear 在 CentOS 下无法编译成功,需要使用 Debian 系才能编译。不是很清楚原因,试了几台 CentOS 都这样。希望有知道原因的菊苣告诉下 Ovear 解决方法。

HOSTCC scripts/unifdef
CC arch/x86/um/user-offsets.s
arch/x86/um/user-offsets.c: In function ‘foo’:
arch/x86/um/user-offsets.c:53: error: invalid application of ‘sizeof’ to incomplete type ‘struct _xstate’
make[1]: *** [arch/x86/um/user-offsets.s] Error 1
make: *** [arch/x86/um/user-offsets.s] Error 2

在 UML 中安装 Arch Linux

因为 Ovear 对 Linux 的最小系统(rootfs)了解不够深刻,所以在这里就直接安装完整的系统了。(也不知道怎么安装 Ubuntu 之类的其他系统)
安装方法参考 amayume 菊苣(略有修改)

# 先下载 Arch 最新的 Bootstrap 包:
wget http://mirror.rackspace.com/archlinux/iso/latest/archlinux-bootstrap-2017.05.01-x86_64.tar.gz
tar xzf archlinux-bootstrap-2017.05.01-x86_64.tar.gz
mv root.x86_64 root
sudo nano root/etc/resolv.conf
# 加上一行 nameserver 8.8.8.8,保存
sudo mount –rbind /proc root/proc
sudo mount –rbind /sys root/sys
sudo mount –rbind /dev root/dev
sudo mount -t tmpfs tmpfs root/tmp
sudo mount –rbind /root root/root
sudo nano root/etc/pacman.d/mirrorlist
# 搜索离你最近的国家镜像,去掉对应的注释
# 进入 chroot
sudo root/bin/arch-chroot root /bin/bash
# 此时已经进入 chroot 环境
pacman-key –init
pacman-key –populate archlinux
# 安装基础系统
pacman -Sy base

改控制台,也可以不改,通过 screen 连接 pts

systemctl enable getty@tty0
systemctl disable getty@tty1
# 退出 chroot
\exit
# 解除 rbind
sudo umount root/{dev,proc,sys,tmp}

这时候就有完整的 rootfs 了,可以直接指定来启动 UML。

###遇到的坑
如果使用 Ubuntu 14.04 及其以下版本,在 arch-chroot 时可能会遇到如下错误提示

unshare: unrecognized option ‘–fork’

这是因为 Ubuntu 14.04 unshare 版本太低,可以按照如下步骤解决
方法来自:https://askubuntu.com/questions/586153/how-to-update-unshare-package-unrecognized-option-fork

apt-get install software-properties-common
add-apt-repository ppa:xeron-oskom/util-linux
apt-get update
apt-get install util-linux

之后应该就没问题了。

设置 NAT 网络

注意: 设置之前请确保 TUN/TAP 已经开启,如没有开启,请联系 VPS 提供商。

首先先测试下,iptables 的 nat 模块是否能用

iptables -t nat -L

如果出现类似如下内容

Chain PREROUTING (policy ACCEPT)
target prot opt source destination

Chain POSTROUTING (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination

则说明没有问题

如果出现下面这种情况,那就需要联系 VPS 提供商处理了

iptables v1.4.21: can’t initialize iptables table `nat’: Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded

之后就是设置 tap 设备了

tunctl -t tap0 #创建 bridge
ip addr add 10.0.0.1/24 dev tap0 #给 bridge 设置 ip
ip route add default via 10.0.0.1 dev venet0:0
ip link set tap0 up
iptables -P FORWARD ACCEPT #允许 nat 转发
iptables -t nat -A POSTROUTING -o venet0 -j MASQUERADE

启动 UML

配置这样就大概成功啦,接下来就是启动虚拟机的时候啦~
由于 OpenVZ 没有 loop 设备,所以是没有办法使用 mount 命令来 mount img 修改的,所以在这里就直接使用了一种较为投机取巧的方法,叫做 hostfs,但是 hostfs 会有一些问题,可能导致程序无法正确运行,这一点放在下一章再讲啦 →_→
当然有些童鞋可能说,hostfs 听说不是只能只读模式么?那不就不能修改内容了,其实不是的,这是跟内核的启动参数有关,加入了之后就可以读写了。

首先找到之前编译内核的目录,然后把 vmlinux 拷贝到自己需要的地方,当然也可以直接在当前目录运行。
然后执行如下命令

./vmlinux uumid=archlinux rw root=/dev/root rootfstype=hostfs hostfs=刚才解压archlinux的地址 eth0=tuntap,tap0 mem=256m

在这里:mem 参数是内存大小,可以自行修改
hostfs 是要启动的系统的根目录地址,这里就是我们刚刚解压的 arch 啦

然后就可以看到像是我们电脑开机一样的启动界面,然后就可以登录操作啦

##配置虚拟机网络
这里根据不同的系统,也有几率不同啦。Arch的话根据官方文档大概是以下步骤
/etc/systemd/network/25-wired.network 内加入以下内容

[Match]
Name=eth0

[Network]
Address=10.0.0.2/24
Gateway=10.0.0.1

然后执行

systemctl enable systemd-networkd
systemctl start systemd-networkd

然后尝试 ping 8.8.8.8
如果能成功 ping 通就说明网络没问题啦~
虚拟机就可以正常使用了。

##映射端口
这时候有的童鞋就问了,那这个 UML 虚拟机没有公网 IP,怎么在外部进行管理呢?这其实用 iptables 自带的 nat 功能,就可以实现类似路由的端口映射啦~

iptables -t nat -A PREROUTING -i venet0 -p tcp –dport 公网端口 -j DNAT –to-destination 10.0.0.2:虚拟机的端口

10.0.0.2 是虚拟机的IP,请根据自己的情况修改

常见问题 & 遇到的坑

1、我要后台运行虚拟机怎么办呀?

这个其实有两种方式解决,第一种使用 screen -S 命令,丢在 screen 里面运行
这种方式特别简单粗暴,非常好用,也容易管理。 Ovear 个人推荐这种方法。
第二种方式,结合 nohup + & 实现,这种方式坑比较多, Ovear 被坑了好久

nohup ./vmlinux uumid=archlinux rw root=/dev/root rootfstype=hostfs hostfs=./root con=pts eth0=tuntap,tap0 mem=256m &

在这里 Ovear 遇到的坑就是 UML 和 nohup 的 IO 冲突的问题,如果不使用 con=pts 参数, 虚拟机可能就会无法启动,Ovear 在这里猜想是因为 nohup 的 IO redirect 跟 UML 的兼容性有问题,使用了这个参数之后,输出流就会走 pts,也就不会产生这个 bug 了。

2、为啥我一重启 iptables 就没了呀?

这个其实是因为你没有保存 iptables 的问题,加一个开机脚本,自动执行一次就好啦。
当然也有系统相关的保存放
如果使用的是 CentOS 系,设置完 iptables 之后,直接执行 server iptabeles save就可以保存了。
如果是 Debian 系,需要安装一个叫做 iptables-persistent 的软件

apt-get install iptables-persistent

然后设置完 iptables 之后执行 service iptables-persistent save 就可以啦

3、我要开机全自动开启 UML 怎么办?

其实这个有一个简单的方法,直接开机启动 screen 就好了。这里 Ovear 同样是强烈推荐这种方法,另外一种 Ovear 也是遇到了一堆坑。
第二种方法是使用脚本启动的方法,因为开机运行系统脚本,很多环境变量之类的没初始化好,所以坑了很久。
首先因为 bridge 是一重启就消失的,所以开机首先要初始化 bridge
创建一个 init_bridge.sh 的文件

#!/bin/sh
tunctl -t tap0
ip addr add 10.0.0.1/24 dev tap0
ip route add default via 10.0.0.1 dev venet0:0
ip link set tap0 up

然后使用 chmod +x init_bridge.sh 设置可执行标志
然后创建一个 start_uml.sh 的文件,这个文件参考于 zohead 菊苣

#!/bin/sh
UML_ID=”archlinux”
TAP_DEV=”tap0″
DIR=”/root/linux_uml”

echo 1 > /proc/sys/net/ipv4/ip_forward
nohup \$DIR/vmlinux uumid=archlinux uml_dir=\$DIR/.uml rw root=/dev/root rootfstype=hostfs hostfs=\$DIR/root con=pts eth0=tuntap,\$TAP_DEV mem=256m > /root/uml_log 2>&1 &

然后同样使用 **chmod +x start_uml.sh 设置可执行标志

在这里,主要是需要增加一个 uml_dir 设置,因为 uml 也会在 \$home 目录下写入一些临时文件,但是系统开机的时候,并没有这个环境变量,在这里手动指定就可以了。

/etc/rc.local 文件插入

/root/linux_uml/init_bridge.sh
/root/linux_uml/start_uml.sh

就可以实现开机启动了,记得在 exit 0 之前插入。

参考文章

https://blog.amayume.net/openvz-vps-an-zhuang-user-mode-linux-yi-shi-xian-bbr-yong-sai-kong-zhi/
https://zohead.com/archives/openvz-uml-bbr/

PM: 下一章(如果有的话)更新在 ArchLinux 中配置遇到的坑 →_→

OpenVZ 通过 User-Mode Linux 来安装 BBR 没有评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注