From Fedora Project Wiki

< Zh

前言

這只是幫助對打包、編譯、測試有興趣,英語程度卻有困難的朋友,一個簡略的 Mock 使用流程;由於我也是翻譯既有英文文檔的原因,一切以英文原版作準:

Using Mock to test package builds

在此謝謝您的耐心閱讀!任何翻譯謬誤或意見回饋敬請不吝指正。以下為原文翻譯。


本頁收集了 mock 使用者覺得有用的資訊。

甚麼是 Mock ?

Mock 讀取一個 srpm 檔案,然後在一個 chroot 上編譯。這確保你的 BuildRequires 內容正確,亦即是在沒有遺漏任何依存套件的情況下,無誤地完成編譯。

我如何設立 Mock?

首先,安裝 mock 套件,它由 Fedora 套件集提供。

預設設定

使用 mock 的時候,您可以使用 "-r" 選項選擇特定的測試設定。 如果一個特定設定會被系統使用者經常使用,您可以把它設定為預設:

# cd /etc/mock
# ln -s --force SOMECONFIG.cfg default.cfg

設立本地鏡像

如果您需要設立本地鏡像,請閱讀:

我應如何使用 Mock ?

在您的 CVS 沙盤 (sandbox) 外使用 Mock

在 mock 群組裏加入您的使用者名稱

usermod -a -G mock myusername

用 'rpmbuild -bs' 命令加入您的 srpm 檔案,然後跳到您的 srpm 檔案建立的文件夾位置。

現在您可以輸入以下命令開始 mock

mock -r <configfile> rebuild package-1.2-3.src.rpm

<configfile> 是位於 /etc/mock/ 裏,設定檔案的名稱 (不用包括 .cfg 延伸檔名).

如果使用 0.8.8 以前的 mock 版本或者帶有 python 2.4 的系統,需要在 x86_64 上編譯 i386 套件的話,於 mock 命令行前置 setarch i386

setarch i386 mock -r <configfile> rebuild package-1.2-3.src.rpm

雖然新版本的 mock 不再需要 setarch 命令, 但是加入了也無傷大雅。

在您的 CVS 沙盤 (sandbox) 使用 Mock

您只需輸入 'make mockbiuld' 開始 mock 編譯。使用建構 (architecture) 會根據您開始 mock 編譯的文件夾被自動選擇。

mock 0.8.x 或以後版本的快取

Mock 0.8.x 引入三種不同的快取類類: 1) 根目錄快取 (root cache), 2) yum 快取, and 3) ccache.

設定這些快取請閱讀 /etc/mock/defaults.cfg 裏的文檔。 您可以更改儲存快取的文件夾位置,儲存快取的最長時間,及空間使用上限 (限 ccache)。

根目錄快取 (Root cache)

從 mock 0.5 開始,它可以自動快取標準編譯根目錄 (standard buildroot) 裏,一個本地 tar 檔案的每個環境參數 (/var/lib/mock/cache/$CONFIG/root_cache/*)。然後它解開這個 tar 檔案把編譯根目錄 (buildroot) 填入,而不是每次以重新下載準備它。當在根目錄快取 (root cache) 中觸開了編譯根目錄 (buildroot),mock 進行一次 yum update 以確保編譯根目錄在安裝額外的 BuildRequires 以作套件編譯前,處於最更新的狀態。

根目錄快取在 mock 0.8.x 或以後版本預設開啟。要關閉它請閱讀 /etc/mock/defaults.cfg 裏的文檔。根目錄快取能全域或個別 chroot (per-chroot) 關閉。根目錄快取每十五天會被自動刪除及重新建立,防立它變得太過時。

緊記根目錄快取會影您編譯的重複性,尤其是在 RPMs 會經常更新的環境下 (例如:rawhide);在重複性最重為重要的環境下,應關閉根目錄快取。

yum 快取

預設 yum 會儲存下載了的 RPM 到 /var/cache/yum 下的文件夾裏。 yum 快取提供掛載 /var/cache/yum chroot 到一個 chroot 環境以外的共用文件夾,讓隨後的編譯儲存及重複使用。這確保 yum 不須在每次編譯的時候從網絡重新下載每個 RPM。這個功能預設開啟。

ccache

cchache 工具,包裹傳到編譯器(像 'gcc')的呼叫,然後進行輸出快取。如果被呼叫同一個程式第二次(帶有一樣的命令參數、 gcc 版本、及 header 檔案),ccache 將會抓取快取的版本,而不會重新編譯。

用 Squid 加快 Mock 下傳套件

上面的編譯根目錄 (buildroots) 快取技巧會比單獨使用 squid 要快,但是您也可以用 squid 作為已快取的編譯根目錄 (buildroot) 的輔助, 尤其是當您有着比較慢的 Internet 連線。

根目錄快取 (root cache) 將會包含標準編譯根目錄套件 (standard buildroot packages) 。可是當它變舊,解開它後 yum update 可能會必須更新大量套件。再者,有些套件不在標準編譯根目錄 (standard buildroot) 裏,卻經常需要用到 (e.g. pkgconfig)。這樣每個套件的編譯,可由於 squid 快取提供代替從 Internet 下傳而加快。

squid 套件可從 Fedora 套件集提供安裝。

/etc/squid/squid.conf 一些地方需要更改:

  • 最大物件體積 (Maximum Object Size) 。 正常來說要 4MB。不過有些基礎套件像 glibc 可以超過 16MB,如果您要編像 Eclipse 插件將是 60MB。因此把它設大一些。

maximum_object_size 409600 KB

  • 快取替換規則 (Cache Replacement Policy) 。 正常來說 lru 足夠。不過在我們的情況,我們希望大型的物件保留時間長一些,儘可能下傳比較小的物件。

cache_replacement_policy heap LFUDA

  • 快取體積 (Cache Size) 。 正常體積為 100MB。 沒有辦法,這個最少要 1GB,假若您定期編譯多個 Fedora 版本及多種架構。

cache_dir ufs /var/spool/squid 1000 16 256

接着啟動 squid ,再設定它在開機時啟動。

要編譯的使用者自動使用 squid 快取,輸入:

echo export http_proxy=\"http://localhost:3128\" >> /home/build/.bash_profile

如果您只想使用 squid 在特定 mock 設定 (也許您有某些發行版的本地鏡像又不需要 squid 給它們),您可以在 mock 設定檔案的 yum.conf 部分,設立代理伺服器設定;而不用設立 http_proxy 環境變數:

config_opts['yum.conf']  = """
[main] 
...
proxy=http://localhost:3128/

...
"""

更改 /etc/mock/*.cfg 以停用鏡像列表

不要使用 mirrorservice.org 鏡像; 它以 HTTP header "Cache-Control: no-store" 阻止順流快取

如果您使用 squid ,又不想 mock+squid 用上隨選鏡像下載套件,可以更改 /etc/mock/*.cfg 的設定檔案,在 baseurl 項使用對您而言最快的鏡像,而不用 mirrorlist 裏的鏡像。

使用 tmpfs 減少讀寫儲存器

tmpfs 是否仍是首選為未知數,不過現在 autocache 運作良好及成為標準功能了。

在有足夠記憶體的時候 (1.5-2 GB) ,使用 tmpfs 能夠有效加速 'prep' 階段。一台配備 1.5GB 記憶體的 Celeron 2.8 GHz 電腦,再次編譯時填入 buildroot 只須花上 2-5s (秒)。

您可以掛載 /var/lib/mock 成 tmpfs,或者在 /var/lib/mock 掛載每一個編譯文件夾成個別 tmpfs 檔案系統。後者讓您得以使用以上的 autocache 及把它儲存到磁碟,而不是到 tmpfs 。如果您經常刪除及重建 autocaches often,把它們放在 tmpfs 就很合理。否則,您應該各自編譯文件夾 tmpfs 掛載方式 (per-build-directory tmpfs mounts) 。

SELinux 下使用 Mock

SELinux 與像 mock 的 chroot-ed 環境下共用,有着一些問題;例如需要用 chroot 文件夾前輟 (directory prefix) 重製 file context,這是系統管理員的惡夢。雖然這個方法非常簡單,但是它只適用於 targeted 規則 (policy): 預先請取一個令所以子進程以為 SELinux 是在關閉狀態的空殼 (dummy) libselinux 。 同時 mock 它以潛水 (unconfined) 進程運行,這樣一般沒有問題。

SELinux 記憶體保護的問題

然而, FC5 以後, SELinux unconfined_t domain 不再被 SELinux 完全隠藏 (unconfined); 記憶體保護 就是為了保護使用者進程免於各種入侵而被編寫。 這表示最少兩類在 FC5 上使用 mock 的問題: 1. 當 正在為遺產 (legacy) 發行版編譯套件,編譯過程會牽涉讀取舊的共用函數庫 (libraries) ,它們都沒有各自像「可執行碼」及「可寫入資料」的區分 (sections)。這引致在 unconfined_t domain 運作的進程試圖讀取一個函數庫的時候得到 execmod 回絶,除非該函數庫被標示了 textrel_shlib_t。 1. 當使用 mono 編譯套件(這也許也適用於 java ), mono 進程會如常地運行它自身比較少限制的 domain (mono_t) ;在 mock 下運行, monounconfined_t domain 裏運行,這樣會招致 execstackexecheap 回絶。 雖則這些檢查可以經由 SELinux booleans 關閉,這不是對每個進程應有的對待。 有另一個方法,就是確保所有檔案都已經在 chroot 被正確標示,與及 SELinux domain 在需要的時候轉移。然而,由於進程在 mock 下運行是由處於 SELinux 關閉狀態的空殼 (dummy) libselinux 指示,從而讓這方法不可行。

mock 用 SELinux 規則 (policy) 組件

以下解決問題的方法,在建立一個 mock 用的 SELinux 規則 (policy) 的同時有以下兩個考量:

  1. 它在自身的 domain (mock_t) 運作,就像其他如果運行的進程一樣不被限制 (unconstrained);這代表它准許
  2. 它用特別的 context type mock_var_lib_t 標示經已安裝在 /var/lib/mock (就是 mock 設立它的 chroot 環境的位置) 的檔案,讓 mock_t domain 內的進程得到 execmod 允許。

這個解決方法足夠地放鬆 SELinux 保護讓 mock 能夠工作,不用妥協對一般 unconfined domain 的負擔。

安裝規則 (policy) 組件:

# make -f /usr/share/selinux/devel/Makefile
Compliling targeted mock module
/usr/bin/checkmodule:  loading policy configuration from tmp/mock.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 5) to tmp/mock.mod
Creating targeted mock.pp policy package
rm tmp/mock.mod.fc tmp/mock.mod
Warning.png
selinux-policy-develcheckpolicy 套件皆必要

如果規則 (policy) 組件在 mock 套件安裝之前讀取, 在安裝的時候 /var/lib/mock 會被標示為 mock_var_lib_t/usr/bin/mock 會被標示為 mock_exec_t。否則,就必須使用 restorecon 修復檔案 contexts:

# restorecon -R /var/lib/mock /usr/bin/mock
Note.png
這個規則應該也能在 mach 作用,只需加入以下兩行到 mock.fc
/usr/bin/mach       -- gen_context(system_u:object_r:mock_exec_t,s0)
/var/lib/mach(/.*)?    gen_context(system_u:object_r:mock_var_lib_t,s0)

作為一個 chroot 沙盤 (sandbox) 工具使用 mock

Mock 可以用來建立 chroots 測試東西,不只是用來編譯套件。以下為扼要步驟:

  • 建立一個設定檔案,指到您選擇的一個或多個包含您測試套件的 repo。
  • mock -r <設定檔名稱> init
  • /usr/sbin/mock-helper yum --installroot /var/lib/mock/<設定檔名稱>/root install <您的套件名稱>
  • mock -r <設定檔名稱> shell

為甚麼不直接 chroot 而要 mock 代勞 (shell)?要 mock 代勞 (to "shell") 讓 mock 建立您大概會在 chroot 裏需要的掛載點 (mountpoints)。如果您想手動管理每個掛載,您可以放心去做。