

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

# 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 应用程序上下文配置文件。