FreeBSD Jails
uWSGI 1.9.16引入了原生的FreeBSD jails支持。
FreeBSD jails可以被看成新一代的chroot(),能够细粒度调整“jail”可以访问的东西。
即使在更高一点的级别上,它们都非常类似于Linux的名字空间 (从API的角度来看)。
自FreeBSD 4起,jails就可用了
为什么用uWSGI管理jails?
一般来说,jails是用系统工具“jail”及其实用程序管理的。
时至今日,在FreeBSD jails中运行uWSGI是非常常见的,但是对于真正大规模的设置 (即,托管业务),其中,Emperor (比方说) 管理数百个无关的uWSGI实例,设置真真会磨死人。
在uWSGI配置文件中直接管理jails极大降低了系统管理员成本,并且帮助更好的组织整个基础设施。
老式的jails (FreeBSD < 8)
FreeBSD公开了2个主要的API,用于管理jails。老的(更早的)那个是基于jail()函数的。
它自FreeBSD 4起可用,并且允许你设置rootfs、主机名和一个或多个ipv4/ipv6地址。
在一个jail中运行一个uWSGI实例需要2个选项:–jail和–jail-ip4/–jail-ip6 (实际上是3个,如果你使用IPv6的话)
—jail <rootfs> [hostname] [jailname]
—jail-ip4 <address>
(can be specified multiple times)
—jail-ip6 <address>
(can be specified multiple times)
显示如何为你的jail创建rootfs并非本文档的目的,但是就我个人而言,我讨厌从源代码重新构建,因此一般而言,我只是从官方库搞到base.tgz文件,并且chroot()到它那里,以进行微调。
一个你必须记得的事情是,附加到jail的ip地址必须在系统中可用(作为别名)。与往常一样,我们往往滥用uWSGI设施。在我们的例子中,–exec-pre-jail hook将会获得成功
- [uwsgi]
- ; create the jail with /jails/001 as rootfs and 'foobar' as hostname
- jail = /jails/001 foobar
- ; create the alias on 'em0'
- exec-pre-jail = ifconfig em0 192.168.0.40 alias
- ; attach the alias to the jail
- jail-ip4 = 192.168.0.40
- ; bind the http-socket (we are now in the jail)
- http-socket = 192.168.0.40:8080
- ; load the application (remember we are in the jail)
- wsgi-file = myapp.wsgi
- ; drop privileges
- uid = kratos
- gid = kratos
- ; common options
- master = true
- processes = 2
新式的jails (FreeBSD >= 8)
FreeBSD 8引入了一个用于管理jails的新的高级的api。基于jail_set()系统调用,libjail公开了几十个功能,并且允许jails的微调。要使用这个新的api,你需要–jail2选项 (别名为–libjail)
—jail2 <key>[=value]
每个–jail2选项都和一个jail属性1:1映射,因此你基本可以调整一切!
- [uwsgi]
- ; create the jail with /jails/001 as rootfs
- jail2 = path=/jails/001
- ; set hostname to 'foobar'
- jail2 = host.hostname=foobar
- ; create the alias on 'em0'
- exec-pre-jail = ifconfig em0 192.168.0.40 alias
- ; attach the alias to the jail
- jail2 = ip4.addr=192.168.0.40
- ; bind the http-socket (we are now in the jail)
- http-socket = 192.168.0.40:8080
- ; load the application (remember we are in the jail)
- wsgi-file = myapp.wsgi
- ; drop privileges
- uid = kratos
- gid = kratos
- ; common options
- master = true
- processes = 2
关于FreeBSD >= 8.4 但是 < 9.0 的注意事项
uWSGI在FreeBSD < 9上使用ipc信号量 (较新的FreeBSD发行版支持POSIX信号量)。
从FreeBSD 8.4起,你需要明确在jails中允许sysvipc。因此,确保这样
- [uwsgi]
- ...
- jail2 = allow.sysvipc=1
- ...
DevFS
DevFS虚拟文件系统管理FreeBSD上的/dev目录。
/dev文件系统并没有挂载在jail中,但是出于数以百计的原因,你可能需要它。
有两个可用的主要方法:在创建jail之前,将其挂载在roots的/dev/目录中,或者允许jail挂载它
- [uwsgi]
- ; avoid re-mounting the file system every time
- if-not-exists = /jails/001/dev/zero
- exec-pre-jail = mount -t devfs devfs /jails/001/dev
- endif =
- ; create the jail with /jails/001 as rootfs
- jail2 = path=/jails/001
- ; set hostname to 'foobar'
- jail2 = host.hostname=foobar
- ; create the alias on 'em0'
- exec-pre-jail = ifconfig em0 192.168.0.40 alias
- ; attach the alias to the jail
- jail2 = ip4.addr=192.168.0.40
- ; bind the http-socket (we are now in the jail)
- http-socket = 192.168.0.40:8080
- ; load the application (remember we are in the jail)
- wsgi-file = myapp.wsgi
- ; drop privileges
- uid = kratos
- gid = kratos
- ; common options
- master = true
- processes = 2
或者 (允许jail自身挂载它)
- [uwsgi]
- ; create the jail with /jails/001 as rootfs
- jail2 = path=/jails/001
- ; set hostname to 'foobar'
- jail2 = host.hostname=foobar
- ; create the alias on 'em0'
- exec-pre-jail = ifconfig em0 192.168.0.40 alias
- ; attach the alias to the jail
- jail2 = ip4.addr=192.168.0.40
- ; allows mount of devfs in the jail
- jail2 = enforce_statfs=1
- jail2 = allow.mount
- jail2 = allow.mount.devfs
- ; ... and mount it
- if-not-exists = /dev/zero
- exec-post-jail = mount -t devfs devfs /dev
- endif =
- ; bind the http-socket (we are now in the jail)
- http-socket = 192.168.0.40:8080
- ; load the application (remember we are in the jail)
- wsgi-file = myapp.wsgi
- ; drop privileges
- uid = kratos
- gid = kratos
- ; common options
- master = true
- processes = 2
重载
重载(或者二进制补丁)的管理有点烦人,因为uWSGI需要重新执行自身,所以在你的jail中,需要一个二进制文件、插件和配置文件的拷贝 (除非你可以牺牲掉优雅重载和简单指定Emperor来重新生成实例)
另一个方法是 (就和devfs一样) 在jail自身中,使用uwsgi二进制文件(和最终插件)挂载该目录,并且使用–binary-path来指示uWSGI使用这个新的路径
jid文件
每个jail可以由一个唯一的名字 (可选的) 或者它的”jid”应用。这类似于一个”pid”,因为你可以用它来发送命令(和更新)到一个已经运行的jail。–jidfile <file>选项允许你存储jid到一个文件中,用于和外部应用使用。
附加到一个jail
你可以使用–jail-attach <id>将uWSGI实例附加到已经运行的jails(也可以是标准的持久化jail)上
id参数可以是jid或者jail的名字。
这个特性需要FreeBSD 8
Debian/kFreeBSD
这是一个官方Debian项目,旨在构建一个带有FreeBSD内核和常见Debian用户空间的操作系统。
它工作良好,也支持jail。
让我们用debootstrap创建一个jail
- debootstrap wheezy /jails/wheezy
添加一个网络别名
- ifconfig em0 192.168.173.105 netmask 255.255.255.0 alias
(将em0改为你的网络接口名)
然后运行它
- uwsgi --http-socket 192.168.173.105:8080 --jail /jails/wheezy -jail-ip4 192.168.173.105
使用Forkpty Router的Jails
你可以使用 Forkpty路由器 轻松附加到FreeBSD jails
只是记得将/dev (嗯,/dev/ptmx) 挂载到你的jail,以允许forkpty()调用
学习如何处理devfs_ruleset以增加你的devfs的安全性
注意事项
当jail中运行的最后一个进程死掉的时候,会销毁这个jail
默认情况下,所有挂载在rootfs(在进入jail之前)的东东将对jail自身可见 (前面在处理devfs的时候,我们已经看到了)