Setup 配方 - AWS OpsWorks

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

Setup 配方

重要

该 AWS OpsWorks Stacks 服务于 2024 年 5 月 26 日终止,新客户和现有客户均已禁用。我们强烈建议客户尽快将其工作负载迁移到其他解决方案。如果您对迁移有疑问,请通过 re AWS : Post 或通过 Pre mium Su AWS pp ort 与 AWS Support 团队联系。

Setup 配方分配给了该层的 Setup 生命周期事件,这些配方在实例启动后运行。它们执行安装程序包、创建配置文件和启动服务等任务。安装配方完成运行后, AWS OpsWorks Stacks 会运行 Deploy 配方,将任何应用程序部署到新实例。

tomcat::setup

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::setup 的中间部分可启用并启动 Tomcat 服务:

  • Chef service 资源可在启动时启用 Tomcat 服务。

  • Chef bash 资源运行一个 Bash 脚本,以启动 autofs 守护进程,这对于 由Amazon EBS 提供支持的实例来说是必要的。然后,该资源通知 service 资源重新启动 Tomcat 服务。

    有关更多信息,请参阅:autofs (对于 Amazon Linux) 或 Autofs (对于 Ubuntu)。

tomcat::setup 的最后一部分可创建配置文件并安装和配置前端 Apache 服务器:

  • tomcat::container_config 配方可创建配置文件。

  • apache2配方(简写为apache2::default)是 AWS OpsWorks Stacks 的内置配方,用于安装和配置 Apache 服务器。

  • tomcat::apache_tomcat_bind 配方可将 Apache 服务器配置为作为 Tomcat 服务器的前端运行。

注意

您通常可以通过使用内置配方执行某些所需任务来节约时间和精力。此配方使用内置 apache2::default 配方来安装 Apache,而不是从头实施 Apache。有关另一个关于如何使用内置配方的示例,请参阅Deploy 配方

后面的部分更加详细地介绍了 Tomcat 说明书的 Setup 配方。有关 apache2 配方的更多信息,请参阅 opsworks-cookbooks/apache2

tomcat::install

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. 创建要安装的程序包的列表,具体取决于实例的操作系统。

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

    Chef package 资源使用适当的提供程序 (对于 Amazon Linux,使用 yum;对于 Ubuntu,使用 apt-get) 来处理安装任务。程序包提供程序将 OpenJDK 作为 Tomcat 依赖项进行安装,但必须显式安装 MySQL 连接器库。

  3. 使用 Chef 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 属性来覆盖该属性。编辑您的堆栈设置,然后在 Custom Chef JSON 框中输入以下 JSON,或者将其添加到任何现有自定义 JSON 即可:

{ 'tomcat' : { 'base_version' : 7 } }

自定义 JSON 属性覆盖默认属性,并将 Tomcat 版本设置为 7。有关覆盖属性的更多信息,请参阅覆盖属性

tomcat::service

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 资源指定 Tomcat 服务名称 (默认情况下为 tomcat6),并设置 supports 属性以定义 Chef 如何管理服务在不同操作系统上的重新启动、重新加载和状态命令。

  • true 表示 Chef 可以使用 init 脚本或其他服务提供程序来运行该命令。

  • false 表示 Chef 必须尝试以其他方式运行该命令。

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

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

tomcat::container_config

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 资源,每个资源都基于一个说明书模板文件创建配置文件,设置文件属性,以及通知 Chef 重新启动服务。

Tomcat 环境配置文件

第一个 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 目录的不同子目录中。ubuntuamazon 目录包含适用于它们各自操作系统的模板。default 文件夹包含一个仅具有一个注释行的伪模板,仅当您尝试使用不受支持的操作系统在一个实例上运行此配方时,才会使用这个模板。tomcat::container_config 配方不需要指定要使用哪个 tomcat_env_config.erb。Chef 根据 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_OPTS 可用于指定 Java 选项,如库路径。如果使用默认的属性值,则模板不会为 Amazon Linux 设置 Java 选项。您可以通过覆盖 ['tomcat']['java_opts'] 属性 (例如,使用自定义 JSON 属性) 来设置您自己的 Java 选项。有关示例,请参阅创建堆栈

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_USERTOMCAT6_GROUP (表示 Tomcat 用户和组) 均被设置为 tomcat6

    如果您将 ['tomcat']['base_version'] 设置为 tomcat7,则变量名称将解析为 TOMCAT7_USERTOMCAT7_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

  • 如果 Tomcat 版本低于 7,则模板取消 LC_ALL 的设置,这可以解决 Ubuntu 错误。

注意

使用默认属性,其中一些环境变量会直接被设置为其默认值。但是,将环境变量显式设置为属性意味着:您可以定义自定义 JSON 属性来覆盖默认属性并提供自定义值。有关覆盖属性的更多信息,请参阅覆盖属性

要查看完整的模板文件,请参阅 source code

Server.xml 配置文件

第二个 template 资源使用 server.xml.erb 创建 system.xml 配置文件,它用于配置 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

tomcat::apache_tomcat_bind

tomcat::apache_tomcat_bind 配方使 Apache 服务器能够充当 Tomcat 的前端,接收传入请求、将其转发到 Tomcat 并将响应返回给客户端。此示例使用 mod_proxy 作为 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 模块和一个基于协议的模块。对于协议模块,您有两个选项:

配方的这两个 execute 资源 都运行 a2enmod 命令,该命令通过创建所需的符号链接来启用特定模块:

  • 第一个 execute 资源启用 proxy 模块。

  • 第二个 execute 资源启用协议模块,它在默认情况下被设置为 proxy_http

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

apache2::service配方是 AWS OpsWorks Stacks 的内置配方,用于定义 Apache 服务。有关更多信息,请参阅 AWS OpsWorks Stacks GitHub 存储库中的配方

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 -%>

该模板使用ProxyPassProxyPassReverse指令来配置用于在 Apache 和 Tomcat 之间传递流量的端口。由于这两个服务器在同一个实例上,所以它们可以使用本地主机 URL,默认情况下,它们均被设置为 http://localhost:8080