6

如何正確地發行 ASP.NET Core 網站到遠端 IIS 站台

 2 years ago
source link: https://blog.miniasp.com/post/2021/06/07/Deploy-ASPNET-Core-to-IIS-without-locking-issue
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

我們最近有專案需要發行一個用 ASP.NET Core 5 開發的網站,有經驗的人應該知道,當網站正在執行時,尤其是 Windows 作業系統,過程中所有 *.dll 檔案都會被鎖定,無法成功覆蓋檔案,以致於自動部署失敗。今天這篇文章我打算來分享幾個常見的作法,以及我認為最好的作法。

手動關閉 IIS 站台 (WebSite)

這種方法的基本流程是:

  1. 停止 IIS 站台
  2. 進行網站程式更新
  3. 啟動 IIS 站台

我發現很多人會用 關閉 IIS 站台 的方式讓網站停下來,但我覺得這方法有點問題!🔥

  1. 首先,你今天的目的是要「更版」,而不是要「關閉站台」,用這種方式雖然可以讓網站關閉,但是卻不一定會關閉應用程式集區 (Application Pool)。怎麼說呢?因為一台 IIS 伺服器中,一個應用程式集區可以讓多個站台應用程式目錄使用,你就算停掉一個站台,可能還有其他的站台還在使用應用程式集區

    重點是,應用程式集區負責用來管理 w3wp.exe 程序 (Process),你的 Process 不停下來,現有被鎖定的 *.dll 組件一樣還是被鎖定,你一樣無法更版!

    一般我們都不建議應用程式集區共用,一個站台使用一個獨立的應用程式集區才正常!

  2. 其次,你在關閉站台的時候,網站是被直接關閉的狀態,完全連不上,是連 HTTP 狀態碼都不會回應的狀態,我覺得這很不正常,我個人很不喜歡這種方法!

  3. 其三,我們都知道 IIS 可以支援同一個 Port 80 同時服務多個不同域名的站台。所以當你在關閉站台的時候,很有可能使用者連進網址看到的確實「另一個網站」的內容,這就更怪了。這點我是完全無法接受!

📝 小結:我覺得這是個有問題的更版方法,請大家不要再這麼做了!

手動關閉應用程式集區 (Application Pool)

這種方法的基本流程是:

  1. 找出要關閉的站台所使用的應用程式集區
  2. 停止應用程式集區
  3. 進行網站程式更新
  4. 啟動應用程式集區

這種方法還行,不過若你有多個網站站台共用同一個應用程式集區,會將所有網站也一起關閉。

關閉應用程式集區之後,站台其實不會關閉,而是改回應 HTTP 503 Service Unavailable 錯誤:

HTTP Error 503. The service is unavailable.

這種作法有幾個優點:

  1. 網站依然可以正常回應,而且 HTTP 503 可以表達非常明確的意圖,就是服務無法使用
  2. 網站不會像上面第一種方法那樣,讓網站連到其他完全不相關的站台。

如果你想用 PowerShell 自動化這個過程,可以參考以下命令:

# 停止應用程式集區
(Get-IISAppPool "DefaultAppPool").Stop()

# >>> 進行網站程式更新 <<<

# 啟動應用程式集區
(Get-IISAppPool "DefaultAppPool").Start()

📝 小結:我覺得這種方法還能接受,只是手動關閉應用程式集區程序比較麻煩一點!

建立應用程式離線檔 (App Offline file)

這種方法的基本流程是:

  1. 在站台根目錄加入 app_offline.htm 檔案 (檔案不需要內容)
  2. 進行網站程式更新
  3. 在站台根目錄刪除 app_offline.htm 檔案

你看,多簡單!這其實是微軟官方建議的部署方法!👍

.NET Runtime 有個 ASP.NET Core Module (ANCM),它是一個 IIS 模組,用來幫助 IIS 管理 ASP.NET Core 的執行程序。

事實上 ANCM 會在啟動 Kestrel 的時候,同時監控應用程式根目錄下是否有個 app_offline.htm 檔案出現,只要有出現,就會立即對應用程式進行優雅的關閉(gracefully shut down),並且停止接聽從用戶端發來的要求(Requests)。

這裡有個重點,那就是所謂 優雅的關閉(gracefully shut down),這個概念我在 當 .NET Core 執行在 Linux 或 Docker 容器中如何優雅的結束 文章中分享過這個觀念。這個意思也就是說,當 app_offline.htm 檔案出現的時候,並不代表著 ASP.NET Core 程序會立即停止,如果你的程式沒寫好,或是有個長時間執行的前景執行緒沒有完成,都會延長程序終止的時間。在 IIS 中,應用程式集區進階設定有個 ShutdownTimeLimit 設定值,用來定義當執行程序不優雅的不結束時,最長可以允許等待多久。IIS 的預設值為 90 秒。

一般來說,當你在透過 CI/CD 自動部署的階段,在建立 app_offline.htm 檔案之後通常會等待幾秒鐘,這個時間長短很難說,端看你的程式與電腦當下的效能狀況而定。所以比較正確的作法,通常是實作 重試 (Rety) 機制,當部署失敗就重新再發布一次,重複個兩三次應該就非常足夠了。

更多關於應用程式離線檔

基本上,你的網站只要有了 app_offline.htm 檔案就會立刻讓網站所有要求全部都轉入 HTTP 503 的回應,而頁面中的回應內容就是 app_offline.htm 的檔案內容。

這裡有點要特別注意,請不要將 app_offline.htm 網頁中需要載入的圖檔、JS、CSS 等檔案放在原本網站中,因為網站已經暫時無法服務。比較正確的作法是將這些靜態檔案放到 CDN 或是其他網頁儲存空間,如果你要把這些資源全部弄成 data URIs 格式也是可以的。

另外,如果你的站台主要以 Web API 為主的話,要注意除了回應狀態碼會統一變成 HTTP 503 之外,還要注意所有回應的 Content-Type 都會暫時變成 text/html 喔!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK