Linux container hand-crafted

本文介绍如何使用 LVM 快速部署 Ubuntu 测试环境,并通过 veth 实现网络隔离,支持 web 服务及 fastcgi 的独立测试。同时探讨了 cgroups 资源限制、upstart 启动问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目标:

快速建立环境用语测试 deb 包安装 / web 应用部署。

可参考 https://github.com/wolf0403/lvmvm 的 README 


基础环境:

Ubuntu Natty (11.04) server. 


文件系统:

测试环境的快速部署依赖 LVM (Logical Volume Management) 。安装宿主系统方法不限,留足够硬盘创建单一分区,如 /dev/sda5 。

将此分区创建为 LVM 物理卷

pvcreate /dev/sda5

在此分区之上创建 LVM 组

vgcreate data /dev/sda5

创建逻辑分区

lvcreate -n natty /dev/data -L2G

创建 文件系统

mkfs.ext4 /dev/data/natty
创建挂载点并挂载
mkdir /mnt/natty
mount /dev/data/natty /mnt/natty




创建测试环境

debootstrap natty /mnt/natty

完成之后的 /mnt/natty 为一个最基础的 Ubuntu Natty 环境(debootstrap 中可以指定其他版本,如 oneiric 等。将 /mnt/natty 卸载作为范本。

umount /mnt/natty

可以压缩分区以节约磁盘空间:将文件系统减到最小

resize2fs -M /dev/data/natty # 会要求先执行 e2fsck -f /dev/data/natty 等

然后根据文件系统大小相应压缩逻辑卷。$NEW_SIZE 为上一条操作执行后文件系统的大小;应该留有适当余地,否则可能损坏文件系统。或使用 -r 参数。

lvresize -L  $NEW_SIZE /dev/data/natty


创建新测试环境

使用 LVM 的 snapshot 功能创建测试环境:

NEWSIZE=`lvdisplay /dev/data/natty | grep 'Current LE' | egrep -o '[[:digit:]]+'`
VOL=snap1
lvcreate -s /dev/data/natty -n $VOL -l$NEWSIZE
mkdir /mnt/$VOL
mount /dev/data/$VOL /mnt/$VOL
export MP=/mnt/$VOL
touch $MP/chroot.$VOL # 盗梦的陀螺
mount --bind /dev $MP/dev
mount none $MP/dev/pts -t devpts
mount --bind /proc $MP/proc
mount --bind /sys $MP/sys
chroot /mnt/$VOL


网络


此时创建的测试环境虽然文件系统独立,但其他均为共享。如果同时创建多个环境运行网络服务(如 web server 或 fastcgi 等)则可能出现端口冲突。解决方法是通过 veth 给每个环境分配独立的网络。

参考:http://lxc.sourceforge.net/index.php/about/kernel-namespaces/network/configuration/

攻略:

宿主环境打开路由和 arp 代理

 echo 1 > /proc/sys/net/ipv4/ip_forward
 echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp
创建虚拟网卡对
ip link add type veth
为网卡对的主机端指定地址。不应与 ethX 冲突

ifconfig veth0 192.168.3.101/24 up
为虚拟网卡打开 arp 转发

echo 1 > /proc/sys/net/ipv4/conf/veth0/proxy_arp
为虚拟网卡对端指定路由(这里 192.168.3.102 是虚拟环境使用的 IP 地址)

route add -host 192.168.3.102 dev veth0

另开一个会话,chroot 进入虚拟环境。用 unshare 命令隔离与宿主的网络空间

unshare -mun chroot /mnt/$VOL

这时执行 ifconfig 应该看不见网卡,ifconfig lo0 可以看见 loopback 网卡,但是没有 IP 地址。在这个 shell 执行

echo $$

得到 PID


在第一个会话中(宿主环境)执行

ip link set veth1 netns $PID
将 veth1 划入虚拟环境


在虚拟环境 chroot shell 中 ifconfig 应该可以看到 veth1 。将 veth1 的地址指定为前述(路由指向的)IP 地址

ifconfig veth1 192.168.3.102


在虚拟环境中测试监听

nc -vv -l 10888

在主机中测试

nc -vv localhost 10888 

失败,但

nc -vv 192.168.2.102 10888

成功,说明网络隔离室成功的。


CPU、内存资源

测试利用 cgroups 限定可用内存和 CPU

通过 cgcreate -g memory:Name 创建分组,然后在 /sys/fs/cgroup/memory/Name/memory.limit_in_bytes 中进行设置,如 echo 10M > memory.limit_in_bytes 等。

FIXME: 通过 for (;;) malloc (1024 * 1024) 并未测得相应的结果,内存增长(top 中 VIRT / RES / SHR)与实际占用( /sys/fs/cgroup/Name/memory.usage_in_bytes)并不对应。


问题

Ubuntu 虚拟环境中 MySQL 等脚本无法执行

Ubuntu 8.04 之后的系统启动脚本由 Sysvinit 替换成了 Upstart。Sysvinit 是一组简单的 shell 脚本,由 /sbin/init 创建进程并独立执行,因此相对简单。Ubuntu 使用的 upstart 系统( http://upstart.ubuntu.com )依赖 dbus 通信,因此脚本的执行依赖于 /sbin/init 的执行。而 Ubuntu 的 /sbni/init 又强制要求自己的 PID 为 1,否则直接退出。因为以上的 unshare 命令目前只能处理网络、System V IPC 等名字空间,但是空间仍然是共用的,无法在虚拟环境中正常执行 /sbin/init。

解决方法 1:对于依赖 upstart 的服务,手工启动(如手工执行 mysqld 等)
解决方法 2:利用 LD_PRELOAD 劫持 getpid 返回 1 强制启动虚拟环境的 /sbin/init (http://blog.youkuaiyun.com/Wolf0403/article/details/389276)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

pid_t getpid (void) {
  char *pidstr = getenv ("HJPID");
  if (pidstr && pidstr[0] == '1' && pidstr[1] == '\0') {
    return (pid_t) 1;
  }
  void *dlh = dlopen ("libc.so.6", RTLD_LAZY);
  if ( !dlh ) {
    exit (1);
  }

  pid_t (* glibc_getpid) ();
  glibc_getpid = dlsym ( dlh, "getpid" );
  if ( ! glibc_getpid ) {
    exit (2);
  }

  pid_t r = glibc_getpid ();

  dlclose ( dlh );
  return r;
}

编译 
cc -shared -fPIC getpid.c -o libpid.so -ldl

然后用 env LD_PRELOAD=libpid.so HJPID=1 方式插入 /sbin/init 这样可以启动 /sbin/init,但是 MySQL 启动仍然有问题。FIXME

整理

目前测试成功的是在虚拟环境中执行 nginx / php-fcgi,MySQL 可以在 chroot 中执行
关于 PID namespace 的问题,Linux 的 clone(2) 系统调用提供了新的 CLONE_NEWPID 参数用于隔离 PID 名称空间。http://linux.die.net/man/2/clone 可以尝试整合到 unshare 中(TODO)。

资源

Upstart /sbin/init PID = 1: http://linux-vserver.org/Upstart_issues
Linux unshare(1) 命令:http://linux.die.net/man/1/unshare


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值