在 Windows Server 故障转移群集中配置 IIS 万维网发布服务
本文介绍如何在 Windows Server 故障转移群集 (WSFC) 中配置 Microsoft Internet Information Services (IIS) 万维网发布服务 (W3SVC)。
原始产品版本: Windows Server 2008 及更高版本、Internet Information Services 8.0 及更高版本
原始 KB 数: 970759
简介
本文中的过程仅适用于万维网发布服务。 有关如何在故障转移群集中配置 FTP 发布服务的说明,请参阅 如何在 Windows Server 故障转移群集中为 IIS 配置 FTP。
详细信息
在早期版本的 Internet Information Services 中,Microsoft提供了通用资源监视器组件,以支持使用Microsoft群集基础结构的高可用性 Web 服务器实例。 但是,需要自定义代码才能充分实现此类解决方案的潜力。 此外,Microsoft提供的泛型脚本无法满足客户需求。 若要在使用 Windows Server 故障转移群集的群集环境中配置 IIS 7.0 或更高版本,必须使用自定义(脚本)代码来启用此类高可用性方案。 执行此操作时,用户可以自定义设置以满足其要求。 这样可以完全控制 Web 应用程序的高可用性集成。 此外,IIS 7.0 中引入的用于管理和监视的脚本接口提供了比之前提供的脚本更丰富的环境。
注意
IIS 7.0 安装文件错误地包括 IIS 6.0 中用于 IIS 群集管理任务的 Clusweb.vbs 和 Clusftp.vbs 脚本文件。 不要将这些脚本用于 IIS 7.0 或更高版本。
建议管理员仔细评估使用网络负载均衡(NLB)作为提高运行 IIS 7.0 或更高版本的多个服务器的 Web 应用程序的可伸缩性和可用性的主要和首选方法,而不是使用故障转移群集。 NLB 的优点之一是,所有服务器都可以积极参与同时处理传入的超文本传输协议 (HTTP) 请求。 另一个好处是,在 NLB IIS 环境中,在仍提供 Web 应用程序的高可用性的同时,支持滚动更新和回滚可能更容易。 有关在 NLB 环境中使用 IIS 7.0 或更高版本的详细信息,请参阅以下文章:
请务必考虑,通过群集化 IIS 服务来群集 IIS 并不总是保证 Web 应用程序的高可用性解决方案。 虽然 IIS 服务(特别是 WWW 服务)可能已启动并运行,但特定的应用程序池的托管进程可能已终止,或者应用程序可能会引发内部服务器 HTTP 错误。 使用自定义脚本对 Web 应用程序进行群集化并监视其运行状况是正确的,建议使用故障转移群集实现高可用性 IIS 群集。 下面是一个示例脚本,用于监视应用程序池的状态,以确定它是否已启动。
若要使用故障转移群集为 IIS 7.0 或更高版本的 Web 服务器配置高可用性,请执行以下步骤。 下面更详细地介绍了步骤 3 到 7。 本文后面的示例脚本可用作 IIS 7.0 或更高版本的示例。
- 在所有群集节点上安装 Web 服务器角色。 有关详细信息,请参阅 IIS 7 部署指南。
- 在所有群集节点上安装故障转移群集功能并创建群集。 有关详细信息,请参阅 故障转移群集部署指南。
- 设置将用于 IIS 共享配置的文件共享。
- 在所有群集节点上配置 IIS 共享配置。
- 为所有群集节点上的共享配置配置配置配置 IIS 脱机文件。
- 配置网站(包括关联的应用程序池),并指定其内容在一个群集节点上的位置。
- 通过在故障转移群集中创建通用脚本,为网站配置高可用性。
设置将用于 IIS 共享配置的文件共享
- 创建将访问将用于 IIS 共享配置的共享的用户。
- 创建文件共享。 此共享将用于存储将在所有群集节点上的 IIS 之间共享的 IIS 共享配置。 有多个选项:
- 在不属于任何故障转移群集的独立服务器上,创建文件共享。
- 在另一个 Windows Server 故障转移群集上,创建高可用性文件共享。 有关详细信息,请访问 故障转移群集分步指南:配置双节点文件服务器故障转移群集。
- 在将托管高可用性网站的同一故障转移群集上,创建高可用性文件共享。 有关详细信息,请参阅 故障转移群集分步指南:配置双节点文件服务器故障转移群集。
- 设置在步骤 2 中创建的共享的权限。 为在步骤 1 中创建的用户授予对文件共享和 NTFS 权限的完全控制权限。
- 确认所有群集节点都可以浏览到文件共享。 文件共享的路径为
\\<fileserver>\<share>
。
在所有群集节点上配置 IIS 共享配置
注意
由于缺少 Windows 2008 服务器的特权 Application Host Helper Service
,Windows 2008 服务器上的 IIS 共享配置出现问题。 若要使共享配置正常工作,必须在 Windows 2008 Server 上设置 IIS 共享配置时执行以下步骤。
打开管理命令提示符。
运行以下命令:
net stop apphostsvc
运行以下命令:
sc privs apphostsvc SeChangeNotifyPrivilege/SeTcbPrivilege/SeImpersonatePrivilege
运行以下命令:
net start apphostsvc
在群集中的每个 Windows 2008 Server 上完成这些步骤后,请继续按照本节中所述设置 IIS 共享配置。
在某个群集节点上,将共享配置导出到文件共享:
- 导航到管理工具,然后选择“Internet Information Services”(IIS)管理器。
- 在左窗格中,选择 服务器名称 节点。
- 双击“共享配置”图标。
- 在“共享配置”页上,选择“操作”窗格中的“导出配置”(右窗格),将配置文件从本地计算机导出到另一个位置。
- 在“ 导出配置 ”对话框中,在“物理路径”框中键入文件共享 (
\\<fileserver>\<share>
) 的路径 。 - 选择“连接方式”,然后键入有权访问在其中存储共享配置的共享的用户帐户的用户名和密码,然后选择“确定”。 此帐户将用于访问共享。 应使用非域管理员的受限 Active Directory 帐户。
- 在 “导出配置 ”对话框中,键入将用于保护加密密钥的密码,然后选择“ 确定”。
- 在 “共享配置 ”页上,选中“ 启用共享配置 ”复选框。
- 键入之前输入的物理路径、用户帐户和密码,然后在“操作”窗格中选择“应用”。
- 在“加密密钥密码”对话框中,键入之前设置的加密密钥密码,然后选择“确定”。
- 在 “共享配置 ”对话框中,选择“ 确定”。
- 选择“确定”。
在所有其他群集节点上,使用刚刚导出到文件共享的共享配置:
- 导航到管理工具,然后选择“Internet Information Services”(IIS)管理器。
- 选择 服务器名称 节点。
- 双击“共享配置”图标。
- 在 “共享配置 ”页上,选中“ 启用共享配置 ”复选框。
- 键入文件共享(
\\<fileserver>\<share>
)、用户帐户和之前输入的密码的物理路径,然后在“操作”窗格中选择“应用”。 - 在“加密密钥密码”对话框中,键入之前设置的加密密钥密码,然后选择“确定”。
- 在 “共享配置 ”对话框中,选择“ 确定”。
- 选择“确定”。
注意
有关如何在 IIS 中设置共享配置的详细信息,请访问 共享配置。
为所有群集节点上的共享配置配置配置配置 IIS 脱机文件
在每个群集节点上,启用脱机文件:
安装桌面体验
- 导航到管理工具,然后选择服务器管理器。
- 在左窗格中,选择“ 功能”。
- 在右窗格中选择“ 添加功能 ”。
- 根据 Windows 版本执行以下任一操作:
- 对于 Windows Server 2016,请访问 安装具有桌面体验的服务器。
- 对于 Windows Server 2102 和 2012 R2,请选择功能列表中的用户界面和基础结构下的桌面体验。
- 对于 Windows Server 2008 和 2008 R2,请选择“ 桌面体验”。
- 选择“安装”以安装桌面体验。
- 重新启动计算机。
执行下列操作之一:
- 对于 Windows Server 2012、2012 R2 和 2016,请在控制面板中选择同步中心,然后选择“管理脱机文件”。
- 对于 Windows Server 2008 和 2008 R2,请选择控制面板中的脱机文件。
选择“ 启用脱机文件”。 目前不要重新启动计算机。
确保缓存设置为只读。 若要执行此操作,请在提升的 cmd 提示符下运行以下命令:
REG ADD "HKLM\System\CurrentControlSet\Services\CSC\Parameters" /v ReadOnlyCache /t REG_DWORD /d 1 /f
重新启动计算机。
从计算机浏览到文件服务器。 右键单击包含 IIS 共享配置的共享,然后选择 “始终可用脱机”。
注意
如果将文件共享设置为在承载 IIS 节点的同一故障转移群集上高度可用, 则右键单击共享时,如果所在的群集节点托管高度可用的文件服务器,则不会显示 Always Available 脱机 选项。 需要将高可用文件服务器应用程序移到另一个节点。
在控制面板中,打开脱机文件。 选择“ 打开同步中心”,然后选择“ 计划”。
计划每天或根据要求进行脱机文件同步。 还可以将脱机同步配置为每隔几分钟运行一次。 即使未设置计划程序,在 Applicationhost.config 文件中更改某些内容时,更改也会反映在 Web 服务器上。
注意
有关如何在 IIS 中为共享配置配置脱机文件的详细信息,请参阅 共享配置的脱机文件。
配置网站,并指定其内容在一个群集节点上的位置
查找拥有群集磁盘资源的群集节点,网站内容文件将保留在其中:
- 导航到 管理工具,然后选择“ 故障转移群集管理器”。
- 连接到群集。 如果位于其中一个群集节点上,群集将自动显示在列表中。
- 在“存储”下,找到网页内容将驻留的磁盘资源。 为此,请展开磁盘资源的存储树。 确保群集上的任何其他高可用性应用程序不使用存储。 可在“可用存储”下 找到存储。
- 此资源处于联机状态的群集节点。 你将在该群集节点上配置 IIS。
- 群集磁盘资源名称。
你将对内容文件使用此密钥。 在资源处于联机状态的群集节点上,将 Web 服务器配置为将共享磁盘用于网站内容:
- 导航到管理工具,然后选择“Internet Information Services”(IIS)管理器。
- 在左窗格中,展开服务器名称节点。
- 展开“站点”,然后在“站点”下,选择要配置的站点。
- 在右窗格中,选择“管理网站”下的“高级设置”。
- 在“常规”设置下找到“物理路径”属性,然后键入网站内容文件所在的位置。 它是在上一过程的步骤 5 中记录的群集磁盘资源的位置。
- 选择“确定”。
通过在故障转移群集管理器中创建通用脚本,为网站配置高可用性
若要为 IIS Web 服务器配置高可用性的最后一步,请设置用于监视网站的网站和应用程序池的通用脚本资源:
在每个群集节点上,将本文
Windows\System32\inetsrv\Clusweb7.vbs
末尾提供的脚本复制到其中。默认情况下,脚本监视名为 “默认网站 ”的网站和名为 DefaultAppPool 的应用程序池。 如果这些不是正确的网站和应用程序池,请
SITE_NAME and APP_POOL_NAME
更改变量。 确保所有群集节点上都存在脚本中的相同网站和应用程序池。注意
名称区分大小写。
导航到 管理工具,然后选择“ 故障转移群集管理器”。
连接到群集。 如果位于其中一个群集节点上,群集将自动显示在列表中。
执行下列操作之一:
- 对于 Windows Server 2012、2012 R2 和 2016,右键单击“角色”,然后选择“配置角色”以创建它。
- 对于 Windows Server 2008 和 2008 R2,右键单击群集,然后选择“ 配置服务或应用程序”。 向导将创建高可用性工作负荷。
选择 通用脚本。
从
%systemroot%\System32\Inetsrv\clusweb7.vbs
中选择脚本文件。将客户端接入点(CAP)名称设置为客户端将用于连接到高可用性网站的网站名称。 指定要用于网站 CAP 的静态 IP。 如果使用动态主机配置协议(DHCP),则不会显示此选项。
在 “选择存储 ”步骤中,选择网站内容文件所在的群集共享磁盘。 群集上的任何其他高可用性应用程序都应使用存储。
注意
如果用于 IIS 共享配置的文件共享托管在同一群集上,则应在此处使用不同的磁盘资源。
确认设置后,向导将创建群集组、群集资源以及资源之间的依赖关系,然后将资源联机。
注意
若要在同一故障转移群集上托管多个高可用性网站,请执行以下步骤。 但是,对每个网站和不同的群集共享存储使用不同的脚本文件。 例如,对于
%systemroot%\System32\Inetsrv
第一个网站,请使用 clusweb7.vbs,将 clweb7-2.vbs 用于第二个网站,将 clweb7-3.vbs 用于第三个网站等。 每个脚本文件监视不同的网站和应用程序池。
以下脚本仅用于示例目的,Microsoft未显式支持。 在 IIS 7.0 或更高版本的群集环境中使用此脚本是有风险的。
'<begin script sample>
'This script provides high availability for IIS websites
'By default, it monitors the "Default Web Site" and "DefaultAppPool"
'To monitor another website, change the SITE_NAME below
'To monitor another application pool, change the APP_POOL_NAME below
'More thorough and application-specific health monitoring logic can be added to the script if needed
Option Explicit
DIM SITE_NAME
DIM APP_POOL_NAME
Dim START_WEB_SITE
Dim START_APP_POOL
Dim SITES_SECTION_NAME
Dim APPLICATION_POOLS_SECTION_NAME
Dim CONFIG_APPHOST_ROOT
Dim STOP_WEB_SITE
'Note:
'Replace this with the site and application pool you want to configure high availability for
'Make sure that the same website and application pool in the script exist on all cluster nodes. Note that the names are case-sensitive.
SITE_NAME = "Default Web Site"
APP_POOL_NAME = "DefaultAppPool"
START_WEB_SITE = 0
START_APP_POOL = 0
STOP_WEB_SITE = 1
SITES_SECTION_NAME = "system.applicationHost/sites"
APPLICATION_POOLS_SECTION_NAME = "system.applicationHost/applicationPools"
CONFIG_APPHOST_ROOT = "MACHINE/WEBROOT/APPHOST"
'Helper script functions
'Find the index of the website on this node
Function FindSiteIndex(collection, siteName)
Dim i
FindSiteIndex = -1
For i = 0 To (CInt(collection.Count) - 1)
If collection.Item(i).GetPropertyByName("name").Value = siteName Then
FindSiteIndex = i
Exit For
End If
Next
End Function
'Find the index of the application pool on this node
Function FindAppPoolIndex(collection, appPoolName)
Dim i
FindAppPoolIndex = -1
For i = 0 To (CInt(collection.Count) - 1)
If collection.Item(i).GetPropertyByName("name").Value = appPoolName Then
FindAppPoolIndex = i
Exit For
End If
Next
End Function
'Get the state of the website
Function GetWebSiteState(adminManager, siteName)
Dim sitesSection, sitesSectionCollection, siteSection, index, siteMethods, startMethod, executeMethod
Set sitesSection = adminManager.GetAdminSection(SITES_SECTION_NAME, CONFIG_APPHOST_ROOT)
Set sitesSectionCollection = sitesSection.Collection
index = FindSiteIndex(sitesSectionCollection, siteName)
If index = -1 Then
GetWebSiteState = -1
End If
Set siteSection = sitesSectionCollection(index)
GetWebSiteState = siteSection.GetPropertyByName("state").Value
End Function
'Get the state of the ApplicationPool
Function GetAppPoolState(adminManager, appPool)
Dim configSection, index, appPoolState
set configSection = adminManager.GetAdminSection(APPLICATION_POOLS_SECTION_NAME, CONFIG_APPHOST_ROOT)
index = FindAppPoolIndex(configSection.Collection, appPool)
If index = -1 Then
GetAppPoolState = -1
End If
GetAppPoolState = configSection.Collection.Item(index).GetPropertyByName("state").Value
End Function
'Start the w3svc service on this node
Function StartW3SVC()
Dim objWmiProvider
Dim objService
Dim strServiceState
Dim response
'Check to see if the service is running
set objWmiProvider = GetObject("winmgmts:/root/cimv2")
set objService = objWmiProvider.get("win32_service='w3svc'")
strServiceState = objService.state
If ucase(strServiceState) = "RUNNING" Then
StartW3SVC = True
Else
'If the service is not running, try to start it
response = objService.StartService()
'response = 0 or 10 indicates that the request to start was accepted
If ( response <> 0 ) and ( response <> 10 ) Then
StartW3SVC = False
Else
StartW3SVC = True
End If
End If
End Function
'Start the application pool for the website
Function StartAppPool()
Dim ahwriter, appPoolsSection, appPoolsCollection, index, appPool, appPoolMethods, startMethod, callStartMethod
Set ahwriter = CreateObject("Microsoft.ApplicationHost.WritableAdminManager")
Set appPoolsSection = ahwriter.GetAdminSection(APPLICATION_POOLS_SECTION_NAME, CONFIG_APPHOST_ROOT)
Set appPoolsCollection = appPoolsSection.Collection
index = FindAppPoolIndex(appPoolsCollection, APP_POOL_NAME)
Set appPool = appPoolsCollection.Item(index)
'See if it is already started
If appPool.GetPropertyByName("state").Value = 1 Then
StartAppPool = True
Exit Function
End If
'Try To start the application pool
Set appPoolMethods = appPool.Methods
Set startMethod = appPoolMethods.Item(START_APP_POOL)
Set callStartMethod = startMethod.CreateInstance()
callStartMethod.Execute()
'If started return true, otherwise return false
If appPool.GetPropertyByName("state").Value = 1 Then
StartAppPool = True
Else
StartAppPool = False
End If
End Function
'Start the website
Function StartWebSite()
Dim ahwriter, sitesSection, sitesSectionCollection, siteSection, index, siteMethods, startMethod, executeMethod
Set ahwriter = CreateObject("Microsoft.ApplicationHost.WritableAdminManager")
Set sitesSection = ahwriter.GetAdminSection(SITES_SECTION_NAME, CONFIG_APPHOST_ROOT)
Set sitesSectionCollection = sitesSection.Collection
index = FindSiteIndex(sitesSectionCollection, SITE_NAME)
Set siteSection = sitesSectionCollection(index)
if siteSection.GetPropertyByName("state").Value = 1 Then
'Site is already started
StartWebSite = True
Exit Function
End If
'Try to start site
Set siteMethods = siteSection.Methods
Set startMethod = siteMethods.Item(START_WEB_SITE)
Set executeMethod = startMethod.CreateInstance()
executeMethod.Execute()
'Check to see if the site started, if not return false
If siteSection.GetPropertyByName("state").Value = 1 Then
StartWebSite = True
Else
StartWebSite = False
End If
End Function
'Stop the website
Function StopWebSite()
Dim ahwriter, sitesSection, sitesSectionCollection, siteSection, index, siteMethods, startMethod, executeMethod, autoStartProperty
Set ahwriter = CreateObject("Microsoft.ApplicationHost.WritableAdminManager")
Set sitesSection = ahwriter.GetAdminSection(SITES_SECTION_NAME, CONFIG_APPHOST_ROOT)
Set sitesSectionCollection = sitesSection.Collection
index = FindSiteIndex(sitesSectionCollection, SITE_NAME)
Set siteSection = sitesSectionCollection(index)
'Stop the site
Set siteMethods = siteSection.Methods
Set startMethod = siteMethods.Item(STOP_WEB_SITE)
Set executeMethod = startMethod.CreateInstance()
executeMethod.Execute()
End Function
'Cluster resource entry points. More details here:
'http://msdn.microsoft.com/en-us/library/aa372846(VS.85).aspx
'Cluster resource Online entry point
'Make sure the website and the application pool are started
Function Online( )
Dim bOnline
'Make sure w3svc is started
bOnline = StartW3SVC()
If bOnline <> True Then
Resource.LogInformation "The resource failed to come online because w3svc could not be started."
Online = False
Exit Function
End If
'Make sure the application pool is started
bOnline = StartAppPool()
If bOnline <> True Then
Resource.LogInformation "The resource failed to come online because the application pool could not be started."
Online = False
Exit Function
End If
'Make sure the website is started
bOnline = StartWebSite()
If bOnline <> True Then
Resource.LogInformation "The resource failed to come online because the web site could not be started."
Online = False
Exit Function
End If
Online = true
End Function
'Cluster resource offline entry point
'Stop the website
Function Offline( )
StopWebSite()
Offline = true
End Function
'Cluster resource LooksAlive entry point
'Check for the health of the website and the application pool
Function LooksAlive( )
Dim adminManager, appPoolState, configSection, i, appPoolName, appPool, index
i = 0
Set adminManager = CreateObject("Microsoft.ApplicationHost.AdminManager")
appPoolState = -1
'Get the state of the website
if GetWebSiteState(adminManager, SITE_NAME) <> 1 Then
Resource.LogInformation "The resource failed because the " & SITE_NAME & " web site is not started."
LooksAlive = false
Exit Function
End If
'Get the state of the Application Pool
if GetAppPoolState(adminManager, APP_POOL_NAME) <> 1 Then
Resource.LogInformation "The resource failed because Application Pool " & APP_POOL_NAME & " is not started."
LooksAlive = false
Exit Function
End if
'Web site and Application Pool state are valid return true
LooksAlive = true
End Function
'Cluster resource IsAlive entry point
'Do the same health checks as LooksAlive
'If a more thorough than what we do in LooksAlive is required, this should be performed here
Function IsAlive()
IsAlive = LooksAlive
End Function
'Cluster resource Open entry point
Function Open()
Open = true
End Function
'Cluster resource Close entry point
Function Close()
Close = true
End Function
'Cluster resource Terminate entry point
Function Terminate()
Terminate = true
End Function
'<end script sample>