

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 示例 8：管理服务
<a name="cookbooks-101-basics-services"></a>

**重要**  
该 AWS OpsWorks Stacks 服务于 2024 年 5 月 26 日终止，新客户和现有客户均已禁用。我们强烈建议客户尽快将其工作负载迁移到其他解决方案。如果您对迁移有疑问，请通过 re [AWS : Post 或通过 Pre](https://repost.aws/) mium Su [AWS pp](https://aws.amazon.com/support) ort 与 AWS 支持 团队联系。

应用程序服务器等软件包通常具有必须启动、停止、重新启动的关联服务。例如，您需要在安装软件包后或在实例完成启动后启动 Tomcat 服务，并在每次修改配置文件时重新启动该服务。本主题以 Tomcat 应用程序服务器为例，讨论了如何在 Linux 实例上管理服务的基础知识。服务资源在 Windows 实例上的工作方式大致相同，但在细节上存在一些差异。有关更多信息，请参阅 [https://docs.chef.io/chef/resources.html#service](https://docs.chef.io/chef/resources.html#service)。

**注意**  
该示例执行极低限度的 Tomcat 安装，刚刚足以演示如何使用 `service` 资源的基础知识。有关如何对功能更强的 Tomcat 服务器实施配方的示例，请参阅[创建自定义 Tomcat 服务器层](create-custom.md)。

**Topics**
+ [定义和启动服务](#cookbooks-101-basics-services-service)
+ [使用通知来启动或重新启动服务](#cookbooks-101-basics-services-notifies)

## 定义和启动服务
<a name="cookbooks-101-basics-services-service"></a>

本节介绍了有关如何定义和启动服务的基础知识。

**开始使用**

1. 在 `opsworks_cookbooks` 目录中，创建名为 `tomcat` 的实例并导航到其中。

1. 将包含以下内容的 `metadata.rb` 文件添加到 `tomcat`。

   ```
   name "tomcat"
   version "0.1.0"
   ```

1. 如[示例 1：安装软件包](cookbooks-101-basics-packages.md)中所述，初始化和配置 Test Kitchen，并从 `platforms` 列表中删除 CentOS。

1. 将 `recipes` 子目录添加 `tomcat` 中。

您使用 [https://docs.chef.io/chef/resources.html#service](https://docs.chef.io/chef/resources.html#service) 资源管理服务。以下默认配方会安装 Tomcat 并启动该服务。

```
execute "install_updates" do
  command "apt-get update"
end

package "tomcat7" do
    action :install
end

include_recipe 'tomcat::service'

service 'tomcat' do
  action :start
end
```

此配方会执行以下操作：
+ `execute` 资源会运行 `apt-get update` 以安装当前系统更新。

  对于此示例中使用的 Ubuntu 实例，必须在安装 Tomcat 之前先安装这些更新。其他系统的要求可能会有所不同。
+ `package` 资源会安装 Tomcat 7。
+ 包含的 `tomcat::service` 配方会定义该服务，稍后将讨论此内容。
+ `service` 资源会启动 Tomcat 服务。

  您还可以使用此资源发出其他命令，例如停止和重新启动服务。

以下示例展示了 `tomcat::service` 配方。

```
service 'tomcat' do
  service_name "tomcat7"
  supports :restart => true, :reload => false, :status => true
  action :nothing
end
```

此配方将创建 Tomcat 服务定义，具体如下：
+ 其他配方使用资源名称 `tomcat` 来引用该服务。

  例如，`default.rb` 会引用 `tomcat` 以启动服务。
+ `service_name` 资源指定服务名称。

  当您在实例上列出服务时，Tomcat 服务将被命名为 tomcat7。
+ `supports` 会指定 Chef 管理服务的 `restart`、`reload` 和 `status` 命令的方式。
  + `true` 表示 Chef 可以使用 init 脚本或其他服务提供程序来运行该命令。
  + `false` 表示 Chef 必须尝试以其他方式运行该命令。

请注意，`action` 设置为 `:nothing`，它会指示资源不执行任何操作。服务资源确实支持诸如 `start` 和 `restart` 等操作。但是，本说明书遵循以下标准做法：使用不执行任何操作的服务定义，并在其他地方启动或重新启动服务。启动或重新启动服务的每个配方首先必须定义该服务，因此最简单的方法是，将服务定义放在单独的配方中，并根据需要将其纳入到其他配方中。

**注意**  
为简便起见，此示例的默认配方会在运行服务定义后使用 `service` 资源启动服务。生产实施通常会通过使用 `notifies` 来启动或重新启动服务 (稍后将进行讨论)。

**运行配方**

1. 创建包含默认配方示例的 `default.rb` 文件，并将其保存至 `recipes`。

1. 创建包含服务定义示例的 `service.rb` 文件，并将其保存至 `recipes`。

1. 运行 `kitchen converge`，然后登录到实例，并运行以下命令，以验证相应服务是否正在运行。

   ```
   sudo service tomcat7 status
   ```

**注意**  
如果您单独从 `default.rb` 运行 `service.rb`，则必须编辑 `.kitchen.yml`，以便将 `tomcat::service` 添加至运行列表中。但是，当您包含某个配方时，在执行该配方之前，会将其代码纳入到父配方中。因此 `service.rb` 基本上是 `default.rb` 的一部分，不需要提供单独的运行列表项。

## 使用通知来启动或重新启动服务
<a name="cookbooks-101-basics-services-notifies"></a>

生产实施通常不使用 `service` 启动或重新启动服务。相反，它们会将 `notifies` 添加到任意几个资源中。例如，如果要在修改配置文件后重新启动服务，请将 `notifies` 包括在相关 `template` 资源中。在显式重新启动服务方面，与使用 `notifies` 资源相比，使用 `service` 具有如下优势。
+ `notifies` 元素仅在关联配置文件发生更改时才会重新启动服务，因此不会导致不必要的服务重新启动的风险。
+ 在每次运行结束时，Chef 最多重新启动服务一次，无论运行包含多少个 `notifies` 均是如此。

  例如，Chef 运行可能包含多个模板资源，其中每个模板资源均会修改不同的配置文件，并要求在文件发生更改时重新启动服务。但是，您通常只需要在 Chef 运行结束时重新启动服务一次。否则，您可能会尝试重新启动尚未从之前的重新启动中完全恢复正常运行的服务，从而可能导致错误。

本示例会修改 `tomcat::default`，以包括使用 `template` 来重新启动服务的 `notifies` 资源。实际的示例会使用一个模板资源来创建其中一个 Tomcat 配置文件的自定义版本，但是这些文件相当长且复杂。为简便起见，该示例仅使用来自[从模板创建文件](cookbooks-101-basics-files.md#cookbooks-101-basics-files-template)的模板资源。它与 Tomcat 没有任何关系，但它提供了一种简单的方式来显示如何使用 `notifies`。有关如何使用模板创建 Tomcat 配置文件的示例，请参阅[Setup 配方](create-custom-setup.md)。

**设置说明书**

1. 将 `templates` 子目录添加到 `tomcat`，并将 `default` 子目录添加到 `templates`。

1. 将 `example_data.json.erb` 模板从 `createfile` 说明书复制到 `templates/default` 目录。

1. 将 `attributes` 子目录添加到 `tomcat` 中。

1. 将 `default.rb` 属性文件从 `createfile` 说明书复制到 `attributes` 目录。

以下配方使用 `notifies` 重新启动 Tomcat 服务。

```
execute "install_updates" do
  command "apt-get update"
end

package "tomcat7" do
    action :install
end

include_recipe 'tomcat::service'

service 'tomcat' do
  action :enable
end

directory "/srv/www/shared" do
  mode 0755
  owner 'root'
  group 'root'
  recursive true
  action :create
end

template "/srv/www/shared/example_data.json" do
  source "example_data.json.erb"
  mode 0644
  variables(
    :a_boolean_var => true,
    :a_string_var => "some string"
  )
  only_if {node['createfile']['install_file']}
  notifies :restart, resources(:service => 'tomcat')
end
```

该示例将来自[从模板创建文件](cookbooks-101-basics-files.md#cookbooks-101-basics-files-template)的配方合并到前一节的配方中，其中包含如下两个重大更改：
+ `service` 资源仍然存在，但该资源的用途目前略有不同。

  `:enable` 操作会在启动时启用 Tomcat 服务。
+ 模板资源现在包含 `notifies`，它会在 `example_data.json` 发生更改时重新启动 Tomcat 服务。

  这样可确保在每次配置更改后首次安装和重新启动 Tomcat 时启动该服务。

**运行配方**

1. 运行 `kitchen destroy`，以便从全新的实例开始。

1. 将 `default.rb` 中的代码替换为前面的示例。

1. 运行 `kitchen converge`，然后登录到实例，并验证相应服务是否正在运行。

**注意**  
如果要重新启动服务，但配方不包含诸如 `template` 这样支持 `notifies` 的资源，则可以改用虚拟 `execute` 资源。例如  

```
execute 'trigger tomcat service restart' do
  command 'bin/true'
  notifies :restart, resources(:service => 'tomcat')
end
```
`execute` 资源必须具有 `command` 属性，即使您仅将该资源用作运行 `notifies` 的一种方法也是如此。此示例通过运行 `/bin/true` 来解决上述要求，该命令是一个只返回成功代码的 shell 命令。