如何将系统服务控制从脚本迁移到服务管理工具

作者:Suzanne Zorn

如何将基于脚本的服务从旧版 Oracle Solaris 或其他 UNIX 环境(如
HP-UX 11i)迁移到 Oracle Solaris 11 服务管理工具 (SMF)。


2012 年 5 月发布

在 Oracle Solaris 11 中管理服务
   SMF 关键组件
向 SMF 添加服务
   创建 SMF 清单文件
   创建启动方法
向 SMF 迁移服务
   通过 SMF 监视服务
   SMF 控制的服务的自动重启演示
总结
另请参见
关于作者

本文介绍了如何将为旧版 Oracle solaris 或其他 UNIX 环境编写的原有 /etc/rc* 脚本控制的服务迁移到 Oracle Solaris 11 服务管理工具 (SMF)。建议管理员使用 svcbundle 实用程序快速生成清单并将其安装到系统中,如在 Oracle Solaris 11 中使用 svcbundle 创建 SMF 清单和配置文件中所述。

OTN 旨在帮助您充分了解 Oracle 技术,以作出明智决策。本网站提供文章、软件下载、文档等。立即加入,获取完成工作所需的技术资源。

Oracle Solaris 11 仍然允许原有 /etc/rc* 脚本启动和停止其服务。但由于 SMF 极大地简化了系统服务的监视和管理,更提供了故障检测、依赖性检查和自动重启,因此值得将这些服务的控制迁移到 SMF。

在 Oracle Solaris 11 中管理服务

在许多 UNIX 环境中,通常使用 /etc/rc* 目录中的脚本启动和停止服务。转换到运行级别时,系统将在这些目录中查找以字母 SK 开头的脚本,找到后按顺序执行这些脚本。

管理员可以在这些目录中添加自定义脚本,但没有相关的管理工具。管理员需要负责确保序号不发生冲突,通过预先执行脚本确保全部必要服务的可用,还必须手动监视和重启故障服务。

SMF 简化了管理,提供了更好的服务控制、监视和管理方法。利用 SMF 可以定义服务之间的关系,可以确保服务仅在其依赖的其他服务联机时才会启动。SMF 不再采用顺序运行脚本的方式,而是可以并行启动服务,从而加快了系统的启动速度。

SMF 还包含一个管理界面,支持轻松管理和控制服务,支持配置更改在重新引导后仍然保持有效。SMF 还可以监视服务,可按照配置自动重启失败的服务,从而提高服务的可用性和可靠性。

SMF 关键组件

SMF 服务具有以下相关组件:

  • 一个描述该服务的清单文件(使用 XML 编写),包括服务名称、如何停止和启动服务及其依赖的其他服务等信息。清单文件存放在 /lib/svc/manifest(首选)或 /var/svc/manifest 子目录下。
  • 定义如何启动、停止和重新启动服务的一个或多个方法。方法通常存储在 /lib/svc/method 子目录下。
  • 由方法为执行服务而调用的一个或多个可执行文件(后台程序)。
  • SMF 用于存储服务输出和状态的日志文件。日志文件存储在 /var/svc/log 目录下,可以使用 svcs -x 命令查找。
  • 一个故障管理资源标识符 (FMRI),用于识别每个特定的服务实例。例如,FMRI svc:/network/rpc/bind:default 包含三部分,用分号分隔:
    • svc 将其标识为服务。
    • /network/rpc/bind 标识该服务。
    • default 标识服务实例(服务的第一个实例通常标记为默认实例)。

向 SMF 添加服务

本文档假设您当前有由 /etc/rc* 脚本启动的服务。

在此示例中,我们从一个名为 myservice 的示例服务开始。这项服务仅用于演示 SMF 功能。我们的服务运行 prstat 可执行文件,由以下 /etc/rc3.d/S99my_service 脚本启动:

#!/bin/sh

if [ -x /usr/bin/prstat ]; then
    /usr/bin/prstat -a > /dev/null &
fi
exit 0

每当系统重新引导或转换到多用户模式(运行级别 3)时,/etc/rc3.d/S* 脚本就会依次运行。我们的 S99myservice shell 脚本运行时,将启动 prstat 可执行文件。可以通过重新引导系统并检查正在运行的进程来确认:

# ps -A | grep prstat
1595 console     0:00 prstat

要将任何服务迁移到 SMF 控制,需要满足以下三个要求:

  • 一个可执行文件(持续运行的后台程序,无控制 tty
  • 一个方法(shell 脚本),用于启动和停止这个可执行文件
  • 一个 XML 文件,用于为 SMF 描述该服务

我们的示例服务目前是由 /etc/rc* 脚本启动的,因此已经满足了前两个条件:可执行文件 (/usr/bin/prstat) 和启动该可执行文件的 shell 脚本 (/etc/rc3.d/S99myservice)。最后一项要求就是创建那个 XML 文件。

创建 SMF 清单文件

SMF 清单文件是向 SMF 描述服务的 XML 文件,其中列出了要运行的可执行文件及其任意依赖项等信息。示例服务所用的清单文件如清单 1 所示。后面介绍了各关键元素。

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM
    /usr/share/lib/xml/dtd/service_bundle.dtd.1">

<service_bundle type="manifest" name="myservice">
  <service name="site/myservice" type="service" version="1">
    <create_default_instance enabled="false" />

    <!-- Dependencies -->
    <dependency 
        name="filesystem-local" grouping="require_all" 
        restart_on="restart" type="service">
        <service_fmri value="svc:/system/filesystem/local:default" />
    </dependency>

    <!-- Execution method for start and stop -->
    <exec_method 
         type="method" name="start" 
         exec="/lib/svc/method/myservice.sh" timeout_seconds="60" >    
      <method_context>
          <method_credential user="root" group="root" />
      </method_context>
    </exec_method>

    <exec_method 
       type="method" name="stop" exec=":kill -9"
       timeout_seconds="60" >
    </exec_method>

    <template>
       <common_name>
         <loctext xml:lang="C">My example service</loctext>
       </common_name>
       <documentation>
          <manpage title="No man" section="99" manpath="/dev/null" />
       </documentation>
    </template>
  </service>
</service_bundle>

清单 1.示例的清单文件

清单文件包含以下元素:

  • XML 标头。标准 XML 标头是:

    <?xml version="1.0"?>
    <!DOCTYPE service_bundle SYSTEM 	
             /usr/share/lib/xml/dtd/service_bundle.dtd.1">
    
  • 服务包。包含服务包的名称,还可以包含零个或多个服务元素。(本例中包含一个服务元素,用于描述我们的服务。)

     <service_bundle type="manifest" name="myservice">
    
  • 服务。指定服务的名称,也包含多个子元素,用于指定依赖项、启动方法等信息。按照惯例,服务将被划分为不同类别,用于标识服务的一般用途。(/lib/svc/manifest 中列出了服务类别,其中包括应用、里程碑、平台、系统、设备、网络和站点)。本例的名称 site/myservice 表明它属于站点类别,名为 myservice

    <service name="site/myservice" type="service" version="1">
    
  • 默认启动标志。该标志元素指定该服务是否应默认启动。我们的示例创建了一个名为 default 的实例,默认为被禁用:

    <create_default_instance enabled="false" />
    
  • 服务依赖项。指定我们的服务所依赖的服务。在本例中,我们指定我们的服务依赖于本地文件系统服务。属性 restart_on=restart 指定在本地文件系统服务因任何原因重新启动时我们的服务也应重新启动。

    其他可能的值包括:none(从不因依赖项状态变化而重新启动服务)、error(如果依赖项是由于硬件故障重新启动,则重新启动服务)和 refresh(如果依赖项因任何原因刷新或重新启动,则重新启动服务)。

    grouping=require_all 属性指定我们的服务所依赖的所有服务都必须联机:

        <dependency 
            name="filesystem-local" grouping="require_all" 
            restart_on="restart" type="service">
            <service_fmri value="svc:/system/filesystem/local:default" />
        </dependency>
    
  • 执行方法。描述用于启动、停止或重启服务的方法。在本例中,我们指定了启动脚本的名称,指定了 60 秒的超时值,并表明我们的方法应以 root 用户和 root 组运行:

    <exec_method 
         type="method" name="start" 
         exec="/lib/svc/method/myservice.sh" timeout_seconds="60" >    
         <method_context>
             <method_credential user="root" group="root" />
         </method_context>
    </exec_method>
    

    对于停止方法,我们告知 SMF 执行 kill 命令来停止服务:

    <exec_method 
        type="method" name="stop" exec=":kill -9" timeout_seconds="60" >
    </exec_method>
    
  • 模板。包含关于服务的元数据,包括可本地化的字符串和文档链接。

:由于本例默认创建一个实例,因此并不需要包括显式实例元素。如果需要启动服务的多个实例,则需要包括以下元素:

<instance name="myservice_instance1" enabled="false" />

本例只包含可用 SMF 清单功能的一个子集。Oracle 白皮书“如何创建 Oracle Solaris 服务管理工具清单”给出了更详细的说明。Oracle Solaris 11 系统的 /usr/share/lib/xml/dtd/service_bundle.dtd.1 文件中给出了完整的 XML 语法。

创建启动方法

向 SMF 添加服务之前,需要确定启动服务可执行文件的方法。我们的启动脚本至少应能启动该服务。其中还可以包含停止和重启该服务的选项。

在本例中,我们可以使用现有 /etc/rc3.d/S99myservice 脚本,只添加一个特定于 SMF 的退出代码:

#!/bin/sh
. /lib/svc/share/smf_include.sh

if [ -x /usr/bin/prstat ]; then
    /usr/bin/prstat -a > /dev/null &
fi

exit $SMF_EXIT_OK

总之,您可以使用一个脚本来全面管理服务,也可以不同的脚本启动和停止服务。虽然大多数服务都使用脚本,但并非严格要求所有情况都使用脚本:如果可以用一个命令启动、停止或刷新服务,则可在清单中指定该命令,删除该脚本。

接下来的几节将逐步介绍将示例服务从原有 /etc/rc* 脚本迁移到 SMF 管理的过程。

向 SMF 迁移服务

此过程假设我们有一项服务当前使用原有 /etc/rc* 脚本自动启动。我们的示例使用 /etc/rc3.d/S99myservice 脚本。

  1. 我们可以使用 svcs 命令看到,我们的服务已由 Oracle Solaris 11 启动,prstat 后台程序正在运行:

    # ls /etc/rc3.d/S99myservice
    /etc/rc3.d/S99myservice
    # svcs S99myservice
    STATE        STIME     FMRI
    Legacy_run   11:41:19  lrc:/etc/rc3_3/S99myservice
    # ps -A | grep prstat
    375 ?        0:00 prstat
    
  2. 首先,我们停止服务(本例中通过结束可执行文件 prstat 实现)。随后需要删除或重命名 /etc/rc* 目录中的任何相关脚本,这样 Oracle Solaris 11 每次重新引导系统时不会再自动启动该服务,例如:

    # pkill prstat 
    # ps -A | grep prstat
    # 
    # mv /etc/rc3.d/S99myservice /etc/rc3.d/_S99myservice
    
  3. 此过程假定我们已经为我们的服务创建了启动脚本和 XML 清单文件,如前几节所述。本例中的启动方法是 /lib/svc/method/myservice.sh

    # ls -l /lib/svc/method/myservice.sh
    -rwxr-xr-x  1 root   root   133 Mar 28 10:30 /lib/svc/method/myservice.sh
    

    :确保您的脚本具有执行权限以及恰当的用户和组所有权。

  4. 将您服务的清单 (XML) 文件复制到 /lib/svc/manifest/site 子目录:

    # ls /lib/svc/manifest/site
    myservice.xml
    
  5. 运行 svccfg validate 命令检查清单文件是否存在语法错误。无输出则表明没有发现错误:

    # svccfg validate /lib/svc/manifest/site/myservice.xml
    #
    
  6. 使用 svcadm restart 命令让 SMF 了解您的新服务:

    # svcadm restart manifest-import
    Loading smf(5) service descriptions: 1/1
    

    :与 Oracle Solaris 10 相比,在 Solaris 11 中向 SMF 添加新服务的过程发生了变化。在 Oracle Solaris 11 中,建议将清单存储在标准位置 /lib/svc/manifest 和 /var/svc/manifest,其中首选 /lib/svc/manifest。在 Oracle Solaris 11 中,如果您的清单存储的标准位置,则不需要(也不建议)再使用 svcadm import 命令。而 svcadm restart 命令将对 SMF 信息库执行同步操作,并识别存储在标准位置的清单文件发生的变更。

  7. 使用 svcs 命令查看所添加的新服务的状态。虽然 SMF 已经知道了我们的服务,但尚未启用该服务:

    # svcs myservice
    STATE     STIME     FMRI
    disabled  10:54:08  svc:/site/myservice:default
    
  8. 使用 svcadm enable 命令启用新服务:

    # svcadm enable myservice
    # svcs myservice
    STATE     STIME     FMRI
    enabled   10:55:03  svc:/site/myservice:default
    
  9. 确认我们的可执行文件(本例中使用的是 prstat 命令)已启动:

    # ps -A | grep prstat
    2135 ?        0:00 prstat
    

通过 SMF 监视服务

我们的服务处于 SMF 控制之后,就可以使用 svcs 命令监视其工作了。

  • 要查看有关特定服务的全部可用信息,可使用带有 -l 选项的 svcs 命令,并指定名称服务,如清单 2 所示:

    # svcs -l myservice
    fmri         svc:/site/myservice/default
    name         A simple example service
    enabled      true
    state        online
    next_state   none
    state_time   March 30, 2012 01:13:54 PM PDT
    logfile      /var/svc/log/site-myservice:default.lot
    restarter    svc:/system/svc/restarter:default
    contract_id  131
    manifest     /lib/svc/manifest/site/myservice.xml
    dependency   require_all/none   
                   svc:/system/system/filesystem/local:default (online)
    

    清单 2.查看服务的全部可用信息

  • 可以使用带 -x 选项的 svcs 命令显示服务的其他信息。这在排除服务问题时将非常有用:

    # svcs -x myservice
    svc:/site/myservice:default (A simple example service)
     State: online since March 30, 2012 01:13:54 PM PDT
        See: man -M /dev/null -s 99 No man
        See: /var/svc/log/site-myservice:default.log
    Impact: None.
    
  • 要显示与服务相关的进程 ID,使用带 -p 选项的 svcs 命令:

    # svcs -p myservice
    STATE       STIME
    Online      13:13:54 svc:/site/myservice:default
                13:13:54     1321 prstat 
    

我们还可以使用 svccfg setnotify 命令修改 SMF 信息库中的事件通知参数,例如什么时候诊断或解决问题。例如,诊断出 SMF 服务发生问题时,默认的行为是发送电子邮件到 root@localhost。以下命令将使 SMF 改为将电子邮件发送到 user1@example.com

# svccfg setnotify problem-diagnosed mailto:user1@example.com

您可以全局设置通知,也可以针对各特定服务设置,还可以为 SMF 状态转换(降级和脱机)设置通知。请参阅 svccfg(1M) 帮助页面了解详细信息。

SMF 控制的服务的自动重启演示

SMF 监视服务,并自动重启任何停止的可执行文件,无论失败原因是管理员或配置错误、软件故障,还是未纠正的硬件错误。下面的示例演示了这种自动重启。

  1. 首先,确认可执行文件正在运行。在我们的示例服务中,启动 prstat 可执行文件:

    # ps -A | grep prstat
    2135 ?        0:00 prstat
    
  2. 结束可执行文件:

    # kill -9 2135
    
  3. 再次检查运行的进程:

    # ps -A | grep prstat
    2155 ?        0:00 prstat
    

    prstat 可执行文件使用 kill 命令停止,但由 SMF 自动重启。(进程 ID 分别是 2135 和 2155,您可以由此判断出两者属于不同的进程。)

SMF 为每个服务实例维护一个日志文件。排查服务问题时,这些日志文件将非常有用。日志文件存储在 /var/svc/log 目录中。存储本示例服务的日志文件是 /var/svc/log/site-myservice:default.log

其中的条目详细记录了此前调用过哪些启动和停止方法,并提供有关服务状态变化的信息。例如,执行上述结束服务可执行文件后,日志文件中将创建如下条目。SMF 注意到发生了失败,就调用停止方法,随后自动调用启动方法来重启服务:

# tail -4 /var/svc/log/site-myservice:default.log
[ Mar 29 11:33:23 Stopping because all processes in service exited. ]
[ Mar 29 11:33:23 Executing stop method (:kill). ]
[ Mar 29 11:33:23 Executing start method ("/lib/svc/method/myservice.sh"). ]
[ Mar 29 11:33:23 Method "start" exited with status 0. ]

总结

本文介绍了如何将过去使用原有 /etc/rc* 脚本启动的服务迁移到 SMF 控制。尽管文中给出的简单示例是完整的,但受篇幅所限,本文无法演示 SMF 的所有功能,也无法介绍 XML 清单文件的所有元素。您可以通过“另请参见”部分中的链接,找到有关创建 SMF 清单文件和利用 SMF 管理服务的更多信息。此外,该部分还提供了记录清单文件格式和 SMF 相关命令的联机帮助页面的链接。

本文参考了 Brian Down(Oracle Solaris 服务管理工具简化系统和服务管理,2010 年 6 月)和 Rob Romack(Solaris 10 操作系统中的服务管理工具,2006 年 2 月)的文章,作者特此向两位专家表示感谢。

另请参见

下面列出了 Oracle Solaris 服务管理工具相关的资源:

以下帮助页面包含有关 SMF 和服务清单文件格式的信息:

以下是有关 Oracle Solaris 11 的一些资源:

关于作者

Suzanne Zorn 已从事计算机技术文档写作和编辑的达 20 多年。此前,Suzanne 担任过 Sun Microsystems 专业服务部的专业顾问,专门从事系统配置和规划。Suzanne 拥有巴克内尔大学的计算机科学与工程学士学位以及伦斯勒理工学院的计算机科学硕士学位。

修订版 1.1,2014 年 4 月 28 日

要了解所有 Oracle 技术中与系统管理员相关的内容,请在 FacebookTwitter 上关注 OTN Systems。