开始和停止jail是你最不需要的问题。您必须能够在jail内运行命令,控制jail的环境和jail内运行的命令环境,配置启动序列,并安装软件。
说到系统管理,iocage是 jail(8)
的前端。无论你如何管理jail,你都必须了解jail的核心功能。我们将介绍使用内置系统工具控制jail,然后使用iocage讨论相同的任务。
第三章:Jail管理启动和关机启动和jail(8)
启动和Iocage调整启动和关闭启动前调整死亡与死后的生命用户和 Jail 命令Jail 调试调试标准 Jails调试iocage JialsJail 返回代码Jail启动顺序标准Jail启动顺序Iocage 启动顺序查看 Jails查看参数其他输出格式查看Iocage Jails流程管理Jailing 命令Jailed过程环境控制台访问控制台日志
主机将每个jail视为一个独立的服务,就像网络服务器或数据库一样。每个jail都运行自己的进程,但从主机的角度来看,jail是一个包含大量进程和内存的单一自我管理实体。host只负责启动和停止jail,并否认管理jail流程的责任。
每个jail都必须启动和停止自己的程序。
jail(8)
使用 service(8)
启动、停止和重新启动jail。我使用jail.conf配置了两个jail:loghost和logdb。
xxxxxxxxxx
# service jail restart
Stopping jails: loghost logdb ioc-www2.
Starting jails: loghost logdb.
我在jail.conf中配置了两个jail;ioc-www2是从哪里来的?那是一个jail。我已经有一个iocage jail在运行,所以 service(8)
停止了它。但是,我的命令没有重新启动ioc-ww2,因为它没有在 jail.conf
中配置。
如果你同时运行标准jail和iocage jail,你需要按名称停止、启动和重新启动标准jail。
xxxxxxxxxx
# service jail restart loghost
Stopping jails: loghost.
Starting jails: loghost.
当你在 /etc/rc.conf 中将 jail_enable
设置为 YES
时,FreeBSD会在引导时运行 service jail start
,并启动 jail.conf 中配置的所有内容。
我经常为测试和调试配置jail,我不想在启动时自动启动。我不希望仅仅存在 jail.conf 条目就使 service(8)
自动启动或停止这些jail。rc.conf 中的 jail_list
选项限制了 service(8)
管理的jail。
xxxxxxxxxx
jail_list="loghost logdb"
这将 service(8)
限制为仅运行jails loghost
和 logdb
。它将 service(8)
在启动时启动所有内容的问题替换为维护jail_list的问题。
要关闭所有已配置的jail,请运行 service jail stop
。要只停止一个jail,请添加jail名称。
iocage与FreeBSD service(8)
架构集成。如果在 /etc/rc.conf 中将 iocage_enable
设置为 YES
,FreeBSD将在引导时运行 service iocage start --rc
。iocage引导参数指定了自动启动的jail,默认为关闭。
xxxxxxxxxx
# iocage get -r boot
+------+-------------+
| NAME | PROP - boot |
+======+=============+
| www2 | off |
+------+-------------+
| www1 | off |
+------+-------------+
我希望iocage在启动时自动启动www1,所以我更改了它的启动参数:
xxxxxxxxxx
# iocage set boot=on www1
Property: boot has been updated to on
运行 iocage get
可以验证这一点。
iocage start
命令启动jail。使用 --rc
标志只影响设置为在启动时启动的jail,就像 service iocage start
一样。您还可以按名称选择jail:
xxxxxxxxxx
# iocage start www1
* Starting www1
+ Started OK
+ Starting services OK
使用 ALL
标志启动每个jail,无论是否设置为在启动时启动:
xxxxxxxxxx
# iocage start ALL
如果一些jail正在运行,那么使用 ALL
只会启动尚未运行的jail。它不会触发重启。
要让iocage重新启动正在运行的jail,请使用 restart
命令。指定一个jail,或使用 ALL
反弹每个jail。
xxxxxxxxxx
# iocage restart www2
好消息是jail启动很快,所以这些服务中断不会持续太久。
使用 iocage stop
命令停止jail,要么给出jail名称,要么,如果你想停止每一个jail,全部。如果在 rc.conf
中启用了iocage,您还可以运行 service iocage stop
。
xxxxxxxxxx
# iocage stop ALL
Iocage在关闭jail时报告每个jail的状态。
当在 rc.conf
中启用iocage时,FreeBSD会在系统关闭时运行 service iocage stop
。这将关闭所有启用 boot
参数的机器。它忽略任何没有该参数的jail,因此您需要自己关闭这些jail,或者让它们随主机一起随意死亡。
当你创建一个jail时,FreeBSD会以非常类似于单用户模式的方式创建它。要进入多用户模式,jail运行 /bin/sh/etc/rc
。在未配置的jail中, /etc/rc
启动 cron
和 syslogd
并等待您的命令。
不过,也许你不想运行完整的启动,出于某种原因,你不想在 /etc/rc.conf 中禁用 cron
和 syslogd
。也许你甚至不想挂载 /dev ,尽管缺乏标准输入和标准输出等关键设备会导致大多数程序快速失败。你可能会得到一个好主意,写自己的jail启动脚本。这种冲动几乎总是错误的。如果您坚持犯这个错误,请将参数 exec.start
设置为您首选的启动脚本:
xxxxxxxxxx
exec.start="/bin/sh /etc/rc.custom"
当你关闭jail时,jail就会运行 /etc/rc.shutdown
。自定义启动脚本用户可能不希望使用标准关闭脚本。使用 exec.stop
参数设置自定义关机脚本。如果你没有实时数据,包括 syslogd
的日志文件,你可以使用 true(1)
。
xxxxxxxxxx
exec.stop="/bin/true"
启动和停止脚本在用户启动和停止jail时运行,通常是root用户。如果你的jail将数据写入磁盘,不要这样做。数据库尤其会因为被残酷地终止而变得非常古怪。
启动和停止jail时,您可能希望在主机上运行命令。exec.prestart
、 exec.poststart
、 exec.prestop
和 exec.poststop
参数支持此功能。在启动jail之前,主机运行 exec.prestart
中的任何命令。一旦jail的 /etc/rc
完成,主机就会在 exec.poststart
中运行命令。同样,exec.prestop
在jail的 /etc/rc.shutdown 之前运行,exec.poststop
在jail被完全杀死后运行。在这里,我在 /etc/jail.conf 中为所有这些设置了默认值。
xxxxxxxxxx
exec.prestart="logger trying to start jail $name...";
exec.poststart="logger jail $name has started";
exec.prestop="logger shutting down jail $name";
exec.poststop="logger jail $name has shut down";
exec.timeout=90;
现在,每次你启动或停止jail时,我都会得到一个 /var/log/messages 条目。
如果你想运行多个命令,用 +=
语法堆叠它们。在这里,我想记录一个jail已经启动,但我也想添加一个在第11章中讨论的CPU限制命令。
xxxxxxxxxx
exec.poststart="logger jail $name has started";
exec.poststart+="cpuset -c -j $name -l 2-5";
iocage的 exec_prestart
、 exec_poststart
、 exec_prestop
和 exec_poststop
参数的工作方式完全相同。
不过,这个 exec.timeout
是从哪里来的?脚本(包括 rc.shutdown
和自定义关机脚本)可能会失败。一个简单的崩溃并不那么令人担忧,但如果脚本永远挂起怎么办?监狱使用 exec.timeout
来设置等待 exec.prestart
、 exec.poststart
、 exec.prestop
和 exec.poststop
的时间限制。如果这些命令在超时后仍在运行,则jail不会启动或停止。您必须修复启动或停止jail的命令。如果你保持这种状态,jail将永远等待jail完成命令。
此外,stop.timeout
参数设置了从关闭脚本完成到jail等待任何延迟命令之间的秒数。默认为10秒。如果你告诉一个jail关闭,但脚本没有在 exec.timeout
允许的分配时间内完成,那么关闭会等待 stop.timeout
秒,然后强制终止jail及其所有进程。
iocage将默认的 exec_timeout
设置为60秒。标准jail没有默认超时;你必须设置一个 exec.timeout
。在这个例子中,我将 exec.timeout
设置为90,以匹配 /etc/rc.shutdown
在强制终止进程之前使用的90秒超时。如果jail的 rc.shutdown
不能结束一个过程,那么jail的删除将以有损(prejudice)结束。
说到超时,我们都看到过主机控制台在系统关闭时,FreeBSD宣布它正在强行屠杀一些完全拒绝退出的程序。这样的项目也可能垄断jail。当一个像数据库这样的大程序被告知要关闭时,它需要几秒钟来完成自我清理并不是不合理的。标准jail不提供宽限期;当jail的 rc.shutdown
完成时,他们会立即终止所有此类进程。参数 stop.timeout
给出了jail等待此类程序退出的秒数。在标准jail中,它默认为 0
,但iocage默认为 stop_timeout
为 30
。
始终设置超时。总是。也许你没有使用任何 exec.pre-
或 post-commands ,你也不认为你的jail会运行在关闭时需要额外时间的进程,但每个真正的系统管理员都知道“事情会发生”,有时这些事情很可怕。在设置主机时,在 jail.conf
的顶部将 exec.timeout
和 stop.timeout
设置为 30
,可以防止以后出现一大堆痛苦。
FreeBSD创建了jail,然后运行jail中的第一个命令。一旦jail存在,但在jail实际开始之前,您可能需要在主机上运行命令。这就是 exec.created
发挥作用的地方。
大多数 exec.created
用例都相当高级,例如jailing ZFS数据集和施加资源限制。我将在这些部分演示 exec.created
。这是一种几乎从不需要的工具,但在极少数情况下,它是无价的。
jail有参数来决定它们在关闭期间的行为,而且确实有特殊的参数,即使里面什么都没有运行,它们也能存在。
当jail正在关闭时,只读参数 dying
设置为 1
。实际上很难捕捉到这一点,因为只有在jail的关闭脚本完成运行并且主机内核正在剥离jail的过程中,才会设置 dying
。不过,在不太可能的情况下,你想在jail被杀死时对其进行更改,将参数 allow.dying
设置为 1
允许这样的更改。
通常,当一个jail不再有任何进程运行FreeBSD时,它会释放所有资源,擦除所有私有命名空间,并忘记jail曾经存在过。不过,你可能需要一个没有任何流程的jail。jail.conf persist
参数告诉FreeBSD即使在没有进程的情况下也要保留jail。iocage没有持久参数。最常见的是,在创建复杂的jail时使用 persist
。
只有root可以启动jail,但许多附加任务(如前脚本和后脚本)不需要以特权运行。以root身份运行此类命令可能是不明智的。虽然 exec.jail_user
、 exec.system_jail_user
和 exec.system_user
参数允许您为某些任务设置特殊用户,但它们并不像看起来那么有用。
记住,jail是通过运行 jail(8)
命令创建的。该命令需要权限才能为jail挂载设备文件系统。大多数用户无法做到这一点。您可以使用 exec.system_user
指定一个用户来运行创建jail的命令,但您需要进行一系列故障排除才能使其正常工作。
同样,exec.jail_user
参数在jail的 /etc/passwd 中定义了一个用户,以在jail命令中运行。没有特权的用户不能运行 /etc/rc ,因此除非你编写了自己的启动脚本,否则它在很大程度上是无用的——即使如此,你最终也会执行大量的故障排除。
最后,exec.system_jail_user
参数有 jail(8)
,它使用主机 /etc/passwd 中的帐户在jailed环境中运行命令。
service
命令为jail管理提供了方便的前端,但当事情出错时,你会怎么做?在这一点上,你必须回到原始的 jail(8)
命令。
这并不像听起来那么糟糕。-c
标志创建了一个jail,-v
增加了冗长。在这里,我通过 jail(8)
开始jail loghost :
xxxxxxxxxx
# jail -vc loghost
loghost: run command: /sbin/ifconfig jailether inet 203.0.113.231 netmask 255.255.255.255 alias
loghost: run command: /sbin/mount -t devfs -oruleset=5 . /jail/loghost/dev
loghost: run command: logger trying to start jail loghost...
loghost: jail_set(JAIL_CREATE) persist name=loghost path=/jail/loghost host.hostname=loghost.mwl.io ip4.addr=198.51.100.225 enforce_statfs=1 allow.mount=true allow.mount.tmpfs=true allow.mount.zfs=true devfs_ruleset=5 allow.raw_sockets
loghost: created
loghost: run command in jail: sh /etc/rc
loghost: run command: logger jail loghost has started
loghost: jail_set(JAIL_UPDATE) jid=4 nopersist
当jail无法启动时,你可以确切地看到原因。当你读完这本书时,你会明白所有这些晦涩难懂的东西。
要删除正在运行的jail,请运行 jail -r
并给出JID或jail名称。jail将运行其关闭脚本并退出。
xxxxxxxxxx
# jail -vr loghost
停机问题较为罕见,但仍然会发生。要无条件地立即销毁jail而不运行任何关闭脚本,请使用 -R
标志。
xxxxxxxxxx
# jail -vR loghost
除了通过 jls
提供jail信息外,jail(8)
还将jail ID存储在 /var/run 中的文件中。每个文件都以 jail_ 开头,添加jail名称,以 .id 结尾。logdb的JID将存储为 /var/run/jail_logdb.id 。
不幸的是,iocage并没有提供一种观察它制造问题jail的方法。然而,它确实提供了错误消息,指示问题所在。
iocage程序在 /var/run 中为它启动的每个jail创建一个配置文件,名为 jail.ioc-、监狱名称和 .conf 。例如,iocage jail www1的配置文件是 /var/run/jail.ioc-www1.conf 。如果你想知道为什么现有的jail会以某种方式运行,请仔细检查它的配置文件。
如果一个iocage jail拒绝关闭,你可以用 jail -vR
和jail名称来摧毁它。原始 jail命令胜过iocage
、service(8)
和所有其他附加工具。
你可能认为你想使用jail的返回码来查看jail内发生了什么,并采取行动。你错了。jail(8)
的返回代码代表了jail所经历的,而不是jail内运行或关闭的程序的特定错误代码。如果jail开始或停止,jail将返回通常的 0
。如果jail没有正确启动或停止,因为jail内的命令出错,jail将返回 1
。
简而言之,你不能依赖jail的返回码来表示jail内的事件。它只能告诉你“东西奏效了”,或者“东西不起作用了”。
你的jail开始的顺序可能很重要,也可能不重要。如果你在另一个jail里有一个由数据库支持的网络服务器,那么在两个jail都完全运行之前,网站将无法运行。如果数据库首先启动,则用户在web服务器启动之前不会得到任何响应。不过,如果web服务器先启动,在数据库可访问之前访问网站的用户将看到“哦,糟糕,我的数据库死了”页面的某种变体。作为一名系统管理员,我理解正在发生的事情,并不真正关心这种短暂的错误。然而,我的经理们一致希望消除用户可见的错误。jail.conf 和 iocage
都允许您管理jail的启动和关闭顺序。
您可以使用 jail_list
或 depend
参数来管理标准的jail启动顺序。
depend
参数可能是控制启动顺序的最简单方法。不要明确列出jail应该开始的顺序,depend
让你说这个jail需要另一个jail。你不在乎你的jail群以什么顺序开始,只要某些jail在其他jail之前开始。假设我需要先启动 logdb
再启动 loghost
。我可以在 loghost
的jail.conf 条目中指定:
xxxxxxxxxx
loghost {
ip4.addr="203.0.113.232";
depend="logdb";
}
如果你没有设置依赖参数,但在 rc.conf
中使用了 jail_list
,FreeBSD将按照jail_liste
中列出的顺序启动和停止jail。如果关闭顺序应与启动顺序相反,请将 rc.conf
选项 jail_reverse_stop
设置为“YES”。
depend
参数覆盖了jail在 jail_list
中的位置,允许所需的jail排在前面。
iocage使用 depends
参数而不是 jail(8)
的 depend
,但它的工作方式完全相同。如果你想让一个jail在开始之前要求另一个jail运行,请根据具体情况列出所需的jail。这里我需要数据库服务器 wdb1 在 www1 之前运行:
xxxxxxxxxx
# iocage set depends=wdb1 www1
Property: depends has been updated to wdb1
如果我需要在开始这个jail之前运行多个jail,我会用引号输入:
xxxxxxxxxx
# iocage set depends="wdb1 wdb2" www1
Property: depends has been updated to wdb1 wdb2
depends参数会覆盖引导。如果一个准备在启动时运行的jail需要另一个jail来启动,那么这个jail就启动了。看看我的iocage jails:
xxxxxxxxxx
# iocage get -rh boot
www2 off
wdb2 off
www1 on
wdb1 off
只有www1在启动时明确启动。
让我们关闭一切,看看启动时会发生什么:
xxxxxxxxxx
# iocage stop ALL
…
# iocage start --rc
# iocage get --rh state
www2 down
wdb2 up
www1 up
wdb1 up
数据库服务器仍在运行。如果这是一次真正的主机关闭,那么您的数据库将无法正常终止。人们普遍认为这是个坏主意。为您希望FreeBSD为您启动的每台机器设置引导参数。
iocage在启动任何jail之前计算启动依赖关系,让您菊花链化(daisy-chain) depends
参数。如果www1需要wdb1,wdb1需要iscsi1,iocage会按顺序启动和停止jail。这样做的缺点是,可以预见的是,循环依赖会使iocage不愉快。如果www1依赖于wdb1,但wdb1需要www1,则创建了一个循环。iocage不会启动任何东西。
依赖关系可能会迅速变得令人沮丧地复杂。大多数时候,我们希望遵循“先启动iscsi jail,然后启动数据库jail,再启动网络服务器”等指导方针。使用 priority
参数建立这种系统。 priority
(优先级)是一个任意整数,默认为99。优先级1首先开始,而其他一切都按顺序开始。按角色对jail进行分组,并相应地分配其优先级,然后用depends修补例外情况:
xxxxxxxxxx
# iocage set priority=50 wdb1
# iocage set priority=10 iscsi1
iocage以相反的优先级顺序关闭jail。
仅仅因为你将jail配置为在启动时启动,并不意味着jail会继续运行。使用 jls(8)
查看当前正在运行的jail。您将看到jail的IP地址、主机名和根目录的路径。在这种情况下,根目录还可以清楚地看出哪些jail是标准的,哪些是iocage。
xxxxxxxxxx
# jls
JID IP Address Hostname Path
1 203.0.113.234 www1 /iocage/jails/www1/root
2 203.0.113.236 wdb1 /iocage/jails/wdb1/root
3 203.0.113.235 www2 /iocage/jails/www2/root
4 203.0.113.237 wdb2 /iocage/jails/wdb2/root
6 203.0.113.232 logdb.mwl.io /jail/logdb
7 203.0.113.231 loghost.mwl.io /jail/loghost
每个jail都有一个唯一的jail ID或 JID
。每个jail在启动时都会被分配一个唯一的jail ID,并在JID运行期间保留该ID。当你停止、重启或重新启动jail时,jail会得到一个新的JID。正如我们将在本书中看到的那样,JID与jail相关的过程和记忆有关。
虽然您可以使用 jid
参数在 jail.conf 中硬编码jail ID,但此功能主要是为了支持过时的管理脚本。jail ID与系统资源绑定,在这些资源从关闭中释放出来之前,jail无法重新启动。这需要的时间比你想象的要长,会导致沮丧,还会让你的母亲感到羞愧。让JID是一次性的。Iocage不包括此选项。
如果你想列出一个特定的jail,请添加 -j
标志和jail的名称:
xxxxxxxxxx
# jls -j loghost
JID IP Address Hostname Path
9 203.0.113.231 loghost.mwl.io /jail/loghost
当您使用 jls(8)
的一些更高级的视图时,按名称列出jail变得非常重要。
jail是由 jail(8)
命令创建的。所有的jail配置方法,从 jail.conf 到iocage以及其他方法,都只是简化创建 jail(8)
命令以启动jail的工具。它们是抽象层。如果你想验证抽象层没有出错,并且你设置的所有选项都实际应用了,你需要查看jail运行的参数。
一些参数,如 securevel
(第8章),可以在创建jail后进行调整。您需要能够查看jail的当前设置,而不是创建jail时如何设置参数。当我们谈到这些参数时,我们会特别提到它们。
jls(8)
命令可以查询主机的内核并显示jail的当前参数设置。未传递给内核的参数不会显示;它们是运行时的昙花一现,无论如何,自从jail开始以来,它们都可能被改变。要找到像 depend
和 exec.prestart
这样的伪参数(pseudo-parameters),您必须读取 jail.conf 或查询 iocage
。
一个有用的设置是查看用于启动jail的命令行。在实时jail中可以更改的参数(如 securevel
)以其当前值而不是启动值显示,但对于大多数调试来说,这已经足够了。使用 -s
标志查看排列为 jail(8)
参数的参数。输出相当可观,所以我通常会将其与 -j
结合起来,只查看我感兴趣的jail:
xxxxxxxxxx
# jls -sj loghost
devfs_ruleset=0 enforce_statfs=2 host=new ip4=disable ip6=disable jid=9 linux=new name=loghost osreldate=1300007 osrelease=13.0-CURRENT path=/jail/loghost nopersist securelevel=-1 sysvmsg=new sysvsem=new sysvshm=new vnet=inherit allow.nochflags allow.nomlock allow.nomount allow.mount.nodevfs allow.mount.nofdescfs allow.mount.nolinprocfs allow.mount.nonullfs allow.mount.noprocfs allow.mount.notmpfs allow.mount.nozfs allow.noquotas allow.noraw_sockets allow.noread_msgbuf allow.reserved_ports allow.set_hostname allow.nosocket_af allow.nosysvipc allow.unprivileged_proc_debug children.max=0 host.domainname=/""}"" host.hostid=0 host.hostname=loghost.mwl.io host.hostuuid=00000000-0000-0000-0000-000000000000 linux.osname=Linux linux.osrelease=2.6.32 linux.oss_version=198144
现在你明白为什么 jail(8)
有抽象层了。
jail(8)
内部有几个参数。要同时提取这些,请使用 -n
标志:
xxxxxxxxxx
# jls -nj loghost
devfs_ruleset=0 nodying enforce_statfs=2 host=new ip4=disable ip6=disable jid=9 linux=new name=loghost osreldate=1300007 osrelease=13.0-CURRENT
…
对于一个标题列出所有参数的漂亮表,以及它下面列出的该参数的每个jail值,请添加 -h
标志。当你想向老板证明你需要一个更大的显示器时,这很有用,因为你目前的显示器只能处理600个字符宽的终端。不过,您可以添加参数名称以仅查看感兴趣的参数。在这里,我检查了 sysvshm
、sysvsem
和 sysvmsg
的值。我还获取了 name
参数,这样我就知道结果适用于哪个监狱。为了整理结果,我通过列 -t
运行它们:
xxxxxxxxxx
# jls -h name sysvshm sysvsem sysvmsg | column -t
name sysvshm sysvsem sysvmsg
ioc-wdb2 0 0 0
ioc-squid1 0 0 0
loghost 1 1 1
ioc-www1 2 2 2
添加 -j
可以检查单个jail的参数。
要为每个jail获得一个漂亮的多行列表并选择参数,请使用 -v
标志。
xxxxxxxxxx
# jls -vj loghost
JID Hostname Path
Name State
CPUSetID
IP Address(es)
9 loghost.mwl.io /jail/loghost
loghost ACTIVE
4
203.0.113.231
这也是查看jail分配给哪个处理器的唯一简单方法——这一事实通常无关紧要,但很高兴知道jail不能叉式轰炸(fork-bomb)你的主机。
jail支持libXO,允许您以HTML、XML、JSON甚至纯文本打印jail信息。如果您希望运行复杂或广泛的报告,并拥有解析这些格式的工具,这将非常有用。添加 --libxo
参数和所需的格式:
xxxxxxxxxx
# jls -n --libxo xml
我们这些老派的系统管理员将继续使用 grep
和切入式(cut in)shell脚本,痛苦地解析结果,并永远在我们的审计脚本中添加特殊的边缘情况,所有这些都是以技术优势的名义进行的。
如果你只对iocage jails感兴趣, iocage list
命令会显示哪些jail正在运行,哪些没有。我们已经做过几次了。要获取每个jail的更多信息,请使用 iocage list -l
打印一个长列表。虽然输出的宽度取决于显示的信息,但您需要一个至少100个字符宽的终端来正确显示它。
iocage list
命令有一大堆标志和参数来查看iocage相关信息。这是检查iocage jail的一般前端。我们将在相关章节中研究这些。
使用标准系统管理工具来管理被jail的流程。iocage(8)
和 jail(8)
都不包括任何特殊的流程管理工具。
jail没有唯一的进程ID范围或单独的进程ID池;它们都与主机共享相同的进程ID范围。如果您是主机上的root并列出所有正在运行的进程,您将看到所有jail中都在运行的进程。jail中的用户只能看到与该jail相关的进程。在jail内运行的进程在 ps(1)
中用 J
标记。
xxxxxxxxxx
# ps -ax
…
1951 - SsJ 0:00.10 /usr/sbin/syslogd -c -ss
2005 - IsJ 0:00.29 /usr/sbin/cron -J 15 -s
2090 - SsJ 0:00.10 /usr/sbin/syslogd -c -ss
2144 - IsJ 0:00.30 /usr/sbin/cron -J 15 -s
2229 - SsJ 0:00.11 /usr/sbin/syslogd -c -ss
2283 - IsJ 0:00.32 /usr/sbin/cron -J 15 -s
…
所有这些过程都有 J
标志,表明它们与监狱有关。
ps(1)
的 -J
标志允许您查看属于特定jail的进程。给 -J
一个论点,jail名称或JID。在这里,我看到了logdb中运行的内容:
xxxxxxxxxx
# ps -ax -J logdb
PID TT STAT TIME COMMAND
3652 - SsJ 0:00.10 /usr/sbin/syslogd -s
3705 - SsJ 0:00.45 sendmail: accepting connections (sendmail)
3708 - IsJ 0:00.02 sendmail: Queue runner@00:30:00 for /var/spool/clientmqueue (sen
3712 - IsJ 0:00.32 /usr/sbin/cron -s
这是一个相当小的系统。别担心,我很快就会补充的。
要排除所有被jail的进程,只查看属于主机的进程,请告诉 J
使用jail ID 0
。这使您可以更轻松地调试主机本身:
xxxxxxxxxx
# ps -ax -J 0
PID TT STAT TIME COMMAND
0 - DLs 2:38.25 [kernel]
1 - ILs 0:00.08 /sbin/init --
2 - DL 0:00.00 [crypto]
…
大多数与进程相关的命令,如 pkill(1)
、 pgrep(1)
和 killall(1)
,都接受 -j
参数来指定jail。每个jail都有自己的 cron
程序。在这里,我找出哪个属于jail jogdb:
xxxxxxxxxx
# pgrep -j logdb cron
3712
然而,我们大多数人不会以这种方式进行故障排除。我们将登录到一个有问题的主机,看到其中一个MySQL进程正在疯狂运行并占用所有CPU,需要回溯它属于哪个jail。ps(1)
的 -O
选项通过关键字参数揭示了许多关于进程的方便事实。(如果你想提取一个过程的信息,一定要看看 ps(1)
中80多个关键字的列表。)添加 -O jail
会打印jail的名称。
xxxxxxxxxx
# ps -ax -O jail | grep 8219
8219 wdb1 - IsJ 0:00.00 /usr/local/libexec/mysqld
进程8219正在jail中运行wdb1。
为了更动态地查看特定jail的流程,top(1)
还接受 -J
标志。添加jail名称作为参数,您将看到jail内运行情况的标top视图:
xxxxxxxxxx
$ top -J ioc-www1
使用 -j
标志运行 top
会显示主机的top列表,包括一个 JID
列。j
也是一个交互式 top
命令,允许您打开和关闭JID显示。
同样,进程管理程序 pkill(1)
、pgrep(1)
和 killall(1)
都接受 -j
参数,通过JID或name指定一个jail:
xxxxxxxxxx
# killall -1 mysqld -j wdb2
是的,您可以使用 jexec(8)
或 iocage exec
来管理jail内的进程。没有实际区别。选择适合你的。(我的手指还不习惯这些新奇的 pgrep
和 pkill
命令,但欢迎你们这些年轻人使用。)
虽然您可以登录到jail运行命令,但您可以使用 jexec(8)
从主机在活动jail中运行命令。您可能希望通过SSH进入jail进行复杂的工作,如服务器配置或故障排除,但对于一次性命令,尤其是在多个监狱中,jexec
几乎总是最简单的。您需要三个参数:-l
、运行命令的jail名称和要运行的命令。(我们将在下一节中看到为什么需要 -l
。)如果你不输入命令,它会运行一个shell。您必须是root才能运行 jexec
:
xxxxxxxxxx
# jexec -l loghost uname -a
FreeBSD loghost.mwl.io 13.0-CURRENT FreeBSD 13.0-CURRENT #10 r338496: Fri Sep 6 12:29:00 EDT 2019
root@storm:/usr/obj/usr/src/amd64.amd64/sys/GENERIC amd64
我已经从我的主机运行了这个命令,但它是在jail loghost运行的。
假设我首先设置jail,我想设置一个root密码。我给出了jail的名称、我要运行的命令以及该命令的任何参数:
xxxxxxxxxx
# jexec -l loghost passwd root
Changing local password for root
New Password:
jexec(8)
命令仅适用于运行jail。要在jail中运行一个不起作用的命令,您需要像第2章中讨论的那样jail一个单独的命令。在这里,我在一个非活跃的jail里开始了一个shell:
xxxxxxxxxx
# jail /jail/loghost/ loghost 203.0.113.231 /bin/sh
从技术上讲,这会启动jail,但只是以有限的方式。在jail里运行的唯一过程是你的shell,加上你开始的任何东西。
你可以在iocage jails上使用 jexec
,但你需要在jail名称前添加 ioc
——记住,iocage jail在他们的名称前会有这个标签。与其记住这一点,不如使用 iocage exec
。与 jexec
一样,它接受两个参数,主机和命令。如果你不提供命令,它会运行一个shell。在这里,我将一个用户添加到我的iocage jail loghost中:
xxxxxxxxxx
# iocage exec www1 adduser
如果你想在jail里有一个shell,最好使用 iocage console
命令。这模拟了您jail的完整root登录。以jail的名字作为参数:
xxxxxxxxxx
# iocage console www1
为什么要使用iocage控制台,而不仅仅是 jexec shell?因为jail的环境。
进程从其父进程继承其环境。由jail启动进程启动的进程是jail /etc/rc (或你用来启动jail的任何命令)的子进程。那个环境净化得很好。虽然你的 jexec
和 iocage exec
命令被标记为属于jail,但它们是你现有shell的子命令。这似乎是一个小细节,但问问一个被jailed的命令关于它的环境。这次我们跳过 -l
:
xxxxxxxxxx
# jexec loghost env
HOME=/home/mwlucas
TERM=xterm
LC_COLLATE=C
…
SSH_CLIENT=203.0.113.70 59076 22
SSH_CONNECTION=203.0.113.70 59076 203.0.113.50 22
SSH_TTY=/dev/pts/2
SSH_AUTH_SOCK=/tmp/ssh-ZfvZOatcsu/agent.60492
…
等等——一个被监禁的进程不应该有我的终端会话的SSH环境变量!它之所以有它们,是因为这个过程虽然是在jail的过程上下文中创建的,但继承了父母的环境。不要介意我的SSH代理的身份验证套接字所在的目录甚至不存在于jail中,它们是shell环境的一部分。同样,它从我的登录文件中继承了一堆其他crud。
添加 -l
命令 jexec
删除除 $HOME
、$SHELL
、$TERM
和 $USER
之外的所有设置。它还保留了用户登录类中的任何内容。
同样,启动jail的初始进程是另一个进程的子进程——可能是主机初始启动的 /etc/rc ,或者如果你手动启动jail,可能是你的shell。exec.clean
参数告诉 jail(8)
在启动jail之前清除环境。默认值为 1
,用于清洁环境。如果你想让一个jail继承启动它的进程的环境,设置exec.noclean
来准确了解你是怎么错的。
iocage的 exec
命令默认在干净的环境中运行所有内容。iocage参数 exec_clean
控制命令是否应在干净的环境中运行。默认值 1
用于清除环境。当设置为 0
时,iocage exec
将继承用户的环境。
您可以运行 jexec -l /bin/sh
或 iocage exec /bin/sh
来获取shell,但这并不能真正模拟以root身份登录jail的效果。真正的登录体验应该是源点文件和处理登录类。
通过运行 login(1)
,通过 jexec(8)
从主机获取jail的真实登录名。为login提供 -f
参数和要登录的帐户。我在jail loghost上找到了一个根shell:
xxxxxxxxxx
# jexec -l loghost login -f root
FreeBSD 13.0-CURRENT (GENERIC) #10 r338496: Thu Sep 6 12:29:00 EDT 2019
Welcome to FreeBSD!
Release Notes, Errata: https://www.FreeBSD.org/releases/
…
root@loghost:~ #
是的,你得到了完整的/etc/motd和一切。
要使用iocage获取root登录,请使用 console
命令:
xxxxxxxxxx
# iocage console www1
…
root@www1:~ #
iocage没有以非root用户身份登录jail的功能,但您可以使用 jexec -l jail login -f user
,以root身份登录并使用 su(1)
,或使用像jailme这样的附加包。
我们都有FreeBSD无法启动、无法停止或在重启过程中莫名其妙地挂起太久的情况。通常你需要检查系统控制台,看看是什么配置错误导致了延迟。jail可以将他们的控制台输出记录到一个文件中。
在标准jail中,将参数 exec.consollelog
设置为一个文件。在这里,我在 jail.conf 的顶部设置了一个默认的控制台日志:
xxxxxxxxxx
exec.consolelog="/var/tmp/$name";
这将创建 /var/tmp/loghost 和 /var/tmp/logdb 等文件。
你可能会认为控制台日志应该得到仔细的保护,这当然是有道理的。然而,你的jail主机应该作为一个整体得到仔细的保护,普通用户不应该有任何访问权限。非法访问jail控制台日志是你的最小问题。不过,如果您担心,请将这些日志放在只能由root读取的目录中。
iocage会自动将所有控制台记录到iocage数据集上的日志目录中,因此我的控制台日志会放在 /Iocage/log/ 中。每个控制台日志都以jail命名,并附加 -console.log。iocage jail www1的日志是 /icage/log/www1-console.log 。
现在您可以创建、启动、停止、重新启动、折叠和主轴jail,让我们用它们执行一些常见的系统管理员任务。