

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

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

**重要**  
 AWS OpsWorks Stacks 此服務已於 2024 年 5 月 26 日終止，並已針對新客戶和現有客戶停用。我們強烈建議客戶盡快將其工作負載遷移至其他解決方案。如果您對遷移有任何疑問，請透過 [AWS re：Post](https://repost.aws/) 或透過 [AWS Premium Support](https://aws.amazon.com/support) 聯絡 AWS 支援 團隊。

應用程式伺服器等套件，通常會有相關聯的服務，必須啟動、停止、重新啟動等等。例如，在安裝套件或執行個體完成開機之後，您需要啟動 Tomcat 服務，每次修改組態檔案後也要重新啟動服務。本主題以 Tomcat 應用程式伺服器為例，討論如何在 Linux 執行個體上管理服務的基本概念。細節上雖有一些差異，但 service 資源的作用在 Windows 執行個體上極其相似。如需詳細資訊，請參閱[https://docs.chef.io/chef/resources.html#service](https://docs.chef.io/chef/resources.html#service)。

**注意**  
此範例執行 Tomcat 最小安裝，僅足以示範如何使用 `service` 資源的基本概念。如需如何實作配方以取得更多 Tomcat 伺服器功能的範例，請參閱[建立自訂 Tomcat 伺服器 Layer](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. 初始化及設定 Test Kitchen (如[範例 1：安裝套件](cookbooks-101-basics-packages.md)中所述)，並從 `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` 元素只會在相關聯的組態檔案變更時才會重新啟動服務，所以沒有重新啟動不必要服務的風險。
+ 無論回合包含多少個 `notifies`，Chef 在每個回合結束時最多重新啟動服務一次。

  例如，Chef 執行可能包含多項範本資源，它們每一個都會修改不同的組態檔案，檔案變更後需要重新啟動服務。不過，在 Chef 執行結束後，您通常只會想要重新啟動服務一次。否則，您可能嘗試重新啟動在前面重新啟動中尚未完全運作的服務，這會導致錯誤。

此範例會修改 `tomcat::default` 以包含 `template` 資源，使用 `notifies` 重新啟動服務。實際範例會使用範本資源建立其中一個 Tomcat 組態檔案的自訂版本，但這些檔案又長又複雜。為求簡化，此範例只使用[從範本建立檔案](cookbooks-101-basics-files.md#cookbooks-101-basics-files-template)中的範本資源。它和 Tomcat 沒有任何關係，但會提供簡單的方式，示範如何使用 `notifies`。如需如何使用範本建立 Tomcat 組態檔案的範例，請參閱[安裝配方](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 命令只會傳回成功代碼。