

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

# 自定义堆栈 OpsWorks
<a name="customizing"></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 支持 团队联系。

OpsWorks Stacks 内置层提供的标准功能足以满足多种用途。但是，您可能会遇到以下一种或多种情况：
+ 某个内置层的标准配置只是够用，但不够理想；您想要针对特定要求优化它。

  例如，您可能希望为工作进程的最大数量或 `keepalivetimeout` 值等设置指定您自己的值，从而调整 Static Web Server 层的 Nginx 服务器配置。
+ 某个内置层的功能很好，但您希望通过安装更多程序包或运行一些自定义安装脚本来扩展它。

  例如，您可能希望通过还安装 Redis 服务器来扩展 PHP App Server 层。
+ 您有一些不由任何内置层处理的要求。

  例如， OpsWorks Stacks 不包括某些常用数据库服务器的内置层。您可以创建一个自定义层来将这些服务器安装在该层的实例上。
+ 您正在运行一个 Windows 堆栈，该堆栈仅支持自定义层。

OpsWorks Stacks 提供了多种自定义图层的方法，以满足您的特定要求。以下按照提高复杂性和增强功能的顺序列出了一些示例：

**注意**  
其中一些方法仅适用于 Linux 堆栈。有关详细信息，请参阅以下主题。
+ 使用自定义 JSON 覆盖默认 OpsWorks 堆栈设置。
+ 使用可覆盖默认 OpsWorks 堆栈设置的属性文件实现自定义 Chef 食谱。
+ 使用覆盖或扩展默认 OpsWorks Stacks 模板的模板实现自定义 Chef 食谱。
+ 使用运行 shell 脚本的简单配方实施自定义 Chef 说明书。
+ 使用执行创建和配置目录、安装程序包、创建配置文件、部署应用程序等任务的配方实施自定义 Chef 说明书。

您还可以覆盖配方，具体取决于堆栈的 Chef 版本和操作系统。
+ 对于 Chef 0.9 和 11.4 堆栈，您无法通过实施具有与内置配方相同的说明书和配方名称的自定义配方来覆盖内置配方。

  对于每个生命周期事件， OpsWorks Stacks 始终首先运行内置配方，然后运行任何自定义配方。由于这些 Chef 版本不会运行一个具有相同说明书和配方名称的配方两次，因此内置配方优先运行，而自定义配方不会执行。
+ 您可以在 Chef 11.10 堆栈上覆盖内置配方。

  有关更多信息，请参阅 [说明书安装和优先顺序](workingcookbook-chef11-10.md#workingcookbook-chef11-10-override)。
+ 您无法在 Windows 堆栈上覆盖内置配方。

   OpsWorks Stacks 处理 Chef 在 Windows 堆栈中运行的方式不允许覆盖内置配方。

**注意**  
由于许多技术都使用自定义食谱，因此[说明书和诀窍](workingcookbook.md)如果您还不熟悉食谱的实现，则应先阅读。 [说明书基础知识](cookbooks-101-basics.md)提供了实现自定义食谱的详细教程介绍，并[实现堆栈食谱 OpsWorks](cookbooks-101-opsworks.md)介绍了有关如何为 OpsWorks Stacks 实例实现食谱的一些细节。

**Topics**
+ [通过覆盖属性 OpsWorks 来自定义堆栈配置](workingcookbook-attributes.md)
+ [使用自定义模板扩展 OpsWorks 堆栈配置文件](workingcookbook-template-override.md)
+ [扩展层](workingcookbook-extend.md)
+ [创建自定义 Tomcat 服务器层](create-custom.md)
+ [堆栈配置和部署属性](workingcookbook-json.md)

# 通过覆盖属性 OpsWorks 来自定义堆栈配置
<a name="workingcookbook-attributes"></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 支持 团队联系。

**注意**  
对于 Windows 堆栈和 Chef 12 Linux 堆栈， OpsWorks Stacks 使用单独的 Chef 运行来制作内置食谱和自定义食谱。这意味着，您无法使用此节中讨论的方法来覆盖 Windows 堆栈和 Chef 12 Linux 堆栈的内置属性。

配方和模板取决于实例的各种 Chef 属性或堆栈特定信息 (如层配置或应用程序服务器设置)。这些属性具有多个源：
+ **自定义 JSON** （可选）-您可在创建、更新或克隆堆栈时或部署应用程序时指定自定义 JSON 属性。
+ **堆栈配置属性** —OpsWorks 堆栈定义这些属性以保存堆栈配置信息，包括您通过控制台设置指定的信息。
+ **部署属性** — AWS OpsWorks 为 Deploy 事件定义与部署相关的属性。
+ **说明书属性** 内置说明书和自定义说明书通常包含一个或多个[属性文件](workingcookbook-installingcustom-components-attributes.md)，这些文件中包含表示说明书特定值（如应用程序服务器配置设置）的属性。
+ **Chef** - Chef 的 [Ohai 工具](http://docs.chef.io/resource_ohai.html)定义了表示各种系统配置设置 (如 CPU 类型和安装的内存) 的属性。

有关堆栈配置和部署属性以及内置说明书属性的完整列表，请参阅[堆栈配置和部署属性：Linux](attributes-json-linux.md) 和[内置说明书属性](attributes-recipes.md)。有关 Ohai 属性的更多信息，请参阅 [Ohai](https://docs.chef.io/ohai.html)。

当[生命周期事件](workingcookbook-events.md)（如部署或配置）出现时，或您运行[堆栈命令](workingstacks-commands.md)（如 `execute_recipes` 或 `update_packages`）时， OpsWorks Stacks 将执行以下操作：
+ 向每个受影响实例上的代理发送相应命令。

  代理将运行适当的配方。例如，对于部署事件，代理将运行内置部署配方，接着运行任何自定义部署配方。
+ 将任何自定义 JSON 和部署属性与堆栈配置属性进行合并，然后在实例上安装它们。

自定义 JSON 中的属性、堆栈配置和部署属性、说明书属性以及 Ohai 属性将会合并到一个*节点对象*中，从而为配方提供属性值。涉及到堆栈配置属性时，包括任何自定义 JSON，实例实际上是无状态的。当您运行某个部署或堆栈命令时，关联的配方将使用通过该命令下载的堆栈配置属性。

**Topics**
+ [属性优先顺序](workingcookbook-attributes-precedence.md)
+ [使用自定义 JSON 覆盖属性](workingcookbook-json-override.md)
+ [使用自定义 OpsWorks Cookbook 属性覆盖堆栈属性](workingcookbook-cookbook-attributes.md)

# 属性优先顺序
<a name="workingcookbook-attributes-precedence"></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 支持 团队联系。

如果一个属性是唯一定义的，Chef 则会简单地将它并入到节点对象中。但是，任何属性源可定义任何属性，因此有可能同一个属性会具有多个使用不同的值的定义。例如，内置 `apache2` 说明书定义 `node[:apache][:keepalive]`，但是您也可在自定义 JSON 或自定义说明书中定义该属性。如果一个属性具有多个定义，则将按下文中描述的顺序对这些定义进行评估，节点对象将接收具有最高最先顺序的定义。

属性的定义如下所示：

```
node.type[:attribute][:sub_attribute][:...]=value
```

如果一个属性有多个定义，则该类型决定哪个定义具有优先级，并将该定义合并到节点对象中。 OpsWorks 堆栈使用以下属性类型：
+ **default**-这是最常见的类型，并且它实际上意味着“如果属性尚未定义，请使用此值。” 如果属性的所有定义都是 `default` 类型，则评估顺序中的第一个定义具有优先顺序并且后续值将被忽略。请注意， OpsWorks Stacks 将所有堆栈配置和部署属性定义设置为`default`类型。
+ **normal**-此类型的属性将覆盖评估顺序中之前定义的任何 `default` 或 `normal` 属性。例如，如果第一个属性来自内置说明书并且具有 `default` 类型，第二个是具有 `normal` 类型的用户定义属性，则第二个定义具有优先顺序。
+ **set** -这是您可能会在早期说明书中看到的已弃用类型。它已由具有相同的优先顺序的 `normal` 取代。

Chef 支持多种其他属性类型，包括优先于所有其他属性定义的 `automatic` 类型。Chef 的 Ohai 工具生成的属性定义均为 `automatic` 类型，因此它们实际上是只读的。这通常不是问题，因为没有理由重写它们，而且它们与 OpsWorks Stacks 的属性不同。但是，您应谨慎为您的自定义说明书属性命名，以便将它们与 Ohai 属性区分开。有关更多信息，请参阅[关于属性](http://docs.chef.io/attributes.html)。

**注意**  
Ohai 工具是您可通过命令行运行的可执行文件。要列出某个实例的 Ohai 属性，请登录该实例并在终端窗口中运行 `ohai`。请注意，此操作将生成一个非常长的输出。

下面是将各种属性定义并入到节点对象中的步骤：

1. 将任何自定义堆栈配置属性合并到堆栈配置和部署属性中。

   可为堆栈或某个特殊部署设置自定义 JSON 属性。它们在评估顺序中优先并且实际上为 `normal` 类型。如果一个或多个堆栈配置属性也是在自定义 JSON 中定义的，则自定义 JSON 值将优先。否则， OpsWorks Stacks 只是将自定义 JSON 属性并入到堆栈配置中。

1. 将任何部署自定义 JSON 属性合并到堆栈配置和部署属性中。

   部署自定义 JSON 属性实际上也是 `normal` 类型，因此它们优先于内置和自定义堆栈配置 JSON 以及内置部署 JSON。

1. 将堆栈配置和部署属性合并到实例的节点对象中。

1. 将实例的内置说明书属性合并到节点对象中。

   内置说明书属性均为 `default` 类型。如果一个或多个内置说明书属性也是在堆栈配置和部署属性中定义的(通常因为您使用自定义 JSON 定义它们)，堆栈配置定义将优先于内置说明书定义。所有其他内置说明书属性将简单地合并到节点对象中。

1. 将实例的自定义说明书属性合并到节点对象中。

   自定义说明书属性通常是 `normal` 或 `default` 类型。唯一属性将合并到节点对象中。如果步骤 1 至步骤 3 中还定义了任何自定义说明书属性 (通常是因为您使用自定义 JSON 定义了它们)，则优先顺序取决于自定义说明书属性的类型：
   + 步骤 1-步骤 3 中定义的属性优先于自定义说明书 `default` 属性。
   + 自定义说明书 `normal` 属性优先于步骤 1 - 步骤 3 中的定义。

**重要**  
请勿使用自定义说明书 `default` 属性覆盖堆栈配置或内置说明书属性。由于自定义说明书属性将最后进行评估，因此 `default` 属性具有最低的优先顺序，并且无法覆盖任何属性。

# 使用自定义 JSON 覆盖属性
<a name="workingcookbook-json-override"></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 支持 团队联系。

**注意**  
由于 OpsWorks Stacks 处理 Windows 堆栈的 Chef 运行方式与 Linux 堆栈不同，因此你不能将本节中讨论的技术用于 Windows 堆栈。

重写 OpsWorks Stacks 属性的最简单方法是在自定义 JSON 中对其进行定义，该属性优先于堆栈配置和部署属性以及内置和自定义食谱`default`属性。有关更多信息，请参阅 [属性优先顺序](workingcookbook-attributes-precedence.md)。

**重要**  
您应谨慎地覆盖堆栈配置和部署属性。例如，覆盖 `opsworks` 命名空间中的属性可能会影响内置配方。有关更多信息，请参阅 [堆栈配置和部署属性](workingcookbook-json.md)。

您还可使用自定义 JSON 来定义唯一属性 (通常用于将数据传递到您的自定义配方)。这些属性将简单地并入到节点对象中，并且配方可通过使用标准 Chef 节点语法来引用它们。

## 如何指定自定义 JSON
<a name="workingcookbook-json-override-specify"></a>

要使用自定义 JSON 来覆盖某个属性值，您必须先确定该属性的完全限定属性名称。然后，您创建一个包含要覆盖、设置为您的首选值的属性的 JSON 对象。为方便起见，[堆栈配置和部署属性：Linux](attributes-json-linux.md) 和[内置说明书属性](attributes-recipes.md)文档一般使用堆栈配置、部署和内置说明书属性，包括其完全限定名称。

对象的父子关系必须对应于适当的完全限定的 Chef 节点。例如，假设您需要更改以下 Apache 属性：
+ [`keepalivetimeout`](attributes-recipes-apache.md#attributes-recipes-apache-keep-timeout) 属性，其节点为 `node[:apache][:keepalivetimeout]` 并且具有默认值 `3`。
+ `logrotate` [`schedule`](attributes-recipes-apache.md#attributes-recipes-apache-log-schedule) 属性，其节点为 `node[:apache][:logrotate][:schedule]`，并且具有默认值 `"daily"`。

要覆盖这些属性并将值分别设置为 `5` 和 `"weekly"`，可使用以下自定义 JSON：

```
{
  "apache" : {
    "keepalivetimeout" : 5,
    "logrotate" : {
       "schedule" : "weekly"
    }
  }
}
```

## 何时指定自定义 JSON
<a name="workingcookbook-json-override-when"></a>

您可为下列任务指定自定义 JSON 结构：
+ [创建新堆栈](workingstacks-creating.md)
+ [更新堆栈](workingstacks-edit.md)
+ [运行堆栈命令](workingstacks-edit.md)
+ [克隆堆栈](workingstacks-cloning.md)
+ [部署应用程序](workingapps-deploying.md)

对于每项任务， OpsWorks Stacks 都会将自定义 JSON 属性与堆栈配置和部署属性合并，然后将其发送到实例，然后合并到节点对象中。但是，请注意以下事项：
+ 如果您在创建、克隆或更新堆栈时指定自定义 JSON，则这些属性将会合并到用于所有后续事件和堆栈命令的堆栈配置和部署属性中。
+ 如果您为部署指定自定义 JSON，则这些属性将会合并到仅用于相应的事件的堆栈配置和部署属性中。

  如果您想要为后续部署使用这些自定义属性，必须再次显式指定自定义 JSON。

请务必记住，这些属性仅在配方使用它们时才会影响实例。如果您覆盖某个属性值，但没有后续配方引用该属性，则更改不会产生影响。您必须确保在关联的配方运行之前发送自定义 JSON，或者确保重新运行适当的配方。

## 自定义 JSON 的最佳实践
<a name="workingcookbook-json-override-best"></a>

你可以使用自定义 JSON 来覆盖任何 OpsWorks Stacks 属性，但是手动输入信息有点麻烦，而且不受任何形式的源代码控制。自定义 JSON 最适合以下用途：
+ 您只想覆盖少量属性，并且您无需使用自定义说明书。

  通过自定义 JSON，您可避免仅为了覆盖一些属性而设置和维护说明书存储库所带来的开销。
+ 敏感值，如密码或身份验证密钥。

  说明书属性存储在一个存储库中，因此所有敏感信息都有泄露风险。可以改为定义使用虚拟值的属性，然后使用自定义 JSON 设置真实值。
+ 预计会变化的值。

  例如，建议的做法是通过不同的开发和暂存堆栈来支持您的生产堆栈。假设这些堆栈支持某个用于接受付款的应用程序。如果您使用自定义 JSON 来指定付款终端节点，则可以为您的暂存堆栈指定一个测试 URL。当您准备好将更新后的堆栈迁移到生产堆栈时，可使用相同的说明书并使用自定义 JSON 来将付款终端节点设置为生产 URL。
+ 特定于某个特殊堆栈或部署命令的值。

# 使用自定义 OpsWorks Cookbook 属性覆盖堆栈属性
<a name="workingcookbook-cookbook-attributes"></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 支持 团队联系。

**注意**  
对于 Windows 堆栈， OpsWorks Stacks 使用单独的 Chef 运行来生成内置食谱和自定义食谱。这意味着，您无法使用此节中讨论的方法来覆盖 Windows 堆栈的内置属性。

自定义 JSON 是覆盖 OpsWorks Stacks 堆栈配置和内置食谱属性的便捷方法，但它有一些限制。具体而言，您必须在每次使用时手动输入自定义 JSON，因此您没有管理定义的稳健方式。更好的方式一般是使用自定义说明书属性文件来覆盖内置属性。这样做可让您将定义置于源代码管理之下。

使用自定义属性文件覆盖 OpsWorks 堆栈定义的过程非常简单。

**重写 OpsWorks Stacks 属性定义**

1. 如[说明书和诀窍](workingcookbook.md)中所述设置说明书存储库。

1. 使用与包含您要覆盖的属性的内置说明书相同的名称创建一个说明书。例如，要覆盖 Apache 属性，说明书应命名为 apache2。

1. 将 `attributes` 文件夹添加到说明书并将一个名为 `customize.rb` 的文件添加到该文件夹中。

1. 将一个属性定义添加到您要覆盖、设置为您的首选值的每个内置说明书属性的文件中。该属性必须是`normal`类型或更高的类型，并且与相应的 OpsWorks Stacks 属性具有完全相同的节点名称。有关 OpsWorks 堆栈属性的详细列表，包括节点名称，请参阅[堆栈配置和部署属性：Linux](attributes-json-linux.md)和。[内置说明书属性](attributes-recipes.md)有关属性和属性文件的更多信息，请参阅[关于属性文件](http://docs.chef.io/attributes.html)。
**重要**  
您的属性必须是`normal`类型才能覆盖 OpsWorks Stacks 属性；`default`类型没有优先级。例如，如果您的 `customize.rb` 文件包含 `default[:apache][:keepalivetimeout] = 5` 属性定义，则内置 `apache.rb` 属性文件中的对应属性将先进行评估，并且优先。有关更多信息，请参阅 [覆盖属性](workingcookbook-attributes.md)。

1. 对于包含您要覆盖的属性的每个内置说明书，重复步骤 2 至 4。

1. 为您的堆栈启用自定义食谱，并提供 Stac OpsWorks ks 将您的食谱下载到堆栈实例所需的信息。有关更多信息，请参阅 [安装自定义说明书](workingcookbook-installingcustom-enable.md)。

**注意**  
有关此过程的完整演练，请参阅[覆盖内置属性](cookbooks-101-opsworks-attributes.md)。

后续生命周期事件、部署命令和堆栈命令使用的节点对象现在将包含您的属性定义而不是 OpsWorks 堆栈值。

例如，要覆盖`keepalivetimeout` 中讨论的内置 `logrotate schedule` 和 [如何指定自定义 JSON](workingcookbook-json-override.md#workingcookbook-json-override-specify) 设置，请将 `apache2`apache 说明书添加到您的存储库并将 `customize.rb` 文件添加到说明书中包含下列内容的 `attributes` 文件夹。

```
normal[:apache][:keepalivetimeout] = 5
normal[:apache][:logrotate][:schedule] = 'weekly'
```

**重要**  
不应通过修改关联的内置属性文件的副本来覆盖 OpsWorks Stacks 属性。例如，如果您将 `apache.rb` 复制到您的 `apache2/attributes` 文件夹并修改其部分设置，实际上将会覆盖内置文件中的所有属性。配方将使用副本中的属性定义并忽略内置文件。如果 OpsWorks Stacks 之后修改内置属性文件，除非您手动更新副本，否则配方将无权访问更改。  
为避免这种情况，所有内置说明书都包含空的 `customize.rb` 属性文件，该文件是所有模块中通过 `include_attribute` 指令要求的。通过覆盖 `customize.rb` 的副本中的属性，您仅影响这些特定属性。配方将获取内置属性文件中的任何其他属性值，并且将自动获取您尚未覆盖的任何属性的当前值。  
此方法将帮助您在说明书存储库中维持少量的属性，从而降低您的维护开销并使未来的升级管理变得更轻松。

# 使用自定义模板扩展 OpsWorks 堆栈配置文件
<a name="workingcookbook-template-override"></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 支持 团队联系。

**注意**  
由于 OpsWorks Stacks 处理 Windows 堆栈的 Chef 运行方式与 Linux 堆栈不同，因此你不能将本节中讨论的技术用于 Windows 堆栈。

OpsWorks Stacks 使用模板来创建配置文件等文件，这些文件通常依赖于许多设置的属性。如果您使用自定义 JSON 或自定义食谱属性来覆盖 OpsWorks 堆栈定义，则您的首选设置将合并到配置文件中，而不是 OpsWorks 堆栈设置。但是， OpsWorks Stacks 不一定要为所有可能的配置设置指定属性；它接受某些设置的默认值，而直接在模板中对其他设置进行硬编码。如果没有相应的 OpsWorks Stacks 属性，则无法使用自定义 JSON 或自定义食谱属性来指定首选设置。

您可以通过创建自定义模板来扩展配置文件以包含额外的配置设置。随后，您可以向文件添加任何配置设置或其他必需内容，并覆盖任何硬编码的设置。有关模板的更多信息，请参阅[模板](workingcookbook-installingcustom-components-templates.md)。

**注意**  
您可以覆盖任何内置模板，但 opsworks-agent.monitrc.erb *除外*。

**创建自定义模板**

1. 创建一个具有与内置说明书相同的结构和目录名的说明书。然后，在适当的目录中创建一个与您要自定义的内置模板同名的模板文件。例如，要使用自定义模板扩展 Apache `httpd.conf` 配置文件，您必须在存储库中实施 `apache2` 说明书，并且您的模板文件必须为 `apache2/templates/default/apache.conf.erb`。使用完全相同的名称允许 OpsWorks Stacks 识别自定义模板并使用它来代替内置模板。

   最简单的方法是将内置模板文件从内置食谱[的 GitHub存储库复制到您的食谱](https://github.com/aws/opsworks-cookbooks)中，然后根据需要进行修改。
**重要**  
请不要复制内置说明书中的任何文件，但要自定义的模板文件除外。复制其他类型的说明书文件 (如配方) 将创建重复的 Chef 资源，并且可能导致错误。

   说明书还可以包含自定义属性、配方和相关文件，但其文件名不应与内置文件名重复。

1. 自定义模板文件以生成符合您要求的配置文件。您可以添加更多设置、删除现有设置、替换硬编码的属性等。

1. 如果您尚未执行此操作，请编辑堆栈设置以启用自定义说明书并指定说明书存储库。有关更多信息，请参阅 [安装自定义说明书](workingcookbook-installingcustom-enable.md)。

**注意**  
有关此过程的完整演练，请参阅[覆盖内置模板](cookbooks-101-opsworks-templates.md)。

您无需实现任何配方或在[图层配置中添加配方](workingcookbook-assigningcustom.md)即可覆盖模板。 OpsWorks Stacks 始终运行内置配方。当此堆栈运行创建配置文件的配方时，它将自动使用您的自定义模板，而不是使用内置模板。

**注意**  
如果 OpsWorks Stacks 对内置模板进行任何更改，则您的自定义模板可能会不同步，无法再正常工作。例如，假设您的模板引用了一个依赖文件，并且文件名发生了变化。 OpsWorks Stacks 不经常进行此类更改，当模板发生更改时，它会列出更改，并允许您选择升级到新版本。您应该监控 OpsWorks Stacks 存储库中是否有更改，并根据需要手动更新您的模板。

# 扩展层
<a name="workingcookbook-extend"></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 支持 团队联系。

有时，您需要通过修改 OpsWorks Stacks 属性或自定义模板来将内置层自定义到无法处理的程度。例如，假设您需要创建符号链接、设置文件或文件夹模式、安装其他程序包等。您必须扩展自定义层以提供最低限度功能之外的功能。在这种情况下，您将需要实施包含配方的一个或多个自定义说明书来处理自定义任务。本主题提供了一些介绍如何使用配方来扩展层的示例。

如果您在 Chef 方面是新手，您应当先阅读[说明书 101](cookbooks-101.md)，这是一个教程，旨在介绍关于如何实施说明书以执行各种常见任务的基本知识。有关如何实施自定义层的详细示例，请参阅[创建自定义 Tomcat 服务器层](create-custom.md)。

**Topics**
+ [使用配方运行脚本](workingcookbook-extend-scripts.md)
+ [使用 Chef 部署挂钩](workingcookbook-extend-hooks.md)
+ [在 Linux 实例上运行 Cron 作业](workingcookbook-extend-cron.md)
+ [在 Linux 实例上安装和配置程序包](workingcookbook-extend-package.md)

# 使用配方运行脚本
<a name="workingcookbook-extend-scripts"></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 支持 团队联系。

如果您已经有一个用于执行所需的自定义任务的脚本，则扩展层的最简单方法通常是实施一个运行该脚本的简单配方。您随后可以将该配方分配到相应的生命周期事件 (通常是设置或部署)，或者使用 `execute_recipes` 堆栈命令手动运行该配方。

以下示例在 Linux 实例上运行 shell 脚本，但您可以对其他类型的脚本（包括 Windows PowerShell 脚本）使用相同的方法。

```
cookbook_file "/tmp/lib-installer.sh" do
  source "lib-installer.sh"
  mode 0755
end

execute "install my lib" do
  command "sh /tmp/lib-installer.sh"
end
```

`cookbook_file` 资源表示一个存储在说明书的 `files` 目录的子目录中的文件，然后将该文件传输到实例上的指定位置。本示例会将 shell 脚本 `lib-installer.sh` 传输到实例的 `/tmp` 目录并将该文件的模式设置为 `0755`。有关更多信息，请参阅 [cookbook\$1file](https://docs.chef.io/chef/resources.html#cookbook-file)。

`execute` 资源表示一个命令，如 shell 命令。此示例运行 `lib-installer.sh`。有关更多信息，请参阅 [execute](https://docs.chef.io/chef/resources.html#execute)。

您还可以通过将脚本集成到配方中来运行脚本。以下示例将运行 bash 脚本，但 Chef 还支持 Csh、Perl、Python 和 Ruby。

```
script "install_something" do
  interpreter "bash"
  user "root"
  cwd "/tmp"
  code <<-EOH
    #insert bash script
  EOH
end
```

`script` 资源表示一个脚本。该示例指定了 bash 解释器，将用户设置为 `"root"`，并将工作目录设置为 `/tmp`。然后，它在 `code` 块中运行了 bash 脚本，该块可根据需要包含任意数量的行。有关更多信息，请参阅[脚本](https://docs.chef.io/chef/resources.html#script)。

有关如何使用配方运行脚本的更多信息，请参阅[示例 7：运行命令和脚本](cookbooks-101-basics-commands.md)。有关如何在 Windows 实例上运行 PowerShell 脚本的示例，请参阅[运行 Windows PowerShell 脚本](cookbooks-101-opsworks-opsworks-powershell.md)。

# 使用 Chef 部署挂钩
<a name="workingcookbook-extend-hooks"></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 支持 团队联系。

您可以实施自定义配方来执行所需的任务并将该配方分配到相应层的部署事件，从而自定义部署。一个替代方法是使用 Chef 部署挂钩运行您的自定义代码，这个方法有时候更简单，尤其是在您出于其他原因无需实施说明书时。此外，在部署后运行的自定义部署配方已由内置配方执行。利用部署挂钩，您可以在部署期间进行交互，例如，在已将应用程序的代码从存储库签出但尚未重新启动 Apache 时。

Chef 分四个阶段部署应用程序：
+ **签出**-从存储库下载文件
+ **迁移**-根据需要运行迁移
+ **符号链接**-创建符号链接
+ **重新启动**-重新启动应用程序

Chef 部署挂钩提供了一种自定义部署的简单方法，即在每个阶段完成后选择性地运行用户提供的 Ruby 应用程序。要使用部署挂钩，请实施一个或多个 Ruby 应用程序，然后将其放在您的应用程序的 `/deploy` 目录中。(如果您的应用程序没有 `/deploy` 目录，请在 `APP_ROOT` 级别创建一个。) 该应用程序必须具有以下名称之一，该名称决定了应用程序运行的时间。
+ `before_migrate.rb` 在签出阶段已完成但迁移尚未开始时运行。
+ `before_symlink.rb` 在迁移阶段已完成但符号链接尚未开始时运行。
+ `before_restart.rb` 在符号链接阶段已完成但重新启动尚未开始时运行。
+ `after_restart.rb` 在重新启动阶段完成后运行。

Chef 部署挂钩可使用标准节点语法访问节点对象，就像配方一样。部署挂钩还可访问您已指定的任何[应用程序环境变量](workingapps-creating.md#workingapps-creating-environment)的值。但是，您必须使用 `new_resource.environment["VARIABLE_NAME"] ` 访问该变量的值，而不是使用 `ENV["VARIABLE_NAME"]`。

# 在 Linux 实例上运行 Cron 作业
<a name="workingcookbook-extend-cron"></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 支持 团队联系。

Linux cron 作业指示 cron 守护程序按指定的时间表运行一个或多个命令。例如，假设您的堆栈支持某个 PHP 电子商务应用程序。您可以设置一个 cron 作业来让服务器在每周的指定时间向您发送销售报告。有关 cron 的更多信息，请参阅 Wikipedia 上的 [cron](http://en.wikipedia.org/wiki/Cron)。有关如何直接在基于 Linux 的计算机或实例上运行 cron 任务的更多信息，请参阅印第安纳大学知识库网站上的[什么是 cron 和 crontab 以及如何使用它们？](https://kb.iu.edu/d/afiz)

尽管您可以通过使用 SSH 连接到 `cron` 任务并编辑其 `crontab` 条目来在各个基于 Linux 的实例上手动设置这些任务，但 OpsWorks Stacks 的关键优势在于您可以指示它跨整层的实例运行该任务。以下过程将介绍如何在 PHP App Server 层的实例上设置 `cron` 任务，但您可以对任何层使用同一方法。

**在层的实例上设置 `cron` 作业**

1. 使用设置作业的 `cron` 资源实施一个包含配方的说明书。该示例假定配方已命名为 `cronjob.rb`；实施详细信息如下文所述。有关说明书和配方的更多信息，请参阅[说明书和诀窍](workingcookbook.md)。

1. 在堆栈上安装说明书。有关更多信息，请参阅 [安装自定义说明书](workingcookbook-installingcustom-enable.md)。

1. 通过将配方分配给以下生命周期事件，让 OpsWorks Stacks 在层的实例上自动运行配方。有关更多信息，请参阅 [自动运行配方](workingcookbook-assigningcustom.md)。
   + **设置** — `cronjob.rb` 为该事件分配指示 OpsWorks Stacks 在所有新实例上运行配方。
   + **部署**-分配`cronjob.rb`给此事件会指示 OpsWorks Stacks 在您将应用程序部署或重新部署到该层时在所有在线实例上运行配方。

   您也可以使用 `Execute Recipes` 堆栈命令来在联机实例上手动运行该配方。有关更多信息，请参阅 [运行堆栈命令](workingstacks-commands.md)。

下面是 `cronjob.rb` 示例，该示例设置了一个 cron 作业来每周运行一次用户实施的 PHP 应用程序，该应用程序将从服务器收集销售数据并通过电子邮件发送报告。有关如何使用 cron 资源的更多示例，请参阅 [cron](https://docs.chef.io/chef/resources.html#cron)。

```
cron "job_name" do
  hour "1"
  minute "10"
  weekday "6"
  command "cd /srv/www/myapp/current && php .lib/mailing.php"
end
```

`cron` 是一种表示 `cron` 作业的 Chef 资源。当 OpsWorks Stacks 在实例上运行配方时，相关的提供商会处理设置任务的细节。
+ `job_name` 是 `cron` 作业的用户定义的名称（如 `weekly report`）。
+ `hour`/`minute`/`weekday` 指定这些命令应在何时运行。本示例在每周六凌晨 1:10 运行这些命令。
+ `command` 指定要运行的命令。

  本示例运行两个命令。首先导航到 `/srv/www/myapp/current` 目录。第二个命令运行用户实施的 `mailing.php` 应用程序，该应用程序将收集销售数据并发送报告。

**注意**  
默认情况下，`bundle` 命令不适用于 `cron` 作业。原因是 OpsWorks Stacks 在目录中安装了`/usr/local/bin`捆绑器。要将 `bundle` 与 `cron` 作业结合使用，您必须将路径 `/usr/local/bin` 显式添加到 cron 作业。此外，由于 \$1PATH 环境变量不能在 `cron` 作业中扩展，因此最佳实践是将所有必需的路径信息显式添加到该作业而不依赖于 \$1PATH 变量的扩展。以下示例显示了在 `cron` 中使用 `bundle` 作业的两种方法。  

```
cron "my first task" do
  path "/usr/local/bin"
  minute "*/10"
  command "cd /srv/www/myapp/current && bundle exec my_command"
end
```

```
cron_env = {"PATH" => "/usr/local/bin"}
cron "my second task" do
  environment cron_env
  minute "*/10"
  command "cd /srv/www/myapp/current && /usr/local/bin/bundle exec my_command"
end
```

如果您的堆栈具有多个应用程序服务器，则将 `cronjob.rb` 分配到 PHP App Server 层的生命周期事件可能不是理想方法。例如，配方在层的所有实例上运行，因此您将收到多个报告。更好的方法是使用自定义层来确保只有一台服务器发送报告。

**仅在层的其中一个实例上运行配方**

1. 例如，创建一个名为的自定义层， PHPAdmin 并将其分配`cronjob.rb`给其设置和部署事件。自定义层不一定要执行很多操作。在这种情况下， PHPAdmin 只需在其实例上运行一个自定义配方即可。

1. 将其中一个 PHP 应用服务器实例分配给 AdminLayer。如果一个实例属于多个图层， OpsWorks Stacks 会运行每个层的内置和自定义配方。

由于只有一个实例属于 PHP App Server 和 PHPAdmin 层，因此只能在该实例上`cronjob.rb`运行，并且您只会收到一份报告。

# 在 Linux 实例上安装和配置程序包
<a name="workingcookbook-extend-package"></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 支持 团队联系。

内置层仅支持特定程序包。有关更多信息，请参阅 [图层](workinglayers.md)。您可以通过实施处理关联的设置、配置和部署任务的自定义配方来安装其他程序包 (如 Redis 服务器)。在某些情况下，最佳方法是扩展内置层以便让该层在其实例上安装该程序包以及该层的标准程序包。例如，如果您有一个支持 PHP 应用程序的堆栈，并且您想要包含 Redis 服务器，则可以扩展 PHP App Server 层以在该层的实例上安装和配置 Redis 服务器以及 PHP 应用程序服务器。

程序包安装配方通常需要执行如下任务：
+ 创建一个或多个目录并设置其模式。
+ 基于模板创建配置文件。
+ 运行安装程序以在实例上安装程序包。
+ 启动一个或多个服务。

有关如何安装 Tomcat 服务器的示例，请参阅[创建自定义 Tomcat 服务器层](create-custom.md)。该主题介绍了如何设置自定义 Redis 层，但您可使用大致相同的代码在内置层上安装和配置 Redis。有关如何安装其他软件包的示例，请参阅 [https://github.com/aws/op](https://github.com/aws/opsworks-cookbooks) sworks-cookbooks 上的内置食谱。

# 创建自定义 Tomcat 服务器层
<a name="create-custom"></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 支持 团队联系。

**注意**  
本主题介绍如何为 Linux 堆栈实施自定义层。但是，也可以修改基本原则和某些代码来为 Windows 堆栈实施自定义层，尤其是应用程序部署上的部分中的 Windows 堆栈。

在 OpsWorks Stacks 实例上使用非标准包的最简单方法是[扩展现有](workingcookbook-extend-package.md)层。但是，这种方法会在该层的实例上同时安装并运行标准和非标准程序包，通常不需要这么做。一种要求更高但更有效的方法是实施自定义层，这使您几乎可以完全控制该层的实例，其中包括以下内容：
+ 安装哪些程序包
+ 如何配置每个程序包
+ 如何将应用程序从存储库部署到实例

无论使用控制台还是 API，您都可以像任何其他层一样创建并管理自定义层，如[自定义层](workinglayers-custom.md)中所述。但是，自定义层的内置配方仅执行一些非常基本的任务，如安装 Ganglia 客户端以向 Ganglia 主机报告指标。要使自定义层的实例不仅仅局限于最低的正常运行，您必须实施一个或多个包含 Chef 配方和相关文件的自定义说明书，以处理安装和配置程序包、部署应用程序等任务。不过，您没有必要从头开始实施所有内容。例如，如果您将应用程序存储在一个标准存储库中，您可以使用内置部署配方来处理在该层的实例上安装应用程序的大部分工作。

**注意**  
如果您在 Chef 方面是新手，您应当先阅读[说明书 101](cookbooks-101.md)，这是一个教程，旨在介绍关于如何实施说明书以执行各种常见任务的基本知识。

以下演练介绍如何实施可支持 Tomcat 应用程序服务器的自定义层。该层基于一个名为 Tomcat 的自定义说明书，该说明书中包含用于处理程序包安装、部署等任务的配方。本演练包括 Tomcat 说明书的摘录。你可以从其[GitHub 存储库](https://github.com/amazonwebservices/opsworks-example-cookbooks/tree/master/tomcat)中下载完整的食谱。如果您不熟悉 [Opscode Chef](http://www.opscode.com/chef/)，您应当先阅读[说明书和诀窍](workingcookbook.md)。

**注意**  
OpsWorks Stacks 包括一个功能齐全的 [Java 应用服务器层](layers-java.md)，供生产使用。Tomcat 说明书的目的在于说明如何实施自定义层，因此它仅支持不包括 SSL 等功能的有限版本的 Tomcat。有关功能完备的实施的示例，请参阅内置 [opsworks\$1java](https://github.com/aws/opsworks-cookbooks/tree/release-chef-11.10/opsworks_java) 说明书。

Tomcat 说明书支持其实例拥有以下特征的自定义层：
+ 它们支持拥有 Apache 前端的 Tomcat Java 应用程序服务器。
+ Tomcat 经配置，允许应用程序使用 JDBC `DataSource` 对象来连接到单独的 MySQL 实例，该实例相当于一个后端数据存储。

针对这个项目的说明书涉及多个关键组件：
+ [属性文件](create-custom-attributes.md)包含各个配方使用的配置设置。
+ [Setup 配方](create-custom-setup.md)被分配给该层的 Setup [生命周期事件](workingcookbook-events.md)。它们在实例启动后运行，并执行安装程序包和创建配置文件等任务。
+ [Configure 配方](create-custom-configure.md)分配给了该层的 Configure 生命周期事件。它们在堆栈的配置发生更改后 (主要是当实例变为在线或离线状态时) 运行，并处理任何所需的配置更改。
+ [Deploy 配方](create-custom-deploy.md)分配给了层的 Deploy 生命周期事件。它们在 Setup 配方之后以及当您手动部署应用程序以在层的实例上安装代码和相关文件并处理相关任务 (如重新启动服务) 之后运行。

最后一部分 [创建堆栈并运行应用程序](create-custom-stack.md) 介绍如何创建一个包含基于 Tomcat 说明书的自定义层的堆栈，以及如何部署和运行一个简单的 JSP 应用程序，该应用程序显示在属于单独的 MySQL 层的实例上运行的 MySQL 数据库中的数据。

**注意**  
Tomcat 食谱依赖于一些 OpsWorks Stacks 内置食谱。为了明确每个配方的来源，本主题使用 Chef *cookbookname*::*recipename* 约定确定配方。

**Topics**
+ [属性文件](create-custom-attributes.md)
+ [Setup 配方](create-custom-setup.md)
+ [Configure 配方](create-custom-configure.md)
+ [Deploy 配方](create-custom-deploy.md)
+ [创建堆栈并运行应用程序](create-custom-stack.md)

# 属性文件
<a name="create-custom-attributes"></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 说明书的属性文件 (该文件包含配方使用的各种配置设置) 是很有帮助的。属性不是必需的；您可以直接在您的配方或模板中对这些值进行硬编码。但是，如果您使用属性定义配置设置，则可以使用 OpsWorks Stacks 控制台或 API 通过定义自定义 JSON 属性来修改值，这比每次要更改设置时都重写配方或模板代码更简单、更灵活。这种方法具有诸多好处，例如，允许您为多个堆栈使用相同的说明书，但对于每个堆栈，要为 Tomcat 服务器配置不同的值。有关属性以及如何覆盖属性的更多信息，请参阅[覆盖属性](workingcookbook-attributes.md)。

以下示例显示了完整的属性文件 `default.rb`，该文件位于 Tomcat 说明书的 `attributes` 目录中。

```
default['tomcat']['base_version'] = 6
default['tomcat']['port'] = 8080
default['tomcat']['secure_port'] = 8443
default['tomcat']['ajp_port'] = 8009
default['tomcat']['shutdown_port'] = 8005
default['tomcat']['uri_encoding'] = 'UTF-8'
default['tomcat']['unpack_wars'] = true
default['tomcat']['auto_deploy'] = true
case node[:platform]
when 'centos', 'redhat', 'fedora', 'amazon'
  default['tomcat']['java_opts'] = ''
when 'debian', 'ubuntu'
  default['tomcat']['java_opts'] = '-Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC'
end
default['tomcat']['catalina_base_dir'] = "/etc/tomcat#{node['tomcat']['base_version']}"
default['tomcat']['webapps_base_dir'] = "/var/lib/tomcat#{node['tomcat']['base_version']}/webapps"
default['tomcat']['lib_dir'] = "/usr/share/tomcat#{node['tomcat']['base_version']}/lib"
default['tomcat']['java_dir'] = '/usr/share/java'
default['tomcat']['mysql_connector_jar'] = 'mysql-connector-java.jar'
default['tomcat']['apache_tomcat_bind_mod'] = 'proxy_http' # or: 'proxy_ajp'
default['tomcat']['apache_tomcat_bind_config'] = 'tomcat_bind.conf'
default['tomcat']['apache_tomcat_bind_path'] = '/tc/'
default['tomcat']['webapps_dir_entries_to_delete'] = %w(config log public tmp)
case node[:platform]
when 'centos', 'redhat', 'fedora', 'amazon'
  default['tomcat']['user'] = 'tomcat'
  default['tomcat']['group'] = 'tomcat'
  default['tomcat']['system_env_dir'] = '/etc/sysconfig'
when 'debian', 'ubuntu'
  default['tomcat']['user'] = "tomcat#{node['tomcat']['base_version']}"
  default['tomcat']['group'] = "tomcat#{node['tomcat']['base_version']}"
  default['tomcat']['system_env_dir'] = '/etc/default'
end
```

稍后将在相关部分中讨论这些设置本身。以下说明适用于一般情况：
+ 所有节点定义都是 `default` 类型，因此，您可以使用[自定义 JSON 属性](workingcookbook-json-override.md)覆盖这些定义。
+ 该文件使用 `case` 语句按照条件并基于实例的操作系统设置一些属性值。

  `platform` 节点由 Chef 的 Ohai 工具生成，表示实例的操作系统。

# Setup 配方
<a name="create-custom-setup"></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 支持 团队联系。

Setup 配方分配给了该层的 Setup [生命周期](workingcookbook-events.md)事件，这些配方在实例启动后运行。它们执行安装程序包、创建配置文件和启动服务等任务。安装配方完成运行后， OpsWorks Stacks 会运行 [Deploy 配方](create-custom-deploy.md)，将任何应用程序部署到新实例。

**Topics**
+ [tomcat::setup](#create-custom-setup-setup)
+ [tomcat::install](#create-custom-setup-install)
+ [tomcat::service](#create-custom-setup-service)
+ [tomcat::container\$1config](#create-custom-setup-config)
+ [tomcat::apache\$1tomcat\$1bind](#create-custom-setup-bind)

## tomcat::setup
<a name="create-custom-setup-setup"></a>

`tomcat::setup` 配方适合分配给层的 Setup 生命周期事件。

```
include_recipe 'tomcat::install'
include_recipe 'tomcat::service'

service 'tomcat' do
  action :enable
end

# for EBS-backed instances we rely on autofs
bash '(re-)start autofs earlier' do
  user 'root'
  code <<-EOC
    service autofs restart
  EOC
  notifies :restart, resources(:service => 'tomcat')
end

include_recipe 'tomcat::container_config'
include_recipe 'apache2'
include_recipe 'tomcat::apache_tomcat_bind'
```

`tomcat::setup` 配方基本上是一个元配方。它包括一组从属配方，这些配方用于处理安装和配置 Tomcat 及相关程序包的大部分详细信息。`tomcat::setup` 的第一部分运行以下配方，我们将在后面的部分进行介绍：
+ [tomcat::install](#create-custom-setup-install) 配方可安装 Tomcat 服务器包。
+ [tomcat::service](#create-custom-setup-service) 配方可设置 Tomcat 服务。

`tomcat::setup` 的中间部分可启用并启动 Tomcat 服务：
+ Chef [service 资源](https://docs.chef.io/chef/resources.html#service)可在启动时启用 Tomcat 服务。
+ Chef [bash 资源](https://docs.chef.io/chef/resources.html#bash)运行一个 Bash 脚本，以启动 autofs 守护进程，这对于 由Amazon EBS 提供支持的实例来说是必要的。然后，该资源通知 `service` 资源重新启动 Tomcat 服务。

  有关更多信息，请参阅：[autofs](https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Storage_Administration_Guide/s2-nfs-config-autofs.html) (对于 Amazon Linux) 或 [Autofs](https://help.ubuntu.com/community/Autofs) (对于 Ubuntu)。

`tomcat::setup` 的最后一部分可创建配置文件并安装和配置前端 Apache 服务器：
+ [tomcat::container\$1config](#create-custom-setup-config) 配方可创建配置文件。
+ `apache2`配方（简写为`apache2::default`）是 OpsWorks Stacks 的内置配方，用于安装和配置 Apache 服务器。
+ [tomcat::apache\$1tomcat\$1bind](#create-custom-setup-bind) 配方可将 Apache 服务器配置为作为 Tomcat 服务器的前端运行。

**注意**  
您通常可以通过使用内置配方执行某些所需任务来节约时间和精力。此配方使用内置 `apache2::default` 配方来安装 Apache，而不是从头实施 Apache。有关另一个关于如何使用内置配方的示例，请参阅[Deploy 配方](create-custom-deploy.md)。

后面的部分更加详细地介绍了 Tomcat 说明书的 Setup 配方。有关 `apache2` 配方的更多信息，请参阅 [opsworks-cookbooks/apache2](https://github.com/aws/opsworks-cookbooks/tree/release-chef-11.4/apache2)。

## tomcat::install
<a name="create-custom-setup-install"></a>

`tomcat::install `配方可安装 Tomcat 服务器、OpenJDK 以及 Java 连接器库，该连接器库可处理与 MySQL 服务器的连接。

```
tomcat_pkgs = value_for_platform(
  ['debian', 'ubuntu'] => {
    'default' => ["tomcat#{node['tomcat']['base_version']}", 'libtcnative-1', 'libmysql-java']
  },
  ['centos', 'redhat', 'fedora', 'amazon'] => {
    'default' => ["tomcat#{node['tomcat']['base_version']}", 'tomcat-native', 'mysql-connector-java']
  },
  'default' => ["tomcat#{node['tomcat']['base_version']}"]
)

tomcat_pkgs.each do |pkg|
  package pkg do
    action :install
  end
end

link ::File.join(node['tomcat']['lib_dir'], node['tomcat']['mysql_connector_jar']) do
  to ::File.join(node['tomcat']['java_dir'], node['tomcat']['mysql_connector_jar'])
  action :create
end

# remove the ROOT webapp, if it got installed by default
include_recipe 'tomcat::remove_root_webapp'
```

该配方执行以下任务：

1. 创建要安装的程序包的列表，具体取决于实例的操作系统。

1. 安装列表中的每个程序包。

   Chef [package 资源](https://docs.chef.io/chef/resources.html#id146)使用适当的提供程序 (对于 Amazon Linux，使用 `yum`；对于 Ubuntu，使用 `apt-get`) 来处理安装任务。程序包提供程序将 OpenJDK 作为 Tomcat 依赖项进行安装，但必须显式安装 MySQL 连接器库。

1. 使用 Chef [link 资源](https://docs.chef.io/chef/resources.html#link)在 Tomcat 服务器的 lib 目录中创建一个指向 JDK 中的 MySQL 连接器库的符号链接。

   如果使用默认属性值，则 Tomcat lib 目录为 `/usr/share/tomcat6/lib`，并且 MySQL 连接器库 (`mysql-connector-java.jar`) 位于 `/usr/share/java/` 中。

`tomcat::remove_root_webapp` 配方可删除 ROOT Web 应用程序 (默认情况下为 `/var/lib/tomcat6/webapps/ROOT`)，以避免出现一些安全问题。

```
ruby_block 'remove the ROOT webapp' do
  block do
    ::FileUtils.rm_rf(::File.join(node['tomcat']['webapps_base_dir'], 'ROOT'), :secure => true)
  end
  only_if { ::File.exists?(::File.join(node['tomcat']['webapps_base_dir'], 'ROOT')) && !::File.symlink?(::File.join(node['tomcat']['webapps_base_dir'], 'ROOT')) }
end
```

`only_if` 语句可确保配方仅在文件存在时删除文件。

**注意**  
Tomcat 版本由 `['tomcat']['base_version']` 属性指定，该属性在属性文件中被设置为 6。要安装 Tomcat 7，您可以使用自定义 JSON 属性来覆盖该属性。[编辑您的堆栈设置](workingstacks-edit.md)，然后在 **Custom Chef JSON** 框中输入以下 JSON，或者将其添加到任何现有自定义 JSON 即可：  

```
{
  'tomcat' : {
    'base_version' : 7
  }
}
```
自定义 JSON 属性覆盖默认属性，并将 Tomcat 版本设置为 7。有关覆盖属性的更多信息，请参阅[覆盖属性](workingcookbook-attributes.md)。

## tomcat::service
<a name="create-custom-setup-service"></a>

`tomcat::service` 配方创建 Tomcat 服务定义。

```
service 'tomcat' do
  service_name "tomcat#{node['tomcat']['base_version']}"

  case node[:platform]
  when 'centos', 'redhat', 'fedora', 'amazon'
    supports :restart => true, :reload => true, :status => true
  when 'debian', 'ubuntu'
    supports :restart => true, :reload => false, :status => true
  end

  action :nothing
end
```

该配方使用 Chef [service 资源](https://docs.chef.io/chef/resources.html#service)指定 Tomcat 服务名称 (默认情况下为 tomcat6)，并设置 `supports` 属性以定义 Chef 如何管理服务在不同操作系统上的重新启动、重新加载和状态命令。
+ `true` 表示 Chef 可以使用 init 脚本或其他服务提供程序来运行该命令。
+ `false` 表示 Chef 必须尝试以其他方式运行该命令。

请注意，`action` 的设置为 `:nothing`。对于每个生命周期事件， OpsWorks Stacks 都会启动 [Chef 运行](https://docs.chef.io/chef_client_overview.html#the-chef-client-run)以执行相应的配方集。Tomcat 说明书采用常见模式：使配方创建服务定义，但不重新启动服务。Chef 运行中的其他配方处理重新启动，这通常是通过在用于创建配置文件的 `notifies` 资源中添加 `template` 命令来实现的。通知是重新启动服务的一种简便方法，因为它们仅在配置发生改变时重新启动服务。此外，如果 Chef 运行拥有针对一项服务的多个重新启动通知，Chef 最多重新启动服务一次。这种做法可以避免在尝试重新启动运行不正常的服务 (Tomcat 错误的常见起因) 时可能发生的问题。

 必须为使用重新启动通知的任何 Chef 运行定义 Tomcat 服务。因此，多个配方都包含 `tomcat::service`，以确保为每个 Chef 运行都定义了该服务。如果一次 Chef 运行包含 `tomcat::service` 的多个实例，不会造成损失，因为 Chef 确保每一次运行，配方仅执行一次，而无论包括了几次实例。

## tomcat::container\$1config
<a name="create-custom-setup-config"></a>

`tomcat::container_config` 配方基于说明书模板文件创建配置文件。

```
include_recipe 'tomcat::service'

template 'tomcat environment configuration' do
  path ::File.join(node['tomcat']['system_env_dir'], "tomcat#{node['tomcat']['base_version']}")
  source 'tomcat_env_config.erb'
  owner 'root'
  group 'root'
  mode 0644
  backup false
  notifies :restart, resources(:service => 'tomcat')
end

template 'tomcat server configuration' do
  path ::File.join(node['tomcat']['catalina_base_dir'], 'server.xml')
  source 'server.xml.erb'
  owner 'root'
  group 'root'
  mode 0644
  backup false
  notifies :restart, resources(:service => 'tomcat')
end
```

该配方首先调用 `tomcat::service`，以在必要时定义该服务。批量配方包含两个 [template 资源](https://docs.chef.io/chef/resources.html#template)，每个资源都基于一个说明书模板文件创建配置文件，设置文件属性，以及通知 Chef 重新启动服务。

### Tomcat 环境配置文件
<a name="create-custom-setup-config-env"></a>

第一个 `template` 资源使用 `tomcat_env_config.erb` 模板文件创建 Tomcat 环境配置文件，该配置文件用于设置环境变量，如 `JAVA_HOME`。默认文件名是 `template` 资源的参数。`tomcat::container_config` 使用 `path` 属性覆盖默认值，并将配置文件命名为 `/etc/sysconfig/tomcat6` (Amazon Linux) 或 `/etc/default/tomcat6` (Ubuntu)。`template` 资源还指定文件的所有者、组和模式设置，并指示 Chef 不要创建备份文件。

如果您查看源代码，实际上有三个版本的 `tomcat_env_config.erb`，这些版本分别位于 `templates` 目录的不同子目录中。`ubuntu` 和 `amazon` 目录包含适用于它们各自操作系统的模板。`default` 文件夹包含一个仅具有一个注释行的伪模板，仅当您尝试使用不受支持的操作系统在一个实例上运行此配方时，才会使用这个模板。`tomcat::container_config` 配方不需要指定要使用哪个 `tomcat_env_config.erb`。Chef 根据 [File Specificity](http://docs.chef.io/templates.html#file-specificity) 中介绍的规则自动为实例的操作系统选择适当的目录。

此示例中的 `tomcat_env_config.erb` 文件主要包含注释。要设置其他环境变量，取消相应行的注释并提供您的首选值即可。

**注意**  
可能发生更改的任何配置设置都应当定义为一个属性，而不应当在模板中对其进行硬编码。这样，您就无需重写模板来更改设置，只需覆盖该属性即可。

Amazon Linux 模板仅设置一个环境变量，如以下摘录中所示。

```
...
# Use JAVA_OPTS to set java.library.path for libtcnative.so
#JAVA_OPTS="-Djava.library.path=/usr/lib"

JAVA_OPTS="${JAVA_OPTS} <%= node['tomcat']['java_opts'] %>"

# What user should run tomcat
#TOMCAT_USER="tomcat"
...
```

JAVA\$1OPTS 可用于指定 Java 选项，如库路径。如果使用默认的属性值，则模板不会为 Amazon Linux 设置 Java 选项。您可以通过覆盖 `['tomcat']['java_opts']` 属性 (例如，使用自定义 JSON 属性) 来设置您自己的 Java 选项。有关示例，请参阅[创建堆栈](create-custom-stack.md#create-custom-stack-stack)。

Ubuntu 模板设置多个环境变量，如以下模板片段所示。

```
# Run Tomcat as this user ID. Not setting this or leaving it blank will use the
# default of tomcat<%= node['tomcat']['base_version'] %>.
TOMCAT<%= node['tomcat']['base_version'] %>_USER=tomcat<%= node['tomcat']['base_version'] %>
...
# Run Tomcat as this group ID. Not setting this or leaving it blank will use
# the default of tomcat<%= node['tomcat']['base_version'] %>.
TOMCAT<%= node['tomcat']['base_version'] %>_GROUP=tomcat<%= node['tomcat']['base_version'] %>
...
JAVA_OPTS="<%= node['tomcat']['java_opts'] %>"

<% if node['tomcat']['base_version'].to_i < 7 -%>
# Unset LC_ALL to prevent user environment executing the init script from
# influencing servlet behavior.  See Debian bug #645221
unset LC_ALL
<% end -%>
```

在使用默认属性值时，模板会将 Ubuntu 环境变量设置如下：
+ `TOMCAT6_USER` 和 `TOMCAT6_GROUP` (表示 Tomcat 用户和组) 均被设置为 `tomcat6`。

  如果您将 ['tomcat']['base\$1version'] 设置为 `tomcat7`，则变量名称将解析为 `TOMCAT7_USER` 和 `TOMCAT7_GROUP`，并且均被设置为 `tomcat7`。
+ `JAVA_OPTS` 被设置为 `-Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC`：
  + 将 `-Djava.awt.headless` 设置为 `true` 可告知图形引擎，实例处于无管模式，没有控制台，这会解决特定图形应用程序的错误行为。
  + `-Xmx128m` 确保 JVM 拥有足够的内存资源，在此示例中为 128 MB。
  + `-XX:+UseConcMarkSweepGC` 指定并发标记清除垃圾收集，这有助于限制垃圾收集引发的暂停。

    有关更多信息，请参阅：[Concurrent Mark Sweep Collector Enhancements](http://docs.oracle.com/javase/6/docs/technotes/guides/vm/cms-6.html)。
+ 如果 Tomcat 版本低于 7，则模板取消 `LC_ALL` 的设置，这可以解决 Ubuntu 错误。

**注意**  
使用默认属性，其中一些环境变量会直接被设置为其默认值。但是，将环境变量显式设置为属性意味着：您可以定义自定义 JSON 属性来覆盖默认属性并提供自定义值。有关覆盖属性的更多信息，请参阅[覆盖属性](workingcookbook-attributes.md)。

要查看完整的模板文件，请参阅 [source code](https://github.com/amazonwebservices/opsworks-example-cookbooks/tree/master/tomcat)。

### Server.xml 配置文件
<a name="create-custom-setup-config-server"></a>

第二个`template`资源`server.xml.erb`用于创建[`system.xml`配置文件](http://tomcat.apache.org/tomcat-7.0-doc/config/)，用于配置 servlet/JSP 容器。 `server.xml.erb`不包含操作系统特定的设置，因此它位于`template`目录的`default`子目录中。

该模板使用标准设置，但它可以为 Tomcat 6 或 Tomcat 7 创建一个 `system.xml` 文件。例如，模板的服务器部分中的以下代码可为指定版本正确配置侦听器。

```
<% if node['tomcat']['base_version'].to_i > 6 -%>
  <!-- Security listener. Documentation at /docs/config/listeners.html
  <Listener className="org.apache.catalina.security.SecurityListener" />
  -->
<% end -%>
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<% if node['tomcat']['base_version'].to_i < 7 -%>
  <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<% end -%>
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<% if node['tomcat']['base_version'].to_i > 6 -%>
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<% end -%>
```

该模板使用属性来代替硬编码设置，因此，您可以轻松地通过定义自定义 JSON 属性来更改设置。例如：

```
<Connector port="<%= node['tomcat']['port'] %>" protocol="HTTP/1.1"
           connectionTimeout="20000"
           URIEncoding="<%= node['tomcat']['uri_encoding'] %>"
           redirectPort="<%= node['tomcat']['secure_port'] %>" />
```

有关更多信息，请参阅 [source code](https://github.com/amazonwebservices/opsworks-example-cookbooks/tree/master/tomcat)。

## tomcat::apache\$1tomcat\$1bind
<a name="create-custom-setup-bind"></a>

`tomcat::apache_tomcat_bind` 配方使 Apache 服务器能够充当 Tomcat 的前端，接收传入请求、将其转发到 Tomcat 并将响应返回给客户端。此示例使用 [mod\$1proxy](https://httpd.apache.org/docs/2.2/mod/mod_proxy.html) 作为 Apache 代理/网关。

```
execute 'enable mod_proxy for apache-tomcat binding' do
  command '/usr/sbin/a2enmod proxy'
  not_if do
    ::File.symlink?(::File.join(node['apache']['dir'], 'mods-enabled', 'proxy.load')) || node['tomcat']['apache_tomcat_bind_mod'] !~ /\Aproxy/
  end
end

execute 'enable module for apache-tomcat binding' do
  command "/usr/sbin/a2enmod #{node['tomcat']['apache_tomcat_bind_mod']}"
  not_if {::File.symlink?(::File.join(node['apache']['dir'], 'mods-enabled', "#{node['tomcat']['apache_tomcat_bind_mod']}.load"))}
end

include_recipe 'apache2::service'

template 'tomcat thru apache binding' do
  path ::File.join(node['apache']['dir'], 'conf.d', node['tomcat']['apache_tomcat_bind_config'])
  source 'apache_tomcat_bind.conf.erb'
  owner 'root'
  group 'root'
  mode 0644
  backup false
  notifies :restart, resources(:service => 'apache2')
end
```

要启用 `mod_proxy`，您必须启用 `proxy` 模块和一个基于协议的模块。对于协议模块，您有两个选项：
+ HTTP: `proxy_http`
+ [Apache JServ 协议](http://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html) (AJP)：`proxy_ajp`

  AJP 是一个内部 Tomcat 协议。

配方的这两个 [execute 资源](https://docs.chef.io/chef/resources.html#execute) 都运行 `a2enmod` 命令，该命令通过创建所需的符号链接来启用特定模块：
+ 第一个 `execute` 资源启用 `proxy` 模块。
+ 第二个 `execute` 资源启用协议模块，它在默认情况下被设置为 `proxy_http`。

  如果您希望使用 AJP，您可以定义自定义 JSON 以覆盖 `apache_tomcat_bind_mod` 属性并将其设置为 `proxy_ajp`。

该`apache2::service`配方是 OpsWorks Stacks 的内置配方，用于定义 Apache 服务。有关更多信息，请参阅 OpsWorks Stacks GitHub 存储库中的[配方](https://github.com/aws/opsworks-cookbooks/blob/release-chef-11.4/apache2/recipes/service.rb)。

`template` 资源使用 `apache_tomcat_bind.conf.erb` 创建一个配置文件，默认情况下，该文件被命名为 `tomcat_bind.conf`。它将该配置文件放在 `['apache']['dir']/.conf.d` 目录中。`['apache']['dir']` 属性在内置 `apache2` 属性文件中定义，默认情况下它被设置为 `/etc/httpd` (Amazon Linux) 或 `/etc/apache2` (Ubuntu)。如果 `template` 资源创建或更改配置文件，则 `notifies` 命令将计划重新启动 Apache 服务。

```
<% if node['tomcat']['apache_tomcat_bind_mod'] == 'proxy_ajp' -%>
ProxyPass <%= node['tomcat']['apache_tomcat_bind_path'] %> ajp://localhost:<%= node['tomcat']['ajp_port'] %>/
ProxyPassReverse <%= node['tomcat']['apache_tomcat_bind_path'] %> ajp://localhost:<%= node['tomcat']['ajp_port'] %>/
<% else %>
ProxyPass <%= node['tomcat']['apache_tomcat_bind_path'] %> http://localhost:<%= node['tomcat']['port'] %>/
ProxyPassReverse <%= node['tomcat']['apache_tomcat_bind_path'] %> http://localhost:<%= node['tomcat']['port'] %>/
<% end -%>
```

该模板使用[ProxyPass](https://httpd.apache.org/docs/2.0/mod/mod_proxy.html#proxypass)和[ProxyPassReverse](https://httpd.apache.org/docs/2.0/mod/mod_proxy.html#proxypassreverse)指令来配置用于在 Apache 和 Tomcat 之间传递流量的端口。由于这两个服务器在同一个实例上，所以它们可以使用本地主机 URL，默认情况下，它们均被设置为 `http://localhost:8080`。

# Configure 配方
<a name="create-custom-configure"></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 支持 团队联系。

Configure 配方被分配给层的 Configure [生命周期](workingcookbook-events.md)事件，每当实例进入在线状态或退出在线状态时，堆栈的所有实例上都会发生该事件。您可以使用 Configure 配方来调整实例的配置，以根据需要响应更改。当您实施 Configure 配方时，请记住，堆栈配置更改可能涉及与此层无关的实例。该配方必须能够作出相应的响应，但在某些情况下，可能不需要执行任何操作。

## tomcat::configure
<a name="create-custom-configure-configure"></a>

`tomcat::configure` 配方用于执行层的 Configure 生命周期事件。

```
include_recipe 'tomcat::context'
# Optional: Trigger a Tomcat restart in case of a configure event, if relevant
# settings in custom JSON have changed (e.g. java_opts/JAVA_OPTS):
#include_recipe 'tomcat::container_config'
```

`tomcat::configure` 配方基本上是一个元配方，可运行两个从属配方。

1. `tomcat::context` 配方可创建一个 Web 应用程序上下文配置文件。

   此文件可配置应用程序用来与 MySQL 实例通信的 JDBC 资源，如下一部分中所述。运行此配方以响应 configure 事件使层可以在数据库层发生变化后更新 Web 应用程序上下文配置文件。

1. `tomcat::container_config` Setup 配方再次运行，以捕获容器配置中的任何更改。

在本示例中，`include` 的 `tomcat::container_config` 被改为注释了。如果您希望使用自定义 JSON 来修改 Tomcat 设置，您可以删除注释。之后，Configure 生命周期事件运行 `tomcat::container_config`，这会更新 Tomcat 相关配置文件 (如[tomcat::container\$1config](create-custom-setup.md#create-custom-setup-config)中所述) 并重新启动 Tomcat 服务。

## tomcat::context
<a name="create-custom-configure-context"></a>

Tomcat cookbook 允许应用程序使用 [J DataSource](http://docs.oracle.com/javase/tutorial/jdbc/basics/sqldatasources.html) 2EE 对象访问 MySQL 数据库服务器，该服务器可以在单独的实例上运行。借助 Tomcat，您可以通过为每个应用程序创建和安装 Web 应用程序上下文配置文件来启用连接。此文件定义应用程序与 JDBC 资源 (应用程序将使用该资源与数据库通信) 之间的关系。有关更多信息，请参阅 [The Context Container](http://tomcat.apache.org/tomcat-7.0-doc/config/context.html)。

`tomcat::context` 配方的主要目的是创建此配置文件。

```
include_recipe 'tomcat::service'

node[:deploy].each do |application, deploy|
  context_name = deploy[:document_root].blank? ? application : deploy[:document_root]

  template "context file for #{application} (context name: #{context_name})" do
    path ::File.join(node['tomcat']['catalina_base_dir'], 'Catalina', 'localhost', "#{context_name}.xml")
    source 'webapp_context.xml.erb'
    owner node['tomcat']['user']
    group node['tomcat']['group']
    mode 0640
    backup false
    only_if { node['datasources'][context_name] }
    variables(:resource_name => node['datasources'][context_name], :webapp_name => application)
    notifies :restart, resources(:service => 'tomcat')
  end
end
```

除了 Tomcat 食谱属性外，此配方还使用了 Stack OpsWorks s 在 Configure 事件中安装的[堆栈配置和部署属性](workingcookbook-json.md)。 OpsWorks Stacks 服务向每个实例的节点对象添加属性，这些属性包含配方通常通过使用数据袋或搜索获得的信息，并将属性安装到每个实例上。这些属性包含关于堆栈配置、部署的应用程序和用户希望包含的任何自定义数据的详细信息。配方可以通过使用标准 Chef 节点语法获取堆栈配置和部署属性的数据。有关更多信息，请参阅 [堆栈配置和部署属性](workingcookbook-json.md)。对于 Chef 11.10 堆栈，您还可以使用 Chef 搜索来获取堆栈配置和部署数据。有关更多信息，请参阅 [使用 Chef 搜索](workingcookbook-chef11-10.md#workingcookbook-chef11-10-search)。

`deploy`属性是指`[:deploy]`命名空间，其中包含与部署相关的属性，这些属性通过控制台或 API 定义，或者由 OpsWorks Stacks 服务生成。`deploy` 属性包含各个已部署应用程序的以应用程序短名称命名的一个属性。每个应用程序属性都包含一组用于描述应用程序的特征的属性，如文档根目录 (`[:deploy][:appname][:document_root]`)。

`context` 配方首先通过调用 [tomcat::service](create-custom-setup.md#create-custom-setup-service) 来确保为此 Chef 运行定义了服务。然后，它定义 `context_name` 变量，该变量表示配置文件的名称，不包括 `.xml` 扩展名。如果您使用默认文档根目录，则 `context_name` 将被设置为应用程序的短名称。否则，它将被设置为指定的文档根目录。[创建堆栈并运行应用程序](create-custom-stack.md)中讨论的示例将文档根目录设置为 `"ROOT"`，因此，上下文是 ROOT，配置文件被命名为 `ROOT.xml`。

批量配方查看部署的应用程序的列表，并为每个应用程序使用 `webapp_context.xml.erb` 模板来创建上下文配置文件。此示例仅部署一个应用程序，但 `deploy` 属性的定义需要您将其看作一组应用程序。

`webapp_context.xml.erb` 模板不是特定于操作系统的，因此它位于 `templates` 目录中的 `default` 子目录中。

该配方创建配置文件，如下所示：
+ 使用默认属性值时，配置文件名称设置为 `context_name.xml`，并安装在 `/etc/tomcat6/Catalina/localhost/` 目录中。

  堆栈配置属性的 `['datasources']` 节点包含一个或多个属性，其中每个属性都会将一个上下文名称映射到关联的应用程序将用来与数据库通信的 JDBC 数据资源。当您创建堆栈时，该节点及其内容通过自定义 JSON 进行定义，如[创建堆栈并运行应用程序](create-custom-stack.md)后面的部分所述。此示例中仅有一个将 ROOT 上下文名称与名为 jdbc/mydb 的 JDBC 资源相关联的属性。
+ 通过使用默认属性值，文件的用户和组均被设置为由 Tomcat 程序包定义的值：`tomcat` (Amazon Linux) 或 `tomcat6` (Ubuntu)。
+ `template` 资源仅在存在 `['datasources']` 节点时创建配置文件，并且包含 `context_name` 属性。
+ `template` 资源会定义两个变量：`resource_name` 和 `webapp_name`。

  `resource_name` 被设置为与 `context_name` 相关联的资源名称，而 `webapp_name` 被设置为应用程序的短名称。
+ template 资源可重新启动 Tomcat 服务以加载并激活更改。

`webapp_context.xml.erb` 模板包含一个 `Context` 元素，该元素包含一个具有其自己的一组属性的 `Resource` 元素。

这些 `Resource` 属性描述上下文配置的特征：
+ **name** - JDBC 资源名称，该名称被设置为 `tomcat::context` 中定义的 `resource_name` 值。

  例如，资源名称设置为 jdbc/mydb。
+ **auth** 和 **type** 这些是 JDBC `DataSource` 连接的标准设置。
+ **maxActive**、**maxIdle** 和 **maxWait** -活动和空闲连接的最大数量，以及恢复连接的最长等待时间。
+ **username** 和 **password** 数据库的用户名和根密码，这些从 `deploy` 属性中获得。
+ **driverClassName**— JDBC 驱动程序的类名，设置为 MySQL 驱动程序。
+ **url** -连接 URL。

  前缀取决于数据库。它的设置应当如下：`jdbc:mysql` (MySQL)、`jdbc:postgresql` (Postgres)，以及 `jdbc:sqlserver` (SQL Server)。此示例将 URL 设置为 `jdbc:mysql://host_IP_Address:3306:simplejsp`，其中 *simplejsp* 是应用程序的短名称。
+ **factory**-`DataSource`工厂，这是 MySQL 数据库所必需的。

有关此配置文件的更多信息，请参阅 Tomcat wiki 的 “[使用](http://wiki.apache.org/tomcat/UsingDataSources)” DataSources 主题。

# Deploy 配方
<a name="create-custom-deploy"></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 支持 团队联系。

Deploy 配方分配给层的 Deploy [生命周期](workingcookbook-events.md)事件。每当你部署应用程序时，它通常会发生在堆栈的所有实例上，但你可以选择将事件限制为仅限指定的实例。 OpsWorks 安装配方完成后，Stacks 还会在新实例上运行 Deploy 配方。Deploy 配方的主要目的是将存储库中的代码和相关文件部署到应用程序服务器层的实例。不过，您通常还可以在其他层上运行 Deploy 配方。这使这些层的实例可以执行更新，例如，更新它们的配置以适应新部署的应用程序。当您实施 Deploy 配方时，请记住，Deploy 事件并不一定意味着会将应用程序部署到实例。它只是一个通知，说明应用程序将部署到堆栈中的其他实例，以允许对实例进行任何必要的更新。该配方必须能够作出相应的响应，这种响应可能不需要执行任何操作。

OpsWorks Stacks 会自动将标准应用程序类型的应用程序部署到相应的内置应用程序服务器层。要将应用程序部署到自定义层，您必须实施自定义 Deploy 配方，该配方可将存储库中的应用程序的文件下载到实例上的适当位置。但是，您通常可以通过使用内置[部署说明书](https://github.com/aws/opsworks-cookbooks/tree/release-chef-11.4/deploy)处理某些方面的部署来限制您必须编写的代码量。例如，如果您将文件存储到某个受支持的存储库中，则内置说明书可以处理关于从存储库将文件下载到层的实例的详细信息。

`tomcat::deploy` 配方旨在被分配给 Deploy 生命周期事件。

```
include_recipe 'deploy'

node[:deploy].each do |application, deploy|
  opsworks_deploy_dir do
    user deploy[:user]
    group deploy[:group]
    path deploy[:deploy_to]
  end

  opsworks_deploy do
    deploy_data deploy
    app application
  end
...
```

`tomcat::deploy` 配方使用内置部署说明书来完成部署的非特定于应用程序的方面。`deploy` 配方 (内置 `deploy::default` 配方的简写) 是一个可根据 `deploy` 属性的数据处理关于设置用户、组等的详细信息的内置配方。

该配方使用两个内置 Chef 定义 (`opsworks_deploy_dir` 和 `opworks_deploy`) 来安装应用程序。

`opsworks_deploy_dir` 定义根据应用程序的部署 JSON 中的数据来设置目录结构。从根本上说，定义是对资源定义进行打包的简便的方式，位于说明书的 `definitions` 目录中。配方使用定义的方式与使用资源很像，但定义本身并没有关联的提供程序，只是资源包括在定义中。您可以定义配方中的变量，这些变量将传递到基础资源定义。`tomcat::deploy` 配方根据部署 JSON 中的数据设置 `user`、`group` 和 `path` 变量。它们将传递到定义的 [directory 资源](https://docs.chef.io/chef/resources.html#directory)，该资源用于管理目录。

**注意**  
您的已部署的应用程序的用户和组由 `[:opsworks][:deploy_user][:user]` 和 `[:opsworks][:deploy_user][:group]` 属性决定，这些属性在[内置部署说明书的 `deploy.rb` 属性文件中进行定义](https://github.com/aws/opsworks-cookbooks/blob/release-chef-11.4/deploy/attributes/deploy.rb)。`[:opsworks][:deploy_user][:user]` 的默认值为 `deploy`。`[:opsworks][:deploy_user][:group]` 的默认值取决于实例的操作系统：  
对于 Ubuntu 实例，默认组为 `www-data`。
对于属于使用 Nginx 和 Unicorn 的 Rails App Server 层的成员的 Amazon Linux 实例，默认组为 `nginx`。
对于所有其他 Amazon Linux 实例，默认组为 `apache`。
您可以通过使用自定义 JSON 或自定义属性文件覆盖相应的属性来更改设置。有关更多信息，请参阅 [覆盖属性](workingcookbook-attributes.md)。

另一个定义 `opsworks_deploy` 可根据 `deploy` 属性中的数据来处理关于查看存储库中的应用程序的代码和相关文件以及将其部署到实例的详细信息。您可以为任何应用程序类型使用此定义；部署详细信息 (例如目录名称) 在控制台中指定或通过 API 指定，并被置入到 `deploy` 属性中。但是，`opsworks_deploy` 仅适用于四种[受支持的存储库类型](workingcookbook-installingcustom-repo.md)：Git、Subversion、S3 和 HTTP。如果您希望使用不同的存储库类型，您必须自己实施此代码。

您将应用程序的文件安装在 Tomcat `webapps` 目录中。通常的做法是直接将文件复制到 `webapps`。但是， OpsWorks Stacks 部署旨在在一个实例上保留多达五个版本的应用程序，因此如有必要，您可以回滚到较早的版本。 OpsWorks 因此，堆栈会执行以下操作：

1. 将应用程序部署到一个不同的目录，该目录的名称中包含一个时间戳，如 `/srv/www/my_1st_jsp/releases/20130731141527`。

1. 创建一个指向此唯一的目录、名为 `current` 的符号链接，如 `/srv/www/my_1st_jsp/current`。

1. 如果尚不存在此目录，请在 `webapps` 目录中创建一个指向在第 2 步中创建的 `current` 符号链接的符号链接。

如果您需要回滚到早期版本，可修改 `current` 符号链接以指向包含相应时间戳的不同目录，例如，通过更改 `/srv/www/my_1st_jsp/current` 的链接目标。

`tomcat::deploy` 的中间部分可设置符号链接。

```
  ...
  current_dir = ::File.join(deploy[:deploy_to], 'current')
  webapp_dir = ::File.join(node['tomcat']['webapps_base_dir'], deploy[:document_root].blank? ? application : deploy[:document_root])

  # opsworks_deploy creates some stub dirs, which are not needed for typical webapps
  ruby_block "remove unnecessary directory entries in #{current_dir}" do
    block do
      node['tomcat']['webapps_dir_entries_to_delete'].each do |dir_entry|
        ::FileUtils.rm_rf(::File.join(current_dir, dir_entry), :secure => true)
      end
    end
  end

  link webapp_dir do
    to current_dir
    action :create
  end
  ...
```

该配方首先创建两个变量 (`current_dir` 和 `webapp_dir`) 以分别表示 `current` 和 `webapp` 目录。然后，它使用 `link` 资源将 `webapp_dir` 链接到 `current_dir`。 OpsWorks Stacks `deploy::default` 配方创建了一些本示例不需要的存根目录，因此摘录的中间部分将其删除。

`tomcat::deploy` 的最后部分可在必要时重新启动 Tomcat 服务。

```
  ...
  include_recipe 'tomcat::service'

  execute 'trigger tomcat service restart' do
    command '/bin/true'
    not_if { node['tomcat']['auto_deploy'].to_s == 'true' }
    notifies :restart, resources(:service => 'tomcat')
  end
end

include_recipe 'tomcat::context'
```

该配方首先运行 `tomcat::service` 以确保为此 Chef 运行定义了服务。然后，它使用 [execute 资源](https://docs.chef.io/chef/resources.html#execute)通知服务重新启动，但前提是 `['tomcat']['auto_deploy']` 被设置为 `'true'`。否则，Tomcat 将侦听其 `webapps` 目录中的变化，这会使 Tomcat 服务执行一次不必要的显式重新启动。

**注意**  
`execute` 资源实际上并不执行任何实质性操作；`/bin/true` 是一个虚拟 Shell 脚本，它只返回成功代码。它在这里只是用于生成重新启动通知的一种简便方式。如之前所提到过的，使用通知可确保不会过于频繁地重新启动服务。

最后，`tomcat::deploy` 运行 `tomcat::context`，如果您已经更改了后端数据库，这会更新 Web 应用程序上下文配置文件。

# 创建堆栈并运行应用程序
<a name="create-custom-stack"></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 说明书实施可运行名为 SimpleJSP 的简单的 Java 服务器页面 (JSP) 应用程序的基本堆栈设置。该堆栈由一个名为的基于 Tomcat 的自定义层和 TomCustom 一个 MySQL 层组成。SimpleJSP 已部署到 MySQL 数据库 TomCustom 并显示一些来自 MySQL 数据库的信息。如果您还不熟悉如何使用 OpsWorks Stacks 的基础知识，则应先阅读[Chef 11 Linux 堆栈入门](gettingstarted.md)。

## SimpleJSP 应用程序
<a name="create-custom-stack-jsp"></a>

SimpleJSP 应用程序演示了关于如何设置数据库连接以及从堆栈的 MySQL 数据库中检索数据的基础知识。

```
<html>
  <head>
    <title>DB Access</title>
  </head>
  <body>
    <%@ page language="java" import="java.sql.*,javax.naming.*,javax.sql.*" %>
    <%
      StringBuffer output = new StringBuffer();
      DataSource ds = null;
      Connection con = null;
      Statement stmt = null;
      ResultSet rs = null;
      try {
        Context initCtx = new InitialContext();
        ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/mydb");
        con = ds.getConnection();
        output.append("Databases found:<br>");
        stmt = con.createStatement();
        rs = stmt.executeQuery("show databases");
        while (rs.next()) {
          output.append(rs.getString(1));
          output.append("<br>");
        }
      }
      catch (Exception e) {
        output.append("Exception: ");
        output.append(e.getMessage());
        output.append("<br>");
      }
      finally {
        try {
          if (rs != null) {
            rs.close();
          }
          if (stmt != null) {
            stmt.close();
          }
          if (con != null) {
            con.close();
          }
        }
        catch (Exception e) {
          output.append("Exception (during close of connection): ");
          output.append(e.getMessage());
          output.append("<br>");
        }
      }
    %>
    <%= output.toString() %>
  </body>
</html>
```

SimpleJSP 使用 `DataSource` 对象与 MySQL 数据库进行通信。Tomcat 使用 [Web 应用程序上下文配置文件](create-custom-configure.md#create-custom-configure-context)中的数据来创建并初始化 `DataSource` 对象，然后将其绑定到一个逻辑名称。然后，它向 Java 命名和目录接口 (JNDI) 命名服务注册该逻辑名称。要获取相应的 `DataSource` 对象的实例，您可以创建一个 `InitialContext` 对象，将资源的逻辑名称传递给该对象的 `lookup` 方法，该方法将检索相应的对象。SimpleJSP 示例的逻辑名称 `java:comp/env/jdbc/mydb` 拥有以下组件：
+ 根命名空间 `java` 通过一个冒号 (:) 与名称的其余部分分隔开来。
+ 任何其他命名空间都通过正斜杠 (/) 分隔开来。

  Tomcat 会自动将资源添加到 `comp/env` 命名空间。
+ 资源名称，它在 Web 应用程序上下文配置文件中定义，并通过正斜杠与命名空间分隔开来。

  此示例中的资源名称为 `jdbc/mydb`。

为了建立与数据库之间的连接，SimpleJSP 将执行以下操作：

1. 调用 `DataSource` 对象的 `getConnection` 方法，该方法将返回一个 `Connection` 对象。

1. 调用 `Connection` 对象的 `createStatement` 方法以创建一个 `Statement` 对象，您可以使用该对象来与数据库通信。

1. 通过调用相应的 `Statement` 方法与数据库进行通信。

   SimpleJSP 调用 `executeQuery` 以执行 SHOW DATABASES 查询，这会列出服务器的数据库。

`executeQuery` 方法将返回一个包含查询结果的 `ResultSet` 对象。SimpleJSP 从返回的 `ResultSet` 对象中获取数据库名称，并将这些名称联接起来创建一个输出字符串。最后，该示例关闭 `ResultSet`、`Statement` 和 `Connection` 对象。有关 JSP 和 JDBC 的更多信息，请分别参见 P [JavaServer ages Tech](http://docs.oracle.com/javaee/5/tutorial/doc/bnagx.html) nology 和 [JD](http://docs.oracle.com/javase/tutorial/jdbc/basics/) BC 基础知识。

要将 SimpleJSP 与堆栈一起使用，您必须将其放到存储库中。您可以使用任何受支持的存储库，但要将 SimpleJSP 与以下部分中讨论的示例堆栈一起使用，您必须将其放到公有 S3 存档中。有关如何使用其他标准存储库的信息，请参阅[说明书存储库](workingcookbook-installingcustom-repo.md)。

**将 SimpleJSP 放到 S3 存档存储库中**

1. 将示例代码复制到名为 `simplejsp.jsp` 的文件中，并将该文件放到名为 `simplejsp` 的目录中。

1. 创建 `simplejsp` 目录的 `.zip` 存档。

1. 创建一个 Amazon S3 存储桶，将 `simplejsp.zip` 上传到该存储桶，并将该文件设置为公有。

   有关如何执行此任务的说明，请参阅 [Amazon Simple Storage Service 入门](https://docs.aws.amazon.com/AmazonS3/latest/gsg/GetStartedWithS3.html)。

## 创建堆栈
<a name="create-custom-stack-stack"></a>

要运行 SimpleJSP，您需要一个包含以下层的堆栈。
+ 一个支持后端 MySQL 服务器的 MySQL 层。
+ 一个使用 Tomcat 说明书以支持 Tomcat 服务器实例的自定义层。

**要创建 堆栈，请执行以下操作：**

1. 在 “ OpsWorks 堆栈” 仪表板上，单击 “**添加堆栈**” 以创建新堆栈，然后单击 “**高级 >>**” 以显示所有选项。按如下所示配置堆栈。
   + **名称**-用户定义的堆栈名称；本示例使用 TomStack。
   + **使用自定义 Chef 说明书 **-将切换设置为 **是 **，这会显示一些其他选项。
   + **Repository type** - Git
   + **存储库 URL**-`git://github.com/amazonwebservices/opsworks-example-cookbooks.git`。
   + **自定义 Chef JSON **-添加以下 JSON：

     ```
     {
       "tomcat": {
         "base_version": 7,
         "java_opts": "-Djava.awt.headless=true -Xmx256m"
       },
       "datasources": {
         "ROOT": "jdbc/mydb"
       }
     }
     ```

   对于其余选项，您可以接受默认值。

   自定义 JSON 执行以下操作：
   + 覆盖 Tomcat 说明书的 `['base_version']` 属性，以将 Tomcat 版本设置为 7；默认值为 6。
   + 覆盖 Tomcat 说明书的 `['java_opts']` 属性，以指定该实例处于无管控状态，并将 JVM 最大堆大小指定为 256MB；默认值并不会为运行 Amazon Linux 的实例设置选项。
   + 指定 `['datasources]` 属性值，这会将 JDBC 资源名称 (jdbc/mydb) 分配给 Web 应用程序上下文名称 (ROOT)，如[tomcat::context](create-custom-configure.md#create-custom-configure-context)中所述。

     最后一个属性没有默认值；您必须使用自定义 JSON 设置该属性。  
![\[Configuration Management interface showing Chef version options and custom JSON input field.\]](http://docs.aws.amazon.com/zh_cn/opsworks/latest/userguide/images/tom_add_stack.png)

1. 单击 **Add a layer**。对于 **Layer type**，选择 **MySQL**。然后单击 **Add Layer**。

1. 在导航窗格中，单击 **Instances**，然后单击 **Add an instance**。单击 **Add Instance** 以接受默认值。在该实例对应的行中，单击 **start**。

1. 返回 **Layers** 页面并单击 **\$1 Layer** 以添加层。对于 **Layer type (层类型)**，单击 **Custom (自定义)**。该示例分别使用 **TomCustom** 和 **tomcustom** 作为层的名称和短名称。  
![\[Add Layer form with Custom layer type, Name, and Short name fields for creating a customized layer.\]](http://docs.aws.amazon.com/zh_cn/opsworks/latest/userguide/images/tom_add_custom_layer.png)

1. 在 **Layers** 页面上，对于自定义层，单击 **Recipes**，然后单击 **Edit**。在 **Custom Chef Recipes** 下，将 Tomcat 说明书配方分配给层的生命周期事件，如下所示：
   + 对于 **Setup (设置)**，键入 **tomcat::setup** 并单击 **\$1**。
   + 对于 **Configure (配置)**，键入 **tomcat::configure** 并单击 **\$1**。
   + 对于 **Deploy (部署)**，键入 **tomcat::deploy** 并单击 **\$1**。然后单击 **Save (保存)**。

     .  
![\[Custom Chef Recipes interface showing setup, configure, and deploy steps with options.\]](http://docs.aws.amazon.com/zh_cn/opsworks/latest/userguide/images/tom_events.png)

1. 在导航窗格中，单击 **Apps**，然后单击 **Add an app**。指定以下选项，然后单击 **Add App**：
   + **名称** —应用程序的名称；该示例使用 simpleJSP， OpsWorks Stacks 生成的短名称将是 simplejsp。
   + **应用程序类型 **-将此选项设置为 **其他**。

     OpsWorks Stacks 会自动将标准应用程序类型部署到关联的服务器实例。如果您将 **App type (应用程序类型)** 设置为“other (其他)”， OpsWorks Stacks 将仅运行 Deploy 配方，并使这些配方处理部署作业。
   + **Document root**-将此选项设置为 **ROOT**。

     **Document root** 值指定上下文名称。
   + **存储库类型 **-将此选项设置为 **S3 存档**。
   + **存储库 URL **-将此选项设置为您之前创建的应用程序的 URL。

   为其他选项使用默认设置。  
![\[Application settings form with fields for name, app type, document root, and source details.\]](http://docs.aws.amazon.com/zh_cn/opsworks/latest/userguide/images/tom_app.png)

1. 使用 “**实例**” 页面向 TomCustom 图层添加实例并启动该实例。 OpsWorks 安装配方完成后，堆栈会自动在新实例上运行 Deploy 配方，因此启动该实例也会部署 SimpleJSP。

1. 当 TomCustom 实例处于联机状态时，在 “实例” 页面上单击**实例**名称以查看其详细信息。复制公有 IP 地址。然后按如下方式构造一个 URL：http: *publicIP* ///tc*appname.jsp*/。例如，此 URL 应类似于 **http://50.218.191.172/tc/simplejsp.jsp**。
**注意**  
将请求转发到 Tomcat 的 Apache URL 被设置为默认 `['tomcat']['apache_tomcat_bind_path']` 属性 `/tc/`。SimpleJSP 文档根目录被设置为 `ROOT`，这是一个解析为 `/` 的特殊值。因此，该 URL 为“.../tc/simplejsp.jsp”。

1. 将上一步骤中的 URL 粘贴到您的浏览器中。您将看到以下内容：

   ```
   Databases found:
   information_schema
   simplejsp
   test
   ```
**注意**  
如果您的堆栈有 MySQL 实例， OpsWorks Stacks 会自动为每个应用程序创建一个数据库，并以应用程序的短名称命名。

# 堆栈配置和部署属性
<a name="workingcookbook-json"></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 支持 团队联系。

当 OpsWorks Stacks 在实例上运行命令（例如，响应 Deploy 生命周期事件的 deploy 命令）时，它会向实例的节点对象添加一组描述堆栈当前配置的属性。对于部署事件和[执行配方堆栈命令](workingstacks-commands.md)， OpsWorks Stacks 会安装部署属性，这些属性提供了一些额外的部署信息。有关节点对象的更多信息，请参阅[覆盖属性](workingcookbook-attributes.md)。要查看常用堆栈配置和部署属性的列表 (包括完全限定的节点名称)，请参阅[堆栈配置和部署属性：Linux](attributes-json-linux.md)和[内置说明书属性](attributes-recipes.md)。

**注意**  
在 Linux 堆栈上，您可以使用代理 CLI 的 [get\$1json 命令](agent-json.md)，获得这些属性 (格式化为 JSON 对象) 的完整列表。

以下各部分介绍了与简单堆栈的配置事件和部署事件相关的属性，简单堆栈包括：
+ 包含两个实例的 PHP App Server 层
+ 一个只有一个实例的 HAProxy 图层

这些示例都来自一个 实例 **php-app1**。为方便起见，这些属性被格式化为 JSON 对象。对象的结构映射到属性的完全限定名称。例如，`node[:opsworks][:ruby_version]` 属性的 JSON 表示形式如下所示。

```
{
  "opsworks": {
    ...
    "ruby_version": "1.8.7",
    ...
  }
}
```

**Topics**
+ [配置属性](#workingcookbook-json-configure)
+ [部署属性](#workingcookbook-json-deploy)

## 配置属性
<a name="workingcookbook-json-configure"></a>

以下 JSON 对象显示当实例联机或脱机时堆栈中各个实例上发生的配置事件的属性。这些属性包括嵌入式堆栈配置属性和事件发生之前为堆栈定义的任何[自定义 JSON 属性](workingstacks-json.md) (此示例中未提及)。其长度已经过编辑。要了解各个属性的详细描述，请参阅[堆栈配置和部署属性：Linux](attributes-json-linux.md)和[内置说明书属性](attributes-recipes.md)。

```
{
  "opsworks": {
    "layers": {
      "php-app": {
        "id": "4a2a56c8-f909-4b39-81f8-556536d20648",
        "instances": {
          "php-app2": {
            "elastic_ip": null,
            "region": "us-west-2",
            "booted_at": "2013-02-26T20:41:10+00:00",
            "ip": "192.0.2.0",
            "aws_instance_id": "i-34037f06",
            "availability_zone": "us-west-2a",
            "instance_type": "c1.medium",
            "private_dns_name": "ip-10-252-0-203.us-west-2.compute.internal",
            "private_ip": "10.252.0.203",
            "created_at": "2013-02-26T20:39:39+00:00",
            "status": "online",
            "backends": 8,
            "public_dns_name": "ec2-192-0-2-0.us-west-2.compute.amazonaws.com"
          },
          "php-app1": {
            ...
          }
        },
        "name": "PHP Application Server"
      },
      "lb": {
        "id": "15c86142-d836-4191-860f-f4d310440f14",
        "instances": {
          "lb1": {
           ...
          }
        },
        "name": "Load Balancer"
      }
    },
    "agent_version": "104",
    "applications": [

    ],
    "stack": {
      "name": "MyStack"
    },
    "ruby_version": "1.8.7",
    "sent_at": 1361911623,
    "ruby_stack": "ruby_enterprise",
    "instance": {
      "layers": [
        "php-app"
      ],
      "region": "us-west-2",
      "ip": "192.0.2.0",
      "id": "45ef378d-b87c-42be-a1b9-b67c48edafd4",
      "aws_instance_id": "i-32037f00",
      "availability_zone": "us-west-2a",
      "private_dns_name": "ip-10-252-84-253.us-west-2.compute.internal",
      "instance_type": "c1.medium",
      "hostname": "php-app1",
      "private_ip": "10.252.84.253",
      "backends": 8,
      "architecture": "i386",
      "public_dns_name": "ec2-192-0-2-0.us-west-2.compute.amazonaws.com"
    },
    "activity": "configure",
    "rails_stack": {
      "name": null
    },
    "deployment": null,
    "valid_client_activities": [
      "reboot",
      "stop",
      "setup",
      "configure",
      "update_dependencies",
      "install_dependencies",
      "update_custom_cookbooks",
      "execute_recipes"
    ]
  },
  "opsworks_custom_cookbooks": {
    "recipes": [

    ],
    "enabled": false
  },
  "recipes": [
    "opsworks_custom_cookbooks::load",
    "opsworks_ganglia::configure-client",
    "ssh_users",
    "agent_version",
    "mod_php5_apache2::php",
    "php::configure",
    "opsworks_stack_state_sync",
    "opsworks_custom_cookbooks::execute",
    "test_suite",
    "opsworks_cleanup"
  ],
  "opsworks_rubygems": {
    "version": "1.8.24"
  },
  "ssh_users": {
  },
  "opsworks_bundler": {
    "manage_package": null,
    "version": "1.0.10"
  },
  "deploy": {
  }
}
```

大部分信息都位于常常被称为命名空间的 `opsworks` 属性下。以下列表描述了主要属性：
+ `layers` 属性-一组属性，其中各个属性分别描述一个堆栈层的配置。

  在此示例中，这些层是由其短名 `php-app` 和 `lb` 确定的。有关其他层的短名的更多信息，请参阅[OpsWorks 堆栈图层参考](layers.md)。
+ `instances` 属性-各层都有一个 `instances` 元素，该元素包含一个针对各层的在线实例、以实例短名称命名的属性。

  PHP App Server 层有两个实例 `php-app1` 和 `php-app2`。该 HAProxy 层有一个实例，`lb1`。
**注意**  
`instances` 元素仅包含创建特定堆栈和部署属性时那些处于联机状态的实例。
+ 实例属性-每个实例属性都包含一组可表明实例特征的属性，如实例的私有 IP 地址和私有 DNS 名称。为了简洁起见，该示例仅详细显示 `php-app2` 属性；其他示例包含类似信息。
+ `applications`-一份已部署应用程序的列表，此示例中未用到。
+ `stack`-堆栈名称，在此示例中为 `MyStack`。
+ `instance`-安装有这些属性的实例，在此示例中为 `php-app1`。配方可以使用此属性来获得关于配方正在其上运行的实例的信息，如实例的公有 IP 地址。
+ `activity`-生成属性的活动，在此示例中为一个配置事件。
+ `rails_stack`-包含 Rails App Server 层的堆栈的 Rails 堆栈。
+ `deployment`-指示这些属性是否与部署有关联。它在此示例中设置为 `null`，因为它们与配置事件相关联。
+ `valid_client_activities`-一份有效客户端活动的列表。

`opsworks` 属性后跟多个其他顶级属性，包括以下各属性：
+ `opsworks_custom_cookbooks`-指示是否启用自定义说明书。如果启用了自定义说明书，则该属性包含一份自定义配方的列表。
+ `recipes`-通过此活动运行的配方。
+ `opsworks_rubygems`— 实例的 RubyGems版本。
+ `ssh_users`-一份 SSH 用户的列表，在此示例中未提及。
+ `opsworks_bundler`-捆绑程序版本，并指示其是否已被启用。
+ `deploy`-关于部署活动的信息，在此示例中未提及。

## 部署属性
<a name="workingcookbook-json-deploy"></a>

部署事件或 [Execute Recipes 堆栈命令](workingstacks-commands.md)的属性包括嵌入式堆栈配置和部署属性以及任何自定义堆栈或部署属性 (在此示例中没有出现)。以下 JSON 对象显示与可将 SimplePHP 应用程序部署到堆栈 PHP 实例的部署事件相关联的 **php-app1** 的属性。大部分对象都包含与上一部分中描述的配置事件的属性相类似的堆栈配置属性，因此，该示例主要关注特定于部署的属性。要了解各个属性的详细描述，请参阅[堆栈配置和部署属性：Linux](attributes-json-linux.md)和[内置说明书属性](attributes-recipes.md)。

```
{
   ...
  "opsworks": {
    ...
    "activity": "deploy",
    "applications": [
      {
        "slug_name": "simplephp",
        "name": "SimplePHP",
        "application_type": "php"
      }
    ],
    "deployment": "5e6242d7-8111-40ee-bddb-00de064ab18f",
    ...
  },
  ...
{
  "ssh_users": {
  },
  "deploy": {
    "simplephpapp": {
      "application": "simplephpapp",
      "application_type": "php",
      "environment_variables": {
        "USER_ID": "168424",
        "USER_KEY": "somepassword"
      },
      "auto_bundle_on_deploy": true,
      "deploy_to": "/srv/www/simplephpapp",
      "deploying_user": "arn:aws:iam::123456789012:user/guysm",
      "document_root": null,
      "domains": [
        "simplephpapp"
      ],
      "migrate": false,
      "mounted_at": null,
      "rails_env": null,
      "restart_command": "echo 'restarting app'",
      "sleep_before_restart": 0,
      "ssl_support": false,
      "ssl_certificate": null,
      "ssl_certificate_key": null,
      "ssl_certificate_ca": null,
      "scm": {
        "scm_type": "git",
        "repository": "git://github.com/amazonwebservices/opsworks-demo-php-simple-app.git",
        "revision": "version1",
        "ssh_key": null,
        "user": null,
        "password": null
      },
      "symlink_before_migrate": {
        "config/opsworks.php": "opsworks.php"
      },
      "symlinks": {
      },
      "database": {
      },
      "memcached": {
        "host": null,
        "port": 11211
      },
      "stack": {
        "needs_reload": false
      }
    }
  },
}
```

`opsworks` 属性与上一部分中的示例大致相似。以下各部分大多与部署有关：
+ `activity`-与这些属性相关联的事件，在此示例中为一个部署事件。
+ `applications`-包含各个应用程序的一组属性，这些属性提供应用程序的名称、临时名称和类型。

  slug 名称是应用程序的简称， OpsWorks Stacks 根据应用程序名称生成该名称。SimplePHP 的临时名称是 simplephp。
+ `deployment`-用于唯一标识部署的部署 ID。

`deploy` 属性包含正在部署的应用程序的信息。例如，嵌入式部署配方使用 `deploy` 属性中的数据，以在相应的目录中安装文件，并创建数据库连接文件。`deploy` 属性包含各个已部署应用程序的、以应用程序短名命名的一个属性。各个应用程序属性都包含以下属性：
+ `environment_variables`-包含您为应用程序定义的任何环境变量。有关更多信息，请参阅 [环境变量](workingapps-creating.md#workingapps-creating-environment)。
+ `domains`-默认情况下，域是应用程序的短名称，在此示例中为 simplephpapp。如果您分配了自定义域名，则它们也会出现在此处。有关更多信息，请参阅 [使用自定义域](workingapps-domains.md)。
+ `application`-应用程序的短名称。
+ `scm`-此元素包含要从其存储库下载应用程序的文件所需的信息，在此示例中为 Git 存储库。
+ `database`-数据库信息，前提是堆栈包含一个数据库层。
+ `document_root`-文档根，在此示例中被设置为 `null`，表明根是公有的。
+ `ssl_certificate_ca`、`ssl_support`、`ssl_certificate_key`-指示应用程序是否获得 SSL 支持。如果获得 SSL 支持，则 `ssl_certificate_key` 和 `ssl_certificate_ca` 属性会被设置为相应的证书。
+ `deploy_to`-应用程序的根目录。