The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何啟用 ASP.NET Core 6.0 部署到 IIS 的陰影複製 (Shadow-copying) 功能

ASP.NET Core 可以部署至 IIS 網站伺服器,但一直以來都有一個毛病,那就是 ASP.NET Core 網站在運行的過程中,許多 *.dll 檔案會被鎖定,導致這些檔案無法順利更新,必須暫時關閉應用程式集區才能順利對網站進行部署。從 ASP.NET Core 6.0 開始,ASP.NET Core Module 包含了一項實驗性功能名叫 陰影複製(Shadow-copying),這個功能可以徹底解決網站運行中無法部署程式的問題。

使用 app_offline.htm 關閉網站

其實一直以來,微軟官方建議的更新手段,是在網站根目錄加上 app_offline.htm 檔案,強迫關閉應用程式集區。但是這種更新方法會導致網站在更新部署的過程中無法提供服務,以致於網站中斷服務,所以一直不是很理想的部署方法。

首先,當網站加上 app_offline.htm 檔案之後,應用程式集區會立即停止運作。注意,並不是「網站」被關閉,網站其實還在,只是整個網站無論用戶端開啟任何頁面,一律只提供 app_offline.htm 檔案的內容,且所有 HTTP 要求的 Content-Type 固定為 text/html,以及 HTTP 回應狀態碼為 503 Service Unavailable

不過,即便你加上了 app_offline.htm 檔案,其實還要等 ASP.NET Core 的程式停止 (Graceful Shutdown),所以這些 *.dll 檔案並不會立即解除鎖定,而檔案解鎖的時間可能會介於 1 ~ 30 秒不等,因此更新程式的時候,還需要額外實作 retry (重新嘗試) 機制,以確保 ASP.NET Core 程式可以順利更新。

使用 ASP.NET Core Module 的陰影複製 (Shadow-copying)

當我們使用 .NET SDK 的 dotnet publish 命令發行 ASP.NET Core 網站時,預設會自動產生一個給 IIS 站台專用的 web.config 檔案,其內容如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\WebApplication1.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
    </system.webServer>
  </location>
</configuration>

要啟用 ASP.NET Core Module 的 陰影複製 (Shadow-copying) 功能,必須調整 <handlerSettings> 設定如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\WebApplication1.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess">
        <handlerSettings>
          <handlerSetting name="experimentalEnableShadowCopy" value="true" />
          <handlerSetting name="shadowCopyDirectory" value="../ShadowCopyDirectory/" />
          <!-- Only enable handler logging if you encounter issues-->
          <!-- <handlerSetting name="debugFile" value="../ShadowCopyLogs/aspnetcore-debug.log" /> -->
          <!-- <handlerSetting name="debugLevel" value="FILE,TRACE" /> -->
        </handlerSettings>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>

注意: 請務必安裝 ASP.NET Core 6.0 的 Hosting Bundle 才能啟用陰影複製功能。

陰影複製設定啟用之後,其運作原理如下:

  1. 使用者發送 HTTP 要求到 IIS 站台

  2. IIS 的 ASP.NET Core Module (ANCM) 將整個站台進行複製

    所有檔案 (包含 wwwroot 資料夾) 會複製一份到 shadowCopyDirectory 指定的目錄中,網站會複製到該目錄的子資料夾中,資料夾名稱是一個流水號,每次陰影複製會累積複製到這裡,太舊的版本會自動刪除,所以該資料夾不需要人工維護。

  3. IIS 的 ASP.NET Core Module (ANCM) 會改從陰影複製資料夾啟動網站

    所以你原本部署的站台目錄下所有檔案就不會被鎖定,之後也可以順利的部署網站。

設定完成後,當你下次更新 ASP.NET Core 網站程式,IIS 的 ASP.NET Core Module (ANCM) 會自動監視到檔案變更,並且自動將網站再次複製一份到 shadowCopyDirectory 指定的目錄中,然後 IIS 會自動切換到新的陰影複製版本來執行程式,因此使用者不會感受到任何斷線時間,是不是非常棒呢! 👍

相關連結

留言評論