跳过导航链接 | |
退出打印视图 | |
![]() |
在 Oracle Solaris 11.1 中使用映像包管理系统打包和交付软件 Oracle Solaris 11.1 Information Library (简体中文) |
由于大量的自动化,使用 IPS 对软件包打包通常很简单。自动化可以避免重复执行单调的操作,这种重复似乎是大部分打包错误产生的主要原因。
在 IPS 中发布包含以下步骤:
生成软件包清单。
将必要的元数据添加到生成的清单中。
评估相关项。
添加需要的任何侧面或执行器。
验证软件包。
发布软件包。
测试软件包。
最简单的入门方法是将组件文件组织成安装系统上所需的相同目录结构。
有两种方法可用于实现此目的:
如果您要打包的软件已经存在于 tarball 中,则将该 tarball 解压缩到子目录中。对于使用 autoconf 实用程序的许多开源软件包,将 DESTDIR 环境变量设置为指向所需的原型区域可以实现此目的。pkg:/developer/build/autoconf 软件包中提供了 autoconf 实用程序。
在 Makefile 中使用 install 目标。
假定您的软件包含一个二进制文件、一个库和一个手册页,并且要在 /opt 下名为 mysoftware 的目录中安装该软件。在构建区域中创建一个目录,在此目录下,您的软件以以上布局显示。在以下示例中,此目录名为 proto:
proto/opt/mysoftware/lib/mylib.so.1 proto/opt/mysoftware/bin/mycmd proto/opt/mysoftware/man/man1/mycmd.1
使用 pkgsend generate 命令为 proto 区域生成清单。通过 pkgfmt 可对输出软件包清单进行排序,以便该清单可读性更好。有关更多信息,请参见 pkgsend(1) 和 pkgfmt(1) 手册页。
在以下示例中,proto 目录位于当前工作目录中:
$ pkgsend generate proto | pkgfmt > mypkg.p5m.1
输出的 mypkg.p5m.1 文件包含以下行:
dir path=opt owner=root group=bin mode=0755 dir path=opt/mysoftware owner=root group=bin mode=0755 dir path=opt/mysoftware/bin owner=root group=bin mode=0755 file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \ group=bin mode=0644 dir path=opt/mysoftware/lib owner=root group=bin mode=0755 file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \ owner=root group=bin mode=0644 dir path=opt/mysoftware/man owner=root group=bin mode=0755 dir path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \ owner=root group=bin mode=0644
要打包的文件路径在 file 操作中出现了两次:
单词 file 之后的第一个单词说明了 proto 区域中文件的位置。
path= 属性中的路径指定了要安装文件的位置。
使用该双项,您可以在不修改 proto 区域的情况下修改安装位置。假如您要对设计用于安装在其他操作系统上的软件重新打包,此功能可以节省大量时间。
请注意,pkgsend generate 对目录所有者和组都应用了缺省值。对于 /opt,缺省值是不正确的。需要删除该目录,因为它是由已经存在于系统上的其他软件包提供的,并且如果 /opt 的属性和那些已经存在于系统上的属性冲突,则 pkg(1) 将不会安装该软件包。下面将必要的元数据添加到生成的清单中显示了删除不需要的目录的编程方式。
如果文件名中包含等号 (=)、双引号 (") 或空格字符,则 pkgsend 在清单中生成 hash 属性,如下例所示:
$ mkdir -p proto/opt $ touch proto/opt/my\ file1 $ touch proto/opt/"my file2" $ touch proto/opt/my=file3 $ touch proto/opt/'my"file4' $ pkgsend generate proto dir group=bin mode=0755 owner=root path=opt file group=bin hash=opt/my=file3 mode=0644 owner=root path=opt/my=file3 file group=bin hash="opt/my file2" mode=0644 owner=root path="opt/my file2" file group=bin hash='opt/my"file4' mode=0644 owner=root path='opt/my"file4' file group=bin hash="opt/my file1" mode=0644 owner=root path="opt/my file1"
发布软件包(请参见发布软件包)时,hash 属性的值会成为文件内容的 SHA-1 散列,如文件操作中所述。
软件包应该定义以下元数据。有关这些值以及如何设置这些值的更多信息,请参见设置操作。
软件包标识符:FMRI中所介绍的软件包的名称和版本。有关 Oracle Solaris 版本控制的介绍可以在Oracle Solaris 软件包版本控制中找到。
软件包内容的描述。
单行描述概要。
该软件包适用的每种体系结构。如果整个软件包可以安装在任何体系结构中,则可以省略 variant.arch。第 5 章中讨论了生成包含用于不同体系结构的不同组件的软件包。
packagemanager(1) GUI 使用的分组方案。支持的值显示在附录 A中。本节中的示例随机指定了一个等级。
此示例还将 link 操作添加到 /usr/share/man/index.d 中,指向 mysoftware 下的 man 目录。添加需要的任何侧面或执行器中将进一步介绍该链接。
请使用 pkgmogrify(1) 编辑生成的清单,而不要直接修改清单。有关使用 pkgmogrify 修改软件包清单的完整说明,请参见第 6 章。
创建以下 pkgmogrify 输入文件以指定要对清单进行的更改。将此文件命名为 mypkg.mog。在此示例中,使用宏定义体系结构,使用正则表达式匹配从清单中删除 /opt 目录。
set name=pkg.fmri value=mypkg@1.0,5.11-0 set name=pkg.summary value="This is an example package" set name=pkg.description value="This is a full description of \ all the interesting attributes of this example package." set name=variant.arch value=$(ARCH) set name=info.classification \ value=org.opensolaris.category.2008:Applications/Accessories link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man <transform dir path=opt$->drop>
对 mypkg.p5m.1 清单运行 pkgmogrify(mypkg.mog 已更改):
$ pkgmogrify -DARCH=`uname -p` mypkg.p5m.1 mypkg.mog | pkgfmt > mypkg.p5m.2
输出的 mypkg.p5m.2 文件包含以下内容。path=opt 的 dir 操作已删除,并且 mypkg.mog 中的元数据和链接内容已添加到原始的 mypkg.p5m.1 内容中。
set name=pkg.fmri value=mypkg@1.0,5.11-0 set name=pkg.summary value="This is an example package" set name=pkg.description \ value="This is a full description of all the interesting attributes of this example package." set name=info.classification \ value=org.opensolaris.category.2008:Applications/Accessories set name=variant.arch value=i386 dir path=opt/mysoftware owner=root group=bin mode=0755 dir path=opt/mysoftware/bin owner=root group=bin mode=0755 file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \ group=bin mode=0644 dir path=opt/mysoftware/lib owner=root group=bin mode=0755 file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \ owner=root group=bin mode=0644 dir path=opt/mysoftware/man owner=root group=bin mode=0755 dir path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \ owner=root group=bin mode=0644 link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man
使用 pkgdepend(1) 命令可自动生成软件包的相关项。生成的 depend 操作在依赖操作中进行了定义,并在第 4 章中有进一步的讨论。
相关项生成由两个单独的步骤组成:
相关项生成。确定软件依赖的文件。使用 pkgdepend generate 命令。
相关项解析。确定包含软件所依赖的那些文件的软件包。使用 pkgdepend resolve 命令。
在以下命令中,-m 选项导致 pkgdepend 在输出中包含整个清单。-d 选项将 proto 目录传递给命令。
$ pkgdepend generate -md proto mypkg.p5m.2 | pkgfmt > mypkg.p5m.3
输出的 mypkg.p5m.3 文件包含以下内容。pkgdepend 实用程序通过 mylib.so.1 和 mycmd 添加了有关依赖于 libc.so.1 的相关项的表示法。无提示地省略了 mycmd 和 mylib.so.1 之间的内部相关项。
set name=pkg.fmri value=mypkg@1.0,5.11-0 set name=pkg.summary value="This is an example package" set name=pkg.description \ value="This is a full description of all the interesting attributes of this example package." set name=info.classification \ value=org.opensolaris.category.2008:Applications/Accessories set name=variant.arch value=i386 dir path=opt/mysoftware owner=root group=bin mode=0755 dir path=opt/mysoftware/bin owner=root group=bin mode=0755 file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \ group=bin mode=0644 dir path=opt/mysoftware/lib owner=root group=bin mode=0755 file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \ owner=root group=bin mode=0644 dir path=opt/mysoftware/man owner=root group=bin mode=0755 dir path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \ owner=root group=bin mode=0644 link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man depend fmri=__TBD pkg.debug.depend.file=libc.so.1 \ pkg.debug.depend.reason=opt/mysoftware/bin/mycmd \ pkg.debug.depend.type=elf type=require pkg.debug.depend.path=lib \ pkg.debug.depend.path=opt/mysoftware/lib pkg.debug.depend.path=usr/lib depend fmri=__TBD pkg.debug.depend.file=libc.so.1 \ pkg.debug.depend.reason=opt/mysoftware/lib/mylib.so.1 \ pkg.debug.depend.type=elf type=require pkg.debug.depend.path=lib \ pkg.debug.depend.path=usr/lib
为解析相关项,pkgdepend 检查当前安装在用于生成软件的映像中的软件包。缺省情况下, pkgdepend 将输出置于 mypkg.p5m.3.res 中。此步骤需要运行一段时间,因为需要装入有关运行中系统的大量信息。如果希望将此时间分摊到所有的软件包上,可以使用 pkgdepend 实用程序一次性解析多个软件包。一次只对一个软件包运行 pkgdepend 从时间上来看不太高效。
$ pkgdepend resolve -m mypkg.p5m.3
完成后,输出的 mypkg.p5m.3.res 文件包含以下内容。pkgdepend 实用程序将有关依赖于 libc.so.1 的文件相关项的表示法转换为交付该文件的 pkg:/system/library 中的软件包相关项。
set name=pkg.fmri value=mypkg@1.0,5.11-0 set name=pkg.summary value="This is an example package" set name=pkg.description \ value="This is a full description of all the interesting attributes of this example package." set name=info.classification \ value=org.opensolaris.category.2008:Applications/Accessories set name=variant.arch value=i386 dir path=opt/mysoftware owner=root group=bin mode=0755 dir path=opt/mysoftware/bin owner=root group=bin mode=0755 file opt/mysoftware/bin/mycmd path=opt/mysoftware/bin/mycmd owner=root \ group=bin mode=0644 dir path=opt/mysoftware/lib owner=root group=bin mode=0755 file opt/mysoftware/lib/mylib.so.1 path=opt/mysoftware/lib/mylib.so.1 \ owner=root group=bin mode=0644 dir path=opt/mysoftware/man owner=root group=bin mode=0755 dir path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \ owner=root group=bin mode=0644 link path=usr/share/man/index.d/mysoftware target=opt/mysoftware/man depend fmri=pkg:/system/library@0.5.11-0.175.1.0.0.21.0 type=require
您应该使用 pkgdepend 生成相关项,而不是手动声明 depend 操作。由于软件包内容会随着时间而更改,手动相关项可能不正确或没有必要。例如,当应用程序所依赖的文件移动到其他软件包时,任何手动声明的依赖于先前软件包的相关项对于该相关项都将是不正确的。
如果 pkgdepend 无法完全确定相关项,手动声明某些相关项可能会是必要的。在这种情况下,应该向清单中添加解释性注释。
第 5 章和第 7 章中更详细地介绍了侧面和执行器。侧面表示一种操作,该操作不是必要的,可以选择性安装。执行器指定在安装、更新或删除关联操作时必须发生的系统更改。
此示例软件包在 opt/mysoftware/man/man1 中交付了一个手册页。本节说明如何添加侧面以指示手册页是可选的。用户可以选择安装软件包中除手册页以外的所有内容。(用户将侧面设置为 false 时,对于使用该侧面对 file 操作进行标记的所有软件包,不会安装任何手册页。)
要将手册页包含在索引中,安装软件包时,必须重新启动 svc:/application/man-index:default SMF 服务。本节说明如何添加 restart_fmri 执行器以执行该任务。man-index 服务在 /usr/share/man/index.d 中查找指向手册页所在目录的符号链接,将每一个链接的目标添加到其扫描的目录列表中。为了将手册页包含在索引中,此示例软件包包含从 /usr/share/man/index.d/mysoftware 到 /opt/mysoftware/man 的链接。包含该链接和执行器是软件自组装中所讨论的自组装的一个很好示例,用于 Oracle Solaris OS 的整个打包过程。
您可以使用的一组 pkgmogrify 转换位于 /usr/share/pkg/transforms 中。这些转换用于打包 Oracle Solaris OS,并在第 6 章中有详细介绍。
文件 /usr/share/pkg/transforms/documentation 中包含的转换类似于此示例中设置手册页侧面和重新启动 man-index 服务所需的转换。由于此示例将手册页交付到 /opt,documentation 转换必须按如下所示进行修改。这些修改的转换包括正则表达式 opt/.+/man(/.+)?,该表达式与 opt 下包含 man 子目录的所有路径相匹配。将以下修改的转换保存到 /tmp/doc-transform:
<transform dir file link hardlink path=opt/.+/man(/.+)? -> \ default facet.doc.man true> <transform file path=opt/.+/man(/.+)? -> \ add restart_fmri svc:/application/man-index:default>
使用以下命令可将这些转换应用到清单:
$ pkgmogrify mypkg.p5m.3.res /tmp/doc-transform | pkgfmt > mypkg.p5m.4.res
输入 mypkg.p5m.3.res 清单包含以下三个与手册页相关的操作:
dir path=opt/mysoftware/man owner=root group=bin mode=0755 dir path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \ owner=root group=bin mode=0644
应用转换后,输出 mypkg.p5m.4.res 清单包含以下修改的操作:
dir path=opt/mysoftware/man owner=root group=bin mode=0755 facet.doc.man=true dir path=opt/mysoftware/man/man1 owner=root group=bin mode=0755 \ facet.doc.man=true file opt/mysoftware/man/man1/mycmd.1 path=opt/mysoftware/man/man1/mycmd.1 \ owner=root group=bin mode=0644 \ restart_fmri=svc:/application/man-index:default facet.doc.man=true
出于效率考虑,在评估相关项前,初次添加元数据时可能已经添加了这些转换。
发布前的最后一步是对清单运行 pkglint(1),以便发现在发布和测试前可以识别的错误。pkglint 可以发现的某些错误在发布时或用户尝试安装软件包时也会发现,但是您当然希望在软件包设计期间尽可能早地识别错误。
pkglint 报告的错误示例包括:
交付的文件已经属于其他软件包。
有关共享、引用计数操作的元数据(如目录)存在不一致情况。此错误的示例在生成软件包清单结尾有介绍。
可以使用以下模式之一运行 pkglint:
直接针对软件包清单运行。此模式通常足以快速地检查清单的有效性。
针对软件包清单运行,同时引用软件包系统信息库。发布到系统信息库前,至少需要使用该模式一次。
通过引用系统信息库,pkglint 可以执行额外检查以确保软件包和系统信息库中的其他软件包之间可以很好地交互。
使用 pkglint -L 命令可显示 pkglint 所执行检查的完整列表。pkglint(1) 手册页中提供了有关如何启用、禁用和绕过特定检查的详细信息。该手册页还详细介绍了如何扩展 pkglint 以运行额外检查。
以下输出显示了示例清单的问题:
$ pkglint mypkg.p5m.4.res Lint engine setup... Starting lint run... WARNING pkglint.action005.1 obsolete dependency check skipped: unable to find dependency pkg:/system/library@0.5.11-0.175.1.0.0.21.0 for pkg:/mypkg@1.0,5.11-0
此警告对于此示例可接受。pkglint.action005.1 警告显示 pkglint 无法找到此示例软件包依赖的名为 pkg:/system/library@0.5.11-0.175.1.0.0.21.0 的软件包。该相关项软件包在软件包系统信息库中,但无法找到,因为调用 pkglint 时仅使用清单文件作为参数。
在以下命令中,-r 选项引用了一个包含相关项软件包的系统信息库。-c 选项指定了一个本地目录,用于缓存来自 lint 和引用系统信息库的软件包元数据:
$ pkglint -c ./solaris-reference -r http://pkg.oracle.com/solaris/release mypkg.p5m.4.res
IPS 提供了三种不同的软件包交付方式:
发布到本地基于文件的系统信息库中。
发布到远程基于 HTTP 的系统信息库中。
转换为 .p5p 软件包归档文件。
一般情况下,对于测试软件包来说,发布到基于文件的系统信息库就足够了。
如果必须将软件包传输到无法访问软件包系统信息库的其他计算机上,则将一个或多个软件包转换为软件包归档文件会很方便。
也可以直接将软件包发布到 HTTP 系统信息库,该系统信息库托管在包含 svc:/application/pkg/server 服务的读/写实例的计算机上,由该计算机运行 pkg.depotd(1M)。
通常不建议发布到 HTTP 系统信息库,因为通过 HTTP 发布时,不对传入软件包进行授权或验证检查。如果无法对文件系统信息库进行 NFS 或 SMB 访问,那么在安全的网络中或者当测试多个计算机上的同一个软件包时,发布到 HTTP 系统信息库会很方便。
通过 HTTP 或 HTTPS 安装软件包是可行的。
使用 pkgrepo(1) 命令可创建并管理系统信息库。在系统上选择一个位置,创建一个系统信息库,然后为该系统信息库设置缺省发布者:
$ pkgrepo create my-repository $ pkgrepo -s my-repository set publisher/prefix=mypublisher $ ls my-repository pkg5.repository
使用 pkgsend(1) 命令可发布示例软件包,然后使用 pkgrepo 检查该系统信息库:
$ pkgsend -s my-repository publish -d proto mypkg.p5m.4.res pkg://mypublisher/mypkg@1.0,5.11-0:20120331T034425Z PUBLISHED $ pkgrepo -s my-repository info PUBLISHER PACKAGES STATUS UPDATED mypublisher 1 online 2012-03-31T03:44:25.235964Z
如果需要,可以使用 pkg.depotd 通过 HTTP 或 HTTPS 提供文件系统信息库访问。
使用软件包归档文件,您可以在一个文件中分发多组软件包。使用 pkgrecv(1) 命令可根据软件包系统信息库创建软件包归档文件,或根据软件包归档文件创建软件包系统信息库。
软件包系统信息库不可用时,可以轻松地从现有的 Web 站点下载软件包归档文件,复制到 USB key,或刻录到 DVD 中以进行安装。
以下命令根据上节中创建的简单系统信息库创建软件包归档文件:
$ pkgrecv -s my-repository -a -d myarchive.p5p mypkg Retrieving packages for publisher mypublisher ... Retrieving and evaluating 1 package(s)... DOWNLOAD PKGS FILES XFER (MB) SPEED Completed 1/1 3/3 0.7/0.7 17.9k/s ARCHIVE FILES STORE (MB) myarchive.p5p 14/14 0.7/0.7
使用 pkgrepo 命令可列出系统信息库或归档文件中的最新可用软件包:
$ pkgrepo -s my-repository list '*@latest' PUBLISHER NAME O VERSION mypublisher mypkg 1.0,5.11-0:20120331T034425Z $ pkgrepo -s myarchive.p5p list '*@latest' PUBLISHER NAME O VERSION mypublisher mypkg 1.0,5.11-0:20120331T034425Z
此输出可用于构建脚本,以便使用给定系统信息库中所有软件包的最新版本创建归档文件。
可以使用 -g 选项向 pkg install 和其他 pkg 操作提供临时系统信息库或软件包归档文件。此类临时系统信息库和归档文件无法用于包含子映像或父映像的系统(例如,包含非全局区域的系统),因为不会使用该发布者信息临时配置系统信息库。非全局区域与全局区域之间为子/父关系。但是,软件包归档文件可以在非全局区域中设置为本地发布者的源。
软件包开发的最后一步是测试已发布的软件包是否已正确打包。
要在不需要 root 特权的情况下测试安装,需要为测试用户指定 Software Installation(软件安装)配置文件。使用 usermod 命令的 -P 选项可为测试用户指定 Software Installation(软件安装)配置文件。
注 - 如果该映像已安装了子映像(非全局区域),则无法使用带 -g 选项的 pkg install 命令测试该软件包的安装。您必须在该映像中配置 my-repository 系统信息库。
将 my-repository 系统信息库中的发布者添加到该映像中的已配置发布者:
$ pfexec pkg set-publisher -p my-repository pkg set-publisher: Added publisher(s): mypublisher
可以使用 pkg install -nv 命令查看安装命令将执行的操作,而不进行任何更改。以下命令实际上安装软件包:
$ pfexec pkg install mypkg Packages to install: 1 Create boot environment: No Create backup boot environment: No Services to change: 1 DOWNLOAD PKGS FILES XFER (MB) SPEED Completed 1/1 3/3 0.0/0.0 0B/s PHASE ITEMS Installing new actions 15/15 Updating package state database Done Updating image state Done Creating fast lookup database Done Reading search index Done Updating search index 1/1
检查交付到系统上的软件:
$ find /opt/mysoftware/ /opt/mysoftware/ /opt/mysoftware/bin /opt/mysoftware/bin/mycmd /opt/mysoftware/lib /opt/mysoftware/lib/mylib.so.1 /opt/mysoftware/man /opt/mysoftware/man/man-index /opt/mysoftware/man/man-index/term.doc /opt/mysoftware/man/man-index/.index-cache /opt/mysoftware/man/man-index/term.dic /opt/mysoftware/man/man-index/term.req /opt/mysoftware/man/man-index/term.pos /opt/mysoftware/man/man1 /opt/mysoftware/man/man1/mycmd.1
执行器重新启动 man-index 服务后,除了二进制文件和手册页,系统同时生成了手册页索引。
pkg info 命令显示添加到软件包的元数据:
$ pkg info mypkg Name: mypkg Summary: This is an example package Description: This is a full description of all the interesting attributes of this example package. Category: Applications/Accessories State: Installed Publisher: mypublisher Version: 1.0 Build Release: 5.11 Branch: 0 Packaging Date: March 31, 2012 03:44:25 AM Size: 0.00 B FMRI: pkg://mypublisher/mypkg@1.0,5.11-0:20120331T034425Z
查询通过 mypkg 交付的文件时,pkg search 命令将返回命中:
$ pkg search -l mycmd.1 INDEX ACTION VALUE PACKAGE basename file opt/mysoftware/man/man1/mycmd.1 pkg:/mypkg@1.0-0