在 Windows Server 故障轉移叢集中設定 IIS World Wide Web 發行服務

本文說明如何在 WSFC) (Windows Server 故障轉移叢集中設定 Microsoft Internet Information Services (IIS) World Wide Web Publishing Service (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) 的使用,作為改善 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 或更新版本的範例。

  1. 在所有叢集節點上安裝 Web 伺服器角色。 如需詳細資訊,請參閱 IIS 7 部署指南
  2. 在所有叢集節點上安裝故障轉移叢集功能,並建立叢集。 如需詳細資訊,請參閱 故障轉移叢集部署指南
  3. 設定將用於 IIS 共用組態的檔案共用。
  4. 在所有叢集節點上設定 IIS 共用設定。
  5. 在所有叢集節點上設定 IIS 離線檔案以進行共享設定。
  6. 設定網站 (包括相關聯的應用程式集區) ,並指定其內容在一個叢集節點上的位置。
  7. 在故障轉移叢集中建立一般腳本,以設定網站的高可用性。

設定將用於 IIS 共用設定的檔案共用

  1. 建立將存取將用於 IIS 共用設定之共用的使用者。
  2. 建立檔案共用。 此共用將用來儲存 IIS 共用組態,這些組態將在所有叢集節點上的 IIS 之間共用。 有多個選項:
  3. 設定您在步驟 2 中建立之共享的許可權。 將您在步驟 1 完整控制許可權中建立的用戶許可權授與檔案共用和 NTFS 許可權。
  4. 確認所有叢集節點都可以流覽至檔案共用。 檔案共享的路徑為 \\<fileserver>\<share>

在所有叢集節點上設定 IIS 共用設定

注意事項

Windows 2008 Server 上的 IIS 共用設定發生問題,因為缺少的 Application Host Helper Service許可權。 若要讓共用設定能夠運作,您必須在 Windows 2008 Server 上設定 IIS 共用設定時,遵循下列步驟。

  1. 開啟系統管理命令提示字元。

  2. 執行下列命令:

    net stop apphostsvc
    
  3. 執行下列命令:

    sc privs apphostsvc SeChangeNotifyPrivilege/SeTcbPrivilege/SeImpersonatePrivilege
    
  4. 執行下列命令:

    net start apphostsvc
    

在叢集中的每部 Windows 2008 伺服器上完成這些步驟之後,請繼續設定 IIS 共用設定,如本節所述。

在其中一個叢集節點上,將共用組態導出至檔案共用:

  1. 流覽至 [ 系統管理工具],然後選 取 [Internet Information Services (IIS) Manager]
  2. 在左窗格中,選取 伺服器名稱 節點。
  3. 按兩下 [共享組態] 圖示。
  4. 在 [ 共用組態] 頁面上 ,選取 [ 動作 ] 窗格中的 [匯出組態] (右窗格) 將組態檔從本機計算機匯出至另一個位置。
  5. 在 [匯出組 態] 對話框的 [實體路徑] 方塊中,輸入檔案共用 (\\<fileserver>\<share>) 的路徑
  6. 選取 [聯機身分],然後輸入具有共用組態儲存所在共用存取權之用戶帳戶的使用者名稱和密碼,然後選取 [ 確定]。 此帳戶將用來存取共用。 您應該使用非網域系統管理員的受限制 Active Directory 帳戶。
  7. 在 [ 匯出 組態] 對話框中,輸入將用來保護加密密鑰的密碼,然後選取 [ 確定]
  8. 在 [ 共享組態] 頁面上,選取 [ 啟用共用設定] 複選框。
  9. 輸入您先前輸入的實體路徑、用戶帳戶和密碼,然後在 [動作] 窗格中選取 [用]。
  10. 在 [ 加密密鑰密碼 ] 對話框中,輸入您稍早設定的加密金鑰密碼,然後選取 [ 確定]
  11. 在 [ 共享組態] 對話框中,選取 [ 確定]
  12. 選取 [確定]

在其他每個叢集節點上,使用您剛匯出至檔案共享的共享組態:

  1. 流覽至 [ 系統管理工具],然後選 取 [Internet Information Services (IIS) Manager]
  2. 選取 伺服器名稱 節點。
  3. 按兩下 [共享組態] 圖示。
  4. 在 [ 共享組態] 頁面上,選取 [ 啟用共用設定] 複選框。
  5. 輸入檔案共享的實體路徑 (\\<fileserver>\<share>) 、使用者帳戶和您先前輸入的密碼,然後在 [動作] 窗格中選取 [用]
  6. 在 [ 加密密鑰密碼 ] 對話框中,輸入您稍早設定的加密金鑰密碼,然後選取 [ 確定]
  7. 在 [ 共享組態] 對話框中,選取 [ 確定]
  8. 選取 [確定]

注意事項

如需如何在 IIS 中設定共用組態的詳細資訊,請瀏覽 共用組態

在所有叢集節點上設定 IIS 離線檔案以進行共享設定

在每個叢集節點上,啟用離線檔案:

  1. 安裝桌面體驗

    1. 流覽至 [系統管理工具],然後選取 [伺服器管理員]。
    2. 在左窗格中,選取 [ 功能]
    3. 選取右窗格中的 [ 新增功能 ]。
    4. 根據您的 Windows 版本,執行下列其中一個動作:
      • 如需 Windows Server 2016,請造訪安裝具有桌面體驗的伺服器
      • 針對 Windows Server 2102 和 2012 R2,請在功能清單的 [使用者介面和基礎結構] 下選擇 [桌面體驗]。
      • 針對 Windows Server 2008 和 2008 R2,選擇 [桌面體驗]
    5. 取 [安裝 ] 以安裝 [桌面體驗]。
    6. 重新啟動電腦。
  2. 執行下列其中一項:

    • 針對 Windows Server 2012 2012 R2 和 2016,選取 [控制台 中的 [同步處理中心],然後選取 [管理離線檔案]
    • 針對 Windows Server 2008 和 2008 R2,選取 [控制台 中的脫機檔案]。
  3. 取 [啟用離線檔案]。 此時不要重新啟動電腦。

  4. 確定快取設定為唯讀。 若要這樣做,請在提升許可權的 Cmd 提示字元中執行下列命令:

    REG ADD "HKLM\System\CurrentControlSet\Services\CSC\Parameters" /v ReadOnlyCache /t REG_DWORD /d 1 /f
    
  5. 重新啟動電腦。

  6. 從電腦瀏覽至檔案伺服器。 以滑鼠右鍵按兩下包含 IIS 共用設定的共享,然後選取 [ 永遠離線可用]

    注意事項

    如果您將檔案共享設定為在裝載 IIS 節點的相同故障轉移叢集上具有高可用性,如果您所在的叢集節點裝載高可用性文件伺服器,當您以滑鼠右鍵按兩下共用時,將不會顯示 [ 永遠可用離線 ] 選項。 您必須將高可用性檔案伺服器應用程式移至另一個節點。

  7. 在 控制台 中,開啟 [脫機檔案]。 選 取 [開啟同步處理中心],然後選取 [ 排程]

  8. 排程每天的離線檔案同步處理,或根據您的需求。 您也可以將離線同步設定為每隔幾分鐘執行一次。 即使您未設定排程器,當您變更 Applicationhost.config 檔案中的某個專案時,變更也會反映在網頁伺服器上。

注意事項

如需如何在 IIS 中設定共用組態離線檔案的詳細資訊,請參閱 共用組態的離線檔案

設定網站,並指定其內容在一個叢集節點上的位置

尋找擁有網站內容檔案將保留之叢集磁碟資源的叢集節點:

  1. 流覽至 [ 系統管理工具],然後選取 [ 故障轉移叢集管理員]
  2. 線上到叢集。 如果您在其中一個叢集節點上,叢集會自動出現在清單上。
  3. 在 [ 記憶體] 底下,尋找網頁內容所在的磁碟資源。 若要這樣做,請展開磁碟資源的儲存樹狀結構。 請確定叢集上任何其他高可用性應用程式不會使用記憶體。 您會在 [可用的記憶體] 下找到 記憶體
  4. 此資源在在線的叢集節點。 您將在該叢集節點上設定 IIS。
  5. 叢集磁碟資源名稱。

您會將此項目用於內容檔案。 在資源上線的叢集節點上,將網頁伺服器設定為使用網站內容的共用磁碟:

  1. 流覽至 [ 系統管理工具],然後選 取 [Internet Information Services (IIS) Manager]
  2. 在左窗格中,展開伺服器名稱節點。
  3. 展開 [網站],然後在 [ 網站] 底下,選取您要設定的網站。
  4. 在右窗格中,選取 [管理網站] 底下的 [進階設定]
  5. 在 [一般設定] 底下找出 [實體路徑] 屬性,然後輸入網站內容檔案所在的位置。 這是您在上一個程式的步驟 5 中記下的叢集磁碟資源位置。
  6. 選取 [確定]

在故障轉移叢集管理員中建立一般腳本,以設定網站的高可用性

在設定 IIS Web 伺服器高可用性的最後一個步驟中,設定將用來監視網站網站和應用程式集區的一般腳本資源:

  1. 在每個叢集節點上,將本文結尾所提供的文稿複製到 Windows\System32\inetsrv\Clusweb7.vbs

  2. 根據預設,腳本會監視名為 Default Web Site 的網站,以及名為 DefaultAppPool 的應用程式集區。 如果這些不是正確的網站和應用程式集區,請變更 SITE_NAME and APP_POOL_NAME 變數。 請確定文稿中的相同網站和應用程式集區存在於所有叢集節點上。

    注意事項

    名稱會區分大小寫。

  3. 流覽至 [ 系統管理工具],然後選取 [ 故障轉移叢集管理員]

  4. 線上到叢集。 如果您在其中一個叢集節點上,叢集會自動出現在清單上。

  5. 執行下列其中一項:

    • 針對 Windows Server 2012 2012 R2 和 2016,以滑鼠右鍵按兩下 [角色],然後選取 [設定角色] 加以建立。
    • 針對 Windows Server 2008 和 2008 R2,以滑鼠右鍵按兩下叢集,然後選取 [設定 服務或應用程式]。 精靈會建立高可用性工作負載。
  6. 選取 [一般腳本]

  7. %systemroot%\System32\Inetsrv\clusweb7.vbs選取腳本檔案。

  8. 將用戶端存取點 (CAP) 名稱設定為用戶端將用來連線到高可用性網站的網站名稱。 指定要用於網站 CAP 的靜態 IP。 如果您使用動態主機設定通訊協定 (DHCP) ,則不會顯示此選項。

  9. 在 [ 選取記憶體 ] 步驟中,選取網站內容檔案所在的叢集共用磁碟。 叢集上任何其他高可用性應用程式應該不會使用記憶體。

    注意事項

    如果用於 IIS 共用組態的檔案共用裝載於相同的叢集上,則應該在這裡使用不同的磁碟資源。

  10. 確認設定之後,精靈會建立叢集群組、叢集資源,以及資源之間的相依性,然後讓資源上線。

    注意事項

    若要在相同的故障轉移叢集上裝載多個高可用性網站,請遵循與上述相同的步驟。 不過,針對每個網站和不同的叢集共用記憶體使用不同的腳本檔案。 例如,在 中 %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>