使用UML合租VPS

使用UML合租VPS

13 March 2016 Linux Tech UML

我是从 微林 那里发现阿里云的新加坡节点的。那个时候我在用 Conoha,因为它到国内的线路越来越玄学,从以前的70ms延迟飙升到300ms,丢包率极高,所以我到微林那里去寻求一个中转服务。我本来只想用那个阿里云香港节点,但是正好看见不知何时他们加上了一个阿里云新加坡节点。因为香港的流量费实在太可怕,我就抱着试试看的心态开了一个新加坡的中转。谁知道这个中转的效果非常好,因为这个新加坡节点到中国电信有双向的CN2线路连接。然而微林的流量费还是太高:阿里云的官方流量价格只有0.53元/GiB,而最低配置的主机价格也就90元的样子。使用微林中转,我仍然需要一个国外VPS来搭建网站,倒不如直接使用阿里云提供的服务……

合租

然而,对于我这个学生党来说,94元/月的配置费仍然是高了一些。所以我想到了合租,几个人可以稍微分担一下配置费用。然而要合租的话,就需要想办法分割各自的用户空间。我首先想到的是用 LXC 或者 systemd-nspawn, 但是使用这些的话,各个用户都必须共享同一个内核。而阿里云这东西比较奇葩的是不允许自定义内核,这样总让我觉得有些不舒服。

在虚拟机里再跑全虚拟化的虚拟机显然是不合适的。而我以前也在 HawkHostOpenVZ VPS 上使用过 User Mode Linux,显然,这是个比较好的解决方案。

于是我找了两个朋友, ToukoBroncoTc,共同使用一台阿里云新加坡VPS。正好,之前我那篇关于UML的文章被我删除了,我也就可以用这篇补上这个空白了。

User Mode Linux

于是首先应该配置好 User Mode Linux, 简称 UML

User Mode Linux 是一个对Linux内核到其自身的适配。它可以将一个 Linux 运行在用户空间,同时却具有几乎全部内核支持的功能,包括但不限于自己的文件系统、自己的TCP/IP协议栈。当使用 OpenVZ 这类的VPS,需要自己挂载文件系统或使用 Tunnelbroker 一类的东西的时候,UML就十分有用了。而阿里云也不让自己换内核,即使不用和其他人合租,UML也是十分有用的东西。

因为偷懒,我在 ArchLinux AUR 上找到了一个UML的 PKGBUILD,从里面拿出了内核配置文件,打算直接使用。然而,这个内核配置文件存在一些问题,比如说关于 Netfilter (iptables) 的内核配置全部没有打开,文件系统的支持也不是很完全。所以,我们得手工编辑这个配置文件,打开需要的选项。当然,使用内核自带的图形化配置工具,也是可以的。

我在 kernel.org 上选择了最新的LTS版本 4.1.19,下载下来,解包,然后把那个改好的配置文件放了进去。然后,直接执行

make ARCH=um vmlinux

就可以获得一个名为 vmlinux 的可执行文件,这就是 User Mode Linux 的可执行文件了。

Bootstrap

然而,在使用UML之前,我们还必须先为UML配置一份自己的用户空间,即为UML虚拟出来的环境安装一个发行版。

由于UML可以从文件内的文件系统镜像启动,所以我创建了一些文件作为 虚拟磁盘 使用

fallocate -l 10G image
mkfs.xfs image

接下来就得把它挂载到一个临时挂载点

mount image /mnt
cd /mnt

以安装 ArchLinux 为例,首先得下载它的 bootstrap 压缩包然后解压。对应的bootstrap包可以在各大 ArchLinux 镜像里面找到,往往和 ISO 文件放在一起,如 http://mirror.rackspace.com/archlinux/iso/2016.03.01/archlinux-bootstrap-2016.03.01-i686.tar.gz

tar zxvf bootstrap_file.tar.gz
mv root.x86_64/* ./

如果要使用 Debian, 则上述过程都可以通过 debootstrap 脚本来完成,只要指定目标目录是挂载出来的 /mnt 即可。

此时需要将必须目录映射进挂载出来的磁盘

mount --rbind /dev /mnt/dev
mount --rbind /sys /mnt/sys
mount --rbind /proc /mnt/proc
mount --rbind /tmp /mnt/tmp

然后执行更新软件包之类的操作。接着需要配置好root密码、配置好locale等。在编辑 fstab 时,请注意,根磁盘应该是 /dev/ubda,这将在稍后的UML启动命令行中体现。

这里有一个大坑:千万不要在UML内系统的fstab里添加swapfile! 这会导致 udev 在启动时卡死。如果一定要用swap,请写一个开机启动的服务来启用。

Networking

UML的网络配置也是一个坑。要对UML启用网络,我们必须使用 tap 设备。例如,我们可以创建一个 tap0:

ip tuntap add tap0 mode tap
ip addr add 192.168.1.1/24 dev tap0
ip link set tap0 up

注意,在阿里云上,只有 192.168.0.0/16 这个内网网段是可用的。这里我们把主机IP设为 192.168.1.1, 假设我们将把UML客户机的IP设为 192.168.1.2

稍后启动UML时,我们将通过这个参数(假设MAC地址设为23:33:33:44:66:66)

eth0=tuntap,tap0,23:33:33:44:66:66,192.168.1.2

来将网络设备映射到UML内部。

为了使UML能访问网络,我们得添加 MASQUERADE 规则。在阿里云上,公网设备是 eth1

iptables -t nat -A POSTROURING -o eth1 -j MASQUERADE

我们还需要映射一定范围的端口到UML内部,以便外网访问。

iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 10000:20000 -j DNAT --to-destination 192.168.1.2

UDP也同理。请记得把UML内部的 sshd 监听的端口改到这个范围之内!

对于 80443 端口,如果只有一个人使用,那么把它映射进UML是没有问题的。如果要多人使用,那就只能依靠主机 haproxy,按照域名来区分了。这要参考 haproxy 的SNI配置,我不再赘述。有一个小小的Tip,那就是在 haproxy 配置中可以使用 hdr_end-m end 指令匹配域名尾部以达到泛域名匹配的效果。

建议将这些网络设备的启动脚本加入主机的启动服务。在UML中,只需要配置 eth0 上的网络,把网关设为 192.168.1.1 就可以了。

[Match]
Name=eth0

[Network]
Address=192.168.1.2/24
Gateway=192.168.1.1

这是 systemd-networkd 的配置。

Boot up

现在已经可以启动UML了。首先我们需要把刚刚挂载出来的目录全部卸载,这一步推荐通过重启完成。然后可以启动

/path/to/vmlinux ubd0=/path/to/image eth0=tuntap,tap0,23:33:33:44:66:66,192.168.1.2 mem=512m con=pts

内存被限制在了 512m。如果你的UML中运行了 sshd, 那么你已经可以用暴露的端口访问内部运行的系统了。如果出现问题,你也可以直接通过 screen /dev/pts/X (X是一个数字,自行ls查看) 来获得一个客户机的 Login shell

当然,我比较推荐的是把这些过程全部写成一个脚本,并且让它能够读取配置文件,这样再将它包装成一个 systemd 服务,就可以方便地管理多用户和开机启动了。

流量监控

在多人共享阿里云时,流量是个大问题,因为阿里云按照流量计费。因而,我们需要一个好用的流量统计工具。

我看中的是 vnstat, 因为它可以单独统计每个网络接口的流量。而UML的每个实例又单独享有一个 tap 接口,这就使流量统计非常方便了。

在CentOS上安装和启用非常简单

yum install vnstat
systemctl start vnstat
systemctl enable vnstat

过一段时间以后,使用 vnstat -q 即可查看统计数据。当然,为了方便其他用户查看,我还利用 bashttpd 搭建了一个服务器,调用 vnstat -q -i tapN 来返回各个接口的统计数据。这十分方便。

bashttpd.conf 中只需要这几行

serve_vnstat() {
    add_response_header "Content-Type" "text/plain"
    send_response_ok_exit <<< "$(vnstat -q -i tap$2)"
}
on_uri_match '^/tap([0-9])$' serve_vnstat

然后按照官方文档使用 socat 启动服务,即可在 YOUR_URL/tapN 访问到对应设备的流量统计。

后记

虽然我们总不太喜欢BAT这类公司,但是阿里云新加坡的这个线路是真的很良心,在价格比较低的同时拥有货真价实的双向CN2,在中国国内的速度十分可观,尤其是电信。对于很多地方的联通,速度也在能够接受的范围之内。而移动,自然是不用说了。

使用UML,不仅仅可以分担费用,还有一定的防止 云盾 抽风的能力,因为云盾目前并不能透过UML控制其内部的环境。虽然并不是说有多安全,至少不会发生云盾炸掉整个环境的糗事。就目前的配置来看,即使外面环境挂了,只要UML进程还在运行,就不会出现任何严重问题。