doc/zh_TW.Big5/books/handbook/jails/chapter.xml
Gabor Kovesdan a6684b4306 - Reduce the misuse of role attribute; role="directory" should actually be
class="directory"
- Add constraint to enforce this
2013-04-04 11:40:58 +00:00

818 lines
30 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="big5"?>
<!--
The FreeBSD Documentation Project
$FreeBSD$
Original revision: 1.15
-->
<chapter id="jails">
<chapterinfo>
<authorgroup>
<author>
<firstname>Matteo</firstname>
<surname>Riondato</surname>
<contrib>Contributed by </contrib>
</author>
</authorgroup>
</chapterinfo>
<title>Jails</title>
<indexterm><primary>jails</primary></indexterm>
<sect1 id="jails-synopsis">
<title>概述</title>
<para>本章將介紹 &os; jail 為何,以及如何運用之法。
Jails 有時也常被認為是 <emphasis>chroot 環境</emphasis>
的加強型替代品之一,它對系統管理者而言是非常好用的工具,
此外,它的一些基本用法對進階使用者而言,也是相當有用。</para>
<para>讀完這章,您將了解︰</para>
<itemizedlist>
<listitem>
<para>jail 是什麼,以及它在 &os; 上可以發揮的作用。</para>
</listitem>
<listitem>
<para>如何編譯、啟動、停止 jail。</para>
</listitem>
<listitem>
<para>jail 管理的基本概念:包括從 jail 內部或主機本身。</para>
</listitem>
</itemizedlist>
<para>其他有用的 jail 相關資源還有:</para>
<itemizedlist>
<listitem>
<para>&man.jail.8; 線上說明。 這是有關 <command>jail</command>
的完整說明 &mdash; &os; 內的啟動、停止、控制 &os; jail
相關管理工具。</para>
</listitem>
<listitem>
<para>郵遞論壇(mailing lists)及舊信檔案館(archives)。
&a.mailman.lists; 所提供的 &a.questions; 及其他郵遞論壇的舊信
,已有包括一堆 jail 的有用資料。 通常,搜尋舊信或者在
&a.questions.name; 上發問,也相當有效。</para>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="jails-terms">
<title>Jail 相關術語</title>
<para>為協助更容易理解 &os; 系統的 jail 相關部分,
以及它們與 &os; 其他部分的相互作用關係,
以下列出本章將使用的術語:</para>
<variablelist>
<varlistentry>
<term>&man.chroot.2; (指令)</term>
<listitem>
<para>&os; 的 system call 之一,其作用為改變 process
及其衍生 process 所能運用的根目錄 (<filename>/</filename>
dir)。</para>
</listitem>
</varlistentry>
<varlistentry>
<term>&man.chroot.2; (環境)</term>
<listitem>
<para>指在 <quote>chroot</quote> 中運行的 process 環境。
這包括了類似檔案系統的可見部分、可用的 UID、GID、網路卡及其他 IPC
機制等資源。</para>
</listitem>
</varlistentry>
<varlistentry>
<term>&man.jail.8; (command)</term>
<listitem>
<para>允許程式在 jail 環境下執行的系統管理工具。</para>
</listitem>
</varlistentry>
<varlistentry>
<term>host (系統、process、帳號等等)</term>
<listitem>
<para>jail 環境的控制系統。 host 系統可以使用全部可用的硬體資源,
並能控制 jail 環境內外的 process。 host 系統與 jail 最大的差別在於
:在 host 系統中的 superuser processes 並不像在 jail
環境那樣處處受到一堆限制。</para>
</listitem>
</varlistentry>
<varlistentry>
<term>hosted (系統、process、帳號等等)</term>
<listitem>
<para>可用資源受到 &os; jail 限制的 process、帳號、或其他設備資源
</para>
</listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 id="jails-intro">
<title>背景故事</title>
<para>由於系統管理是困難又繁瑣的工作,因此人們開發許多好用工具,
以讓管理工作更加簡單輕鬆。 這些改善通常是讓系統能夠以更簡單的方式安裝、
設定、維護,而有些改善目標則是系統安全的正確設定,使其能真正發揮原本用途,
而非陷入安全風險之中。</para>
<para>&os; 系統所提供的一種用於強化安全的工具就是 <emphasis>jail</emphasis>
。 Jail 是由 &a.phk;&os;&nbsp;4.X 開始導入,而在 &os;&nbsp;5.X
受到許多重大改良而集大成,成為強大而靈活的子系統,目前仍在持續開發、
以提高其可用性、效能與安全。</para>
<sect2 id="jails-what">
<title>何為 Jail</title>
<para>BSD-like 作業系統自 4.2BSD 起即提供 &man.chroot.2;
&man.chroot.8; 可用來變更一組 process 的根目錄位置,
藉此建立與實體系統中相隔離的安全環境。 處於 chrooted 環境的
process 會無法不能存取世外的檔案或資源。 由於此因素,
故即使攻擊者攻破某個處於 chroot 環境的 service也不能攻破整個系統。
&man.chroot.8; 對於那些不太需要彈性或複雜又高級的簡單應用而言相當好用。
另外,在引入 chroot 概念的過程中,曾經發現許多可脫逃 chroot 環境的方式,
儘管這些問題在較新版本的 &os; kernel 均已修正,但很明顯地 &man.chroot.2;
絕非用於強化安全的理想解決方案。 因此,
勢必得實作新的子系統來解決這些問題。</para>
<para>這就是為何要開發 <emphasis>jail</emphasis> 的最主要原因。</para>
<para>Jail 在各種方式分進合擊,改進傳統 &man.chroot.2; 環境的概念。
在傳統的 &man.chroot.2; 環境中,只限制 process 對於檔案系統的存取部分,
而系統資源的其他部分(例如系統帳號、執行中的 process、網路子系統)則是由
chroot process 與 host 系統的其他 process 一起共享。
Jail 以『虛擬化』來擴展這模型,不單只有檔案系統的存取,還延伸到
系統帳號、&os; kernel 的網路子系統及其他系統資源的虛擬化。
關於這些 jail 環境存取的細微調控,請參閱 <xref
linkend="jails-tuning"/></para>
<para>jail 具有下列四項特色:</para>
<itemizedlist>
<listitem>
<para>目錄子樹(directory subtree) &mdash; 也就是進入 jail 的起點。
一旦進入 jail 之後process 就不再被允許跳到 subtree 以外。
&amp;傳統會影響到 &man.chroot.2; 最初設計的安全問題,就不會再影響
&os; jail。</para>
</listitem>
<listitem>
<para>主機名稱(hostname) &mdash; 用於 jail 的 hostname。 由於
jail 主要用於網路服務,因此若各 jail 皆有名稱,
對於系統管理工作的簡化會相當有效。</para>
</listitem>
<listitem>
<para><acronym>IP</acronym> address &mdash; 是用來給 jail 使用,
並且在 jail 生命週期內都無法變更。 通常 jail 的 IP address
是現有網卡的 alias address但這並不是必須的。</para>
</listitem>
<listitem>
<para>指令(Command) &mdash; 準備在 jail 內執行的完整路徑。 這指令是相對於
jail 環境的根目錄,視 jail 環境的類型不同,而有所差異。</para>
</listitem>
</itemizedlist>
<para>除了上述之外jail 也可擁有自己的帳號及 <username>root</username>
帳號。 當然,這裡的<username>root</username> 權力會受制於 jail 環境內。
並且從 host 系統的角度來看jail 的 <username>root</username>
並非無所不能的帳號。 此外 jail 的 <username>root</username>
並不能執行其對於 &man.jail.8; 環境以外的一些關鍵性操作。
關於 <username>root</username> 的能力與限制,將於稍後的
<xref linkend="jails-tuning"/> 介紹之。</para>
</sect2>
</sect1>
<sect1 id="jails-build">
<title>建立和控制 Jail</title>
<para>有些系統管理者把 jail 分為下列兩種:<quote>complete(完全)</quote>
jail &mdash; 通常包括完整的 &os; 系統;另一種則為
<quote>service(服務)</quote> jail &mdash;
專門只跑某單一可能要用特殊權限的程式或 service。 這只是一種概念上的區分
,並不影響如何建立 jail 的過程。 至於如何建立 jail 在 &man.jail.8;
內有更詳細的說明:</para>
<screen>&prompt.root; <userinput>setenv D <replaceable>/here/is/the/jail</replaceable></userinput>
&prompt.root; <userinput>mkdir -p $D</userinput> <co id="jailpath"/>
&prompt.root; <userinput>cd /usr/src</userinput>
&prompt.root; <userinput>make world DESTDIR=$D</userinput> <co id="jailworld"/>
&prompt.root; <userinput>cd etc/</userinput> <footnote><para>&os; 6.0(含)
之後就不需這步驟。</para></footnote>
&prompt.root; <userinput>make distribution DESTDIR=$D</userinput> <co id="jaildistrib"/>
&prompt.root; <userinput>mount -t devfs $D/dev</userinput> <co id="jaildevfs"/></screen>
<calloutlist>
<callout arearefs="jailpath">
<para>首先就是先為 jail 找個家。 該路徑是在 host 系統中的 jail
實體位置。 習慣是放在 <filename
class="directory">/usr/jail/<replaceable>jailname</replaceable></filename>
<replaceable>jailname</replaceable> 請替換為該 jail 的 hostname
以便辨別。 通常 <filename class="directory">/usr</filename>
會有足夠空間來存放 jail 檔案系統,對於 <quote>complete</quote> jail
而言,它通常包括了 &os; 預設安裝 base system 所有檔案的拷貝檔。</para>
</callout>
<callout arearefs="jailworld">
<para>該指令將會在 jail 目錄中安裝所需的 binary、library、manual 說明等
。 這些是以傳統的 &os; 方式完成 &mdash; 即首先先編譯所有檔案,
接著再裝到目的地。</para>
</callout>
<callout arearefs="jaildistrib">
<para>使用 <maketarget>distribution</maketarget> 這個
<application>make</application> target 來裝所有會用到的設定檔。
簡單來說該動作就是把 <filename
class="directory">/usr/src/etc/</filename> 複製到 jail 環境內的
<filename class="directory">/etc</filename>,也就是
<filename class="directory">$D/etc/</filename></para>
</callout>
<callout arearefs="jaildevfs">
<para>對於 jail 環境而言,&man.devfs.8; 檔案系統的掛載並非必須,
但另一方面,幾乎所有應用程式都會需要存取至少一個設備(device)
這主要取決於該程式目的而定。 控制 jail 所能存取的設備非常重要,
因為不正確的設定,會讓攻擊者對 jail 有機可趁。 至於如何透過
&man.devfs.8; 來控制的規則,可以參閱 &man.devfs.8;
&man.devfs.conf.5; 說明。</para>
</callout>
</calloutlist>
<para>裝好 jail 之後,就可以用 &man.jail.8; 工具。 &man.jail.8;
需要四項必填參數,這些參數在 <xref linkend="jails-what"/> 有介紹過。
除了這四個參數之外,還可以指定其他參數,像是以特定帳號在 jail 中執行
process。 <option><replaceable>command</replaceable></option>
參數取決於 jail 類型而定;對於 <emphasis>virtual system(虛擬系統)
</emphasis>,那麼就選擇 <filename>/etc/rc</filename>
因為它會完成真正 &os; 系統啟動所需的操作。 對於 <emphasis>service(服務)
</emphasis> jail 而言,執行的指令取決於將在 jail 內執行的 service
或應用程式而定。</para>
<para>Jail 通常要在系統開機時啟動,因此 &os;<filename>rc</filename>
機制提供一些便利的方式來簡化這些工作:</para>
<procedure>
<step>
<para>開機時要啟動的 jail 清單要加到 &man.rc.conf.5; 設定檔:</para>
<programlisting>jail_enable="YES" # 若設為 NO 則表示不自動啟動 jail
jail_list="<replaceable>www</replaceable>" # 若有許多 jail 則請以空白隔開來寫</programlisting>
</step>
<step>
<para>對於每一筆在 <varname>jail_list</varname> 所列出的 jail
也要在 &man.rc.conf.5; 做出相對應的設定:</para>
<programlisting>jail_<replaceable>www</replaceable>_rootdir="/usr/jail/www" # jail 的根目錄
jail_<replaceable>www</replaceable>_hostname="<replaceable>www</replaceable>.example.org" # jail 的 hostname
jail_<replaceable>www</replaceable>_ip="192.168.0.10" # jail 的 IP address
jail_<replaceable>www</replaceable>_devfs_enable="YES" # 在 jail 內 mount devfs
jail_<replaceable>www</replaceable>_devfs_ruleset="<replaceable>www_ruleset</replaceable>" # jail 內所用的 devfs 規則表</programlisting>
<para>&man.rc.conf.5; 所預設的 jail 啟動設定會跑
<filename>/etc/rc</filename> 內的 jail script也就是說會假設 jail
是完整的虛擬系統。 若要用 service jail 類型,則要另外指定啟動指令,
方法是設定對應的
<varname>jail_<replaceable>jailname</replaceable>_exec_start</varname>
設定。</para>
<note>
<para>若欲知道所有可用的選項清單,請參閱 &man.rc.conf.5; 說明。</para>
</note>
</step>
</procedure>
<para>也可以透過手動執行 <filename>/etc/rc.d/jail</filename> script
來啟動或停止 <filename>rc.conf</filename> 所設定的 jail</para>
<screen>&prompt.root; <userinput>/etc/rc.d/jail start <replaceable>www</replaceable></userinput>
&prompt.root; <userinput>/etc/rc.d/jail stop <replaceable>www</replaceable></userinput></screen>
<para>目前尚無任何方法來很乾淨地關閉 &man.jail.8;
此乃因為正常用來關閉系統的指令,目前尚不能在 jail 中使用。 目前關閉 jail
最佳的方式,是在 jail 內執行下列指令,或者 jail 外面透過 &man.jexec.8;
執行下列指令:</para>
<screen>&prompt.root; <userinput>sh /etc/rc.shutdown</userinput></screen>
<para>詳情請參閱 &man.jail.8; 說明。</para>
</sect1>
<sect1 id="jails-tuning">
<title>微調與管理</title>
<para>可以為 jail 設定許多不同選項,並讓 &os; 的 host 系統與 jail
以各種不同方式組合搭配,以符合更多的應用用途。 本節要介紹的是:</para>
<itemizedlist>
<listitem>
<para>用以微調 jail 行為與安全限制的選項。</para>
</listitem>
<listitem>
<para>可透過 &os; Ports Collection 安裝的高階 jail 管理程式,
搭配這些程式可以達到一些 jail-based 解決方案。</para>
</listitem>
</itemizedlist>
<sect2 id="jails-tuning-utilities">
<title>&os; 所提供的 jail tuning 工具</title>
<para>對於 jail 設定的微調,基本上都是透過設定 &man.sysctl.8; 變數來完成。
系統提供一組 sysctl 的特殊子樹,全部相關的選項都在該子樹內,也就是
&os; kernel 中的 <varname>security.jail.*</varname> 子樹。
下面則是與 jail 相關的主要 sysctl 設定及預設值,這些名稱都相當容易理解,
如欲更進一步的資訊,請參閱 &man.jail.8;&man.sysctl.8; 說明:</para>
<itemizedlist>
<listitem>
<para><varname>security.jail.set_hostname_allowed:
1</varname></para>
</listitem>
<listitem>
<para><varname>security.jail.socket_unixiproute_only:
1</varname></para>
</listitem>
<listitem>
<para><varname>security.jail.sysvipc_allowed:
0</varname></para>
</listitem>
<listitem>
<para><varname>security.jail.enforce_statfs:
2</varname></para>
</listitem>
<listitem>
<para><varname>security.jail.allow_raw_sockets:
0</varname></para>
</listitem>
<listitem>
<para><varname>security.jail.chflags_allowed:
0</varname></para>
</listitem>
<listitem>
<para><varname>security.jail.jailed: 0</varname></para>
</listitem>
</itemizedlist>
<para>系統管理者可在 <emphasis>host system</emphasis>
透過修改這些設定值來增加、取消 Jail 內 <username>root</username>
帳號的預設限制。 請注意:有些限制是不能取消,在 &man.jail.8; 環境的
<username>root</username> 不能掛載或卸載檔案系統。 此外亦不能載入、
卸載 &man.devfs.8; 規則、設定防火牆規則,或執行其他需修改 kernel
資料的管理作業,例如設定 kernel 的 <varname>securelevel</varname>
值。</para>
<para>&os; base system 內附一些基本工具,可用來查閱目前使用中的 jail、
並接上(attach) jail 以執行管理指令。 &man.jls.8;&man.jexec.8;
均屬於 &os; base system 之一,可用來執行一些簡單工作:</para>
<itemizedlist>
<listitem>
<para>列出有在使用的 jail 及其相對應的 jail identifier
(<acronym>JID</acronym>)、<acronym>IP</acronym> address、
hostname、路徑。</para>
</listitem>
<listitem>
<para>接上(Attach)正在運作中的 jail並在其中執行指令以進行管理工作。
這點在當 <username>root</username> 想乾淨關閉 jail 時相當有用,
&man.jexec.8; 也可用在 jail 中啟動 shell 以便對其進行管理,
比如:</para>
<screen>&prompt.root; <userinput>jexec <replaceable>1</replaceable> tcsh</userinput></screen>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="jails-tuning-admintools">
<title>&os; Ports Collection 所提供的高階管理工具</title>
<para>在諸多 third-party 所提供的 jail 管理工具當中,<filename
role="package">sysutils/jailutils</filename> 是最完整也最好用的。
該套件是由一系列 &man.jail.8; 管理小工具所組成的。 詳情請參閱其網站介紹
</para>
</sect2>
</sect1>
<sect1 id="jails-application">
<title>Jail 的應用</title>
<sect2 id="jails-service-jails">
<sect2info>
<authorgroup>
<author>
<firstname>Daniel</firstname>
<surname>Gerzo</surname>
<contrib>Contributed by </contrib>
<!-- 15. May 2007 -->
</author>
</authorgroup>
</sect2info>
<title>Service Jails</title>
<para>本節主要以 &a.simon; 寫的 <ulink
url="http://simon.nitro.dk/service-jails.html"></ulink> 為主,加上
Ken Tom <email>locals@gmail.com</email> 所更新的文章。
本節介紹如何設定 &os;&man.jail.8; 功能來增加額外的安全層面。
這部分假設您系統跑的是 RELENG_6_0 或更新的版本,
並且對本章先前部分均能理解。</para>
<sect3 id="jails-service-jails-design">
<title>Design</title>
<para>Jail 的主要問題之一在於如何對其進行更新、升級和管理。
由於每個 jail 都是從頭重新編譯,對於單一 jail 而言,
升級也許還不是很嚴重的問題,因為更新、升級並不會太麻煩。
但對於一堆 jail 而言,升級不僅會耗費太多時間,並相當枯燥乏味。</para>
<warning>
<para>這些設定的前提是您對 &os; 使用、功能運用上有相當的經驗,
若下面的設定對您來說太過複雜,建議您該考慮用較簡易的系統,像是
<filename role="package">sysutils/ezjail</filename>,其提供更簡單的
&os; jail 管理方式。</para>
</warning>
<para>基本的想法是在不同的 jail 中儘量以安全的方式來共用資源
&mdash; 採用唯讀的 &man.mount.nullfs.8; 掛載,來讓升級更簡單,
並把各個 service 放到不同的 jail 的作法會更加可行。 此外,
其也提供對於如何增加、刪除、升級 jail 的簡便方式。</para>
<note>
<para>service 常見的例子包括:
<acronym>HTTP</acronym> server、<acronym>DNS</acronym>
server、<acronym>SMTP</acronym> server 等等。</para>
</note>
<para>本節介紹的設定目的在於:</para>
<itemizedlist>
<listitem>
<para>建立簡易且容易理解的 jail 架構。 也就是說
<emphasis>不必</emphasis>為每個 jail 都執行完整的 installworld
</para>
</listitem>
<listitem>
<para>讓 jail 的新增、移除更簡單。</para>
</listitem>
<listitem>
<para>讓 jail 的更新、升級更輕鬆。</para>
</listitem>
<listitem>
<para>可以跑自行打造的 &os; 分支。</para>
</listitem>
<listitem>
<para>對安全有更偏執狂的追求,儘可能降低被攻陷的可能。</para>
</listitem>
<listitem>
<para>儘量節省空間與 inode。</para>
</listitem>
</itemizedlist>
<para>如同先前所提到的,這設計主要是靠把唯讀的主要模版
(也就是大家所熟知的 <application>nullfs</application>)掛載到每個
jail並且讓每個 jail 有個可讀、寫的設備,這設備可以是獨立實體硬碟、
、分割區、或以 vnode 為後端的 &man.md.4; 設備。 在本例當中,
我們採用可讀寫的 <application>nullfs</application> 掛載。</para>
<para>下面的表則介紹檔案系統的配置:</para>
<itemizedlist>
<listitem>
<para>每個 jail 都會掛載到 <filename
class="directory">/home/j</filename> 底下的其中一個目錄。</para>
</listitem>
<listitem>
<para><filename class="directory">/home/j/mroot</filename> 則是每個
jail 共用的模版,並對於所有 jail 而言都是唯讀。</para>
</listitem>
<listitem>
<para>每個 jail 在 <filename class="directory">/home/j</filename>
底下都有一個相對應的空目錄。</para>
</listitem>
<listitem>
<para>每個 jail 都會有 <filename
class="directory">/s</filename> 目錄,
該目錄會連到系統的可讀寫部分。</para>
</listitem>
<listitem>
<para>每個 jail 都會在 <filename
class="directory">/home/j/skel</filename> 目錄建立自屬的可讀寫空間
</para>
</listitem>
<listitem>
<para>每個 jailspace (各 jail 可讀寫的部分) 都建在 <filename
class="directory">/home/js</filename>>。</para>
</listitem>
</itemizedlist>
<note>
<para>這邊假設所有 jail 都放在
<filename class="directory">/home</filename> 分割區。 當然,
也可以依自身需求更改,但接下來的例子中,
也要記得修改相對應的地方。</para>
</note>
<!-- Insert an image or drawing here to illustrate the example. -->
</sect3>
<sect3 id="jails-service-jails-template">
<title>建立模版</title>
<para>本節將逐步介紹如何建立 jail 要用的唯讀主模版。</para>
<para>建議先把 &os; 系統升級到最新的 -RELEASE 分支,至於如何做請參閱
Handbook 的
<ulink url="&url.books.handbook;/makeworld.html">相關章節</ulink>
當更新完成之後,就要進行 buildworld 程序,此外還要裝 <filename
role="package">sysutils/cpdup</filename> 套件。
我們將用 &man.portsnap.8; 來下載 &os; Ports Collection
在 Handbook 中對 <ulink
url="&url.books.handbook;/portsnap.html">Portsnap 章節</ulink>
中有相關介紹,初學者可以看看。</para>
<procedure>
<step>
<para>首先,先建立唯讀的目錄結構給 jail 放 &os; binary
接著到 &os; source tree 目錄,並安裝 jail 模版:</para>
<screen>&prompt.root; <userinput>mkdir -p /home/j/mroot</userinput>
&prompt.root; <userinput>cd /usr/src</userinput>
&prompt.root; <userinput>make installworld DESTDIR=/home/j/mroot</userinput></screen>
</step>
<step>
<para>接著跟 &os; source tree 一樣,也把 &os; Ports Collection
放一份供 jail 使用,以備 <application>mergemaster</application>
</para>
<screen>&prompt.root; <userinput>cd /home/j/mroot</userinput>
&prompt.root; <userinput>mkdir usr/ports</userinput>
&prompt.root; <userinput>portsnap -p /home/j/mroot/usr/ports fetch extract</userinput>
&prompt.root; <userinput>cpdup /usr/src /home/j/mroot/usr/src</userinput></screen>
</step>
<step>
<para>建立可讀寫部分的骨架:</para>
<screen>&prompt.root; <userinput>mkdir /home/j/skel /home/j/skel/home /home/j/skel/usr-X11R6 /home/j/skel/distfiles</userinput>
&prompt.root; <userinput>mv etc /home/j/skel</userinput>
&prompt.root; <userinput>mv usr/local /home/j/skel/usr-local</userinput>
&prompt.root; <userinput>mv tmp /home/j/skel</userinput>
&prompt.root; <userinput>mv var /home/j/skel</userinput>
&prompt.root; <userinput>mv root /home/j/skel</userinput></screen>
</step>
<step>
<para><application>mergemaster</application> 來裝漏掉的設定檔。
接下來刪除 <application>mergemaster</application>
所建立的多餘目錄:</para>
<screen>&prompt.root; <userinput>mergemaster -t /home/j/skel/var/tmp/temproot -D /home/j/skel -i</userinput>
&prompt.root; <userinput>cd /home/j/skel</userinput>
&prompt.root; <userinput>rm -R bin boot lib libexec mnt proc rescue sbin sys usr dev</userinput></screen>
</step>
<step>
<para>現在把可讀寫的檔案系統以 symlink 方式連到唯讀的檔案系統。
請確認 symbolic link 是否有正確連到 <filename
class="directory">s/</filename> 目錄,若目錄建立方式不對,
或指向位置不對,可能會導致安裝失敗。</para>
<screen>&prompt.root; <userinput>cd /home/j/mroot</userinput>
&prompt.root; <userinput>mkdir s</userinput>
&prompt.root; <userinput>ln -s s/etc etc</userinput>
&prompt.root; <userinput>ln -s s/home home</userinput>
&prompt.root; <userinput>ln -s s/root root</userinput>
&prompt.root; <userinput>ln -s ../s/usr-local usr/local</userinput>
&prompt.root; <userinput>ln -s ../s/usr-X11R6 usr/X11R6</userinput>
&prompt.root; <userinput>ln -s ../../s/distfiles usr/ports/distfiles</userinput>
&prompt.root; <userinput>ln -s s/tmp tmp</userinput>
&prompt.root; <userinput>ln -s s/var var</userinput></screen>
</step>
<step>
<para>最後則是新增 <filename>/home/j/skel/etc/make.conf</filename>
,並填入以下內容:</para>
<programlisting>WRKDIRPREFIX?= /s/portbuild</programlisting>
<para>要設定 <literal>WRKDIRPREFIX</literal> 才可以讓各 jail
得以順利編譯 &os; ports。請記住 ports 目錄是屬唯讀檔案系統。
而搭配自訂的 <literal>WRKDIRPREFIX</literal> 才可以讓各 jail
在可讀寫空間進行編譯。</para>
</step>
</procedure>
</sect3>
<sect3 id="jails-service-jails-creating">
<title>建立 Jail</title>
<para>現在已經有完整的 &os; jail 模版,可以在
<filename>/etc/rc.conf</filename> 內做相關設定。
下面這例子則示範如何建立 3 個 jail<quote>NS</quote>
<quote>MAIL</quote><quote>WWW</quote></para>
<procedure>
<step>
<para><filename>/etc/fstab</filename> 加上下列設定,
以便讓系統自動掛載各 jail 所需的唯讀模版與讀寫空間:</para>
<programlisting>/home/j/mroot /home/j/ns nullfs ro 0 0
/home/j/mroot /home/j/mail nullfs ro 0 0
/home/j/mroot /home/j/www nullfs ro 0 0
/home/js/ns /home/j/ns/s nullfs rw 0 0
/home/js/mail /home/j/mail/s nullfs rw 0 0
/home/js/www /home/j/www/s nullfs rw 0 0</programlisting>
<note>
<para>分割區的 pass number 標示為 0 就不會在開機時做 &man.fsck.8;
檢查;而分割區的 dump number 標示為 0 則不會被 &man.dump.8;
所備份。
我們並不希望
<application>fsck</application> 檢查
<application>nullfs</application> 的掛載,或者讓
<application>dump</application> 備份 jail 內唯讀的 nullfs 掛載。
這也就是為何上述 <filename>fstab</filename>
每行設定後面都有兩欄為 <quote>0&nbsp;0</quote></para>
</note>
</step>
<step>
<para><filename>/etc/rc.conf</filename> 內設定 jail</para>
<programlisting>jail_enable="YES"
jail_set_hostname_allow="NO"
jail_list="ns mail www"
jail_ns_hostname="ns.example.org"
jail_ns_ip="192.168.3.17"
jail_ns_rootdir="/usr/home/j/ns"
jail_ns_devfs_enable="YES"
jail_mail_hostname="mail.example.org"
jail_mail_ip="192.168.3.18"
jail_mail_rootdir="/usr/home/j/mail"
jail_mail_devfs_enable="YES"
jail_www_hostname="www.example.org"
jail_www_ip="62.123.43.14"
jail_www_rootdir="/usr/home/j/www"
jail_www_devfs_enable="YES"</programlisting>
<warning>
<para>之所以要把
<varname>jail_<replaceable>name</replaceable>_rootdir</varname>
<filename class="directory">/home</filename> 改為 <filename
class="directory">/usr/home</filename> 的原因在於 &os;
預設安裝的 <filename
class="directory">/home</filename> 目錄其實只是指向 <filename
class="directory">/usr/home</filename> 的 symbolic link。 而
<varname>jail_<replaceable>name</replaceable>_rootdir</varname>
變數須為 <emphasis>實體目錄</emphasis> 而非 symbolic link
否則 jail 會拒絕啟動。 可以用 &man.realpath.1;
來決定該變數。 詳情請參閱 &os;-SA-07:01.jail 安全通告。</para>
</warning>
</step>
<step>
<para>替每個 jail 建立必須的唯讀檔案系統掛載點:</para>
<screen>&prompt.root; <userinput>mkdir /home/j/ns /home/j/mail /home/j/www</userinput></screen>
</step>
<step>
<para>為每個 jail 安裝可讀寫的模版。 請注意這時要用 <filename
role="package">sysutils/cpdup</filename>
,它能確保每個目錄都有正確複製。</para>
<!-- keramida: Why is cpdup required here? Doesn't cpio(1)
already include adequate functionality for performing this
job *and* have the advantage of being part of the base
system of FreeBSD? -->
<screen>&prompt.root; <userinput>mkdir /home/js</userinput>
&prompt.root; <userinput>cpdup /home/j/skel /home/js/ns</userinput>
&prompt.root; <userinput>cpdup /home/j/skel /home/js/mail</userinput>
&prompt.root; <userinput>cpdup /home/j/skel /home/js/www</userinput></screen>
</step>
<step>
<para>如此一來就已完成 jail 環境建立,可以準備好要用了。
請先為各 jail 掛載所須的檔案系統,再用
<filename>/etc/rc.d/jail</filename> script 來啟動:</para>
<screen>&prompt.root; <userinput>mount -a</userinput>
&prompt.root; <userinput>/etc/rc.d/jail start</userinput></screen>
</step>
</procedure>
<para>現在 jail 應該就會啟動了。 若要檢查是否有正常啟動,可以用
&man.jls.8; 指令來看,該指令的執行結果應該類似下面:</para>
<screen>&prompt.root; <userinput>jls</userinput>
JID IP Address Hostname Path
3 192.168.3.17 ns.example.org /home/j/ns
2 192.168.3.18 mail.example.org /home/j/mail
1 62.123.43.14 www.example.org /home/j/www</screen>
<para>此時就可以登入各 jail 並新增帳號與設定相關 service 要用的 daemon
。 上面的 <literal>JID</literal> 欄代表正在運作中的 jail 編號。
可用下列指令以在 <literal>JID</literal> 編號 3 的 jail
執行管理工作:</para>
<screen>&prompt.root; <userinput>jexec 3 tcsh</userinput></screen>
</sect3>
<sect3 id="jails-service-jails-upgrading">
<title>升級</title>
<para>有時由於安全問題或者 jail 內要用新功能,而需要把 &os;
系統升級到更新。 這種安裝設計方式讓既有的 jail 升級變得更加容易。
jail 也可以把 service 停機時間(downtime)降到最低,因為 jail
只需在最後關鍵才需要重開。 此外,萬一新版有問題的話,
它也提供輕鬆回溯到舊版的功能。</para>
<procedure>
<step>
<para>首先是照一般方式來升級 host system再新增臨時的唯讀模版
<filename class="directory">/home/j/mroot2</filename></para>
<screen>&prompt.root; <userinput>mkdir /home/j/mroot2</userinput>
&prompt.root; <userinput>cd /usr/src</userinput>
&prompt.root; <userinput>make installworld DESTDIR=/home/j/mroot2</userinput>
&prompt.root; <userinput>cd /home/j/mroot2</userinput>
&prompt.root; <userinput>cpdup /usr/src usr/src</userinput>
&prompt.root; <userinput>mkdir s</userinput></screen>
<para>同樣地,在執行 <maketarget>installworld</maketarget>
時會建立一些用不著的目錄,請把這些砍掉:</para>
<screen>&prompt.root; <userinput>chflags -R 0 var</userinput>
&prompt.root; <userinput>rm -R etc var root usr/local tmp</userinput></screen>
</step>
<step>
<para>重新建立到主系統的可讀寫空間 symlink</para>
<screen>&prompt.root; <userinput>ln -s s/etc etc</userinput>
&prompt.root; <userinput>ln -s s/root root</userinput>
&prompt.root; <userinput>ln -s s/home home</userinput>
&prompt.root; <userinput>ln -s ../s/usr-local usr/local</userinput>
&prompt.root; <userinput>ln -s ../s/usr-X11R6 usr/X11R6</userinput>
&prompt.root; <userinput>ln -s s/tmp tmp</userinput>
&prompt.root; <userinput>ln -s s/var var</userinput></screen>
</step>
<step>
<para>現在可以關閉 jail</para>
<screen>&prompt.root; <userinput>/etc/rc.d/jail stop</userinput></screen>
</step>
<step>
<para>卸載原先的檔案系統:</para>
<!-- keramida: Shouldn't we suggest a short script-based
loop here, instead of tediously copying the same commands
multiple times? -->
<screen>&prompt.root; <userinput>umount /home/j/ns/s</userinput>
&prompt.root; <userinput>umount /home/j/ns</userinput>
&prompt.root; <userinput>umount /home/j/mail/s</userinput>
&prompt.root; <userinput>umount /home/j/mail</userinput>
&prompt.root; <userinput>umount /home/j/www/s</userinput>
&prompt.root; <userinput>umount /home/j/www</userinput></screen>
<note>
<para>可讀寫空間(<filename class="directory">/s</filename>)
是掛載在唯讀檔案系統底下,故要先卸載。</para>
</note>
</step>
<step>
<para>把舊的唯讀系統搬走,換成新的。 如此一來,
可同時保留先前系統的備份,以備萬一升級後有問題可回復。
這邊的命名方式採新唯讀檔案系統的建立時間,此外原先 &os;
Ports Collection 直接搬到新的檔案系統,以節省硬碟空間與 inode
</para>
<screen>&prompt.root; <userinput>cd /home/j</userinput>
&prompt.root; <userinput>mv mroot mroot.20060601</userinput>
&prompt.root; <userinput>mv mroot2 mroot</userinput>
&prompt.root; <userinput>mv mroot.20060601/usr/ports mroot/usr</userinput></screen>
</step>
<step>
<para>現在新的唯讀模版準備好了,只剩下重新掛載以及啟動 jail</para>
<screen>&prompt.root; <userinput>mount -a</userinput>
&prompt.root; <userinput>/etc/rc.d/jail start</userinput></screen>
</step>
</procedure>
<para>最後以 &man.jls.8; 來檢查 jail 是否均正常啟動。
別忘了要在各 jail 內執行 mergemaster還有相關設定檔以及
rc.d scripts 均要更新。</para>
</sect3>
</sect2>
</sect1>
</chapter>