[隨手筆記][ASP.NET MVC5 網站容器化] .NET與Docker Container微服務實務應用

[上課筆記] .NET與Docker Container微服務實務應用

Docker desktop 切換至Windows Container方法

(因為 .NET Framework 程式只能跑在 Windows 容器上(不是 Linux 容器),所以 Docker Desktop 必須切換到 Windows 容器模式。)

開發人員本機電腦Windows功能勾選啟用以下兩項:
   - Containers(容器)                                                                                                                                                      
   - Hyper-V                                                                                                                                                   
                                                                                                                                                                             
須重新開機                                                                                                                                                              
                                                                                                                                                                             
Docker Desktop 設定的 「Use the WSL 2 based engine」 的選項勾消

DockerDesktop的安裝設定檔 C:\ProgramData\DockerDesktop\install-settings.json 裡面寫著:

 {
   "noWindowsContainers": true,    ← 這裡明確禁止了 Windows 容器!
   "wslEngineEnabled": false
 }

 需要把 "noWindowsContainers" 改成 false。這個檔案需要系統管理員權限才能修改。

用系統管理員身份開啟記事本或任何文字編輯器,修改這個檔案:

 路徑:C:\ProgramData\DockerDesktop\install-settings.json

 改成:
 {
   "noWindowsContainers": false,
   "wslEngineEnabled": false
 }

 改完存檔後,重新啟動 Docker Desktop(右鍵鯨魚圖示 → Restart)

C:\Program Files\Docker\Docker 目錄下執行cmd:DockerCli.exe -SwitchWindowsEngine

如此一來 Windows工作列右下角右鍵鯨魚圖示才會出現「Switch to Windows containers...」選項

cmd驗證docker desktop已切換至windows container:docker version

驗證結果:docker version 顯示 Server OS/Arch: windows/amd64,Context: desktop-windows。

.dockerignore 範例(略過哪些檔案不要打包進 image 映像檔)

.dockerignore放置在.Net 方案目錄下

.vs/
WebNet/obj/
WebNet/Properties/
packages/
*.user
*.suo
*.cs
*.vb
*.csproj
packages.config
Dockerfile
docker-compose.yml
.dockerignore
.git/
.gitignore
Dockerfile範例(描述哪些檔案要被打包進 image 映像檔),網站名稱為Webnet

在.Net 方案目錄下創建 docker/Dockerfile.web

# 使用官方 ASP.NET 4.8.1 映像檔(已內建 IIS + .NET Framework 4.8.1,基於 Windows Server 2022)
# 版本相容規則:容器的 Windows 版本不能高於本機電腦的 Windows 版本。
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8.1-windowsservercore-ltsc2022

# 設定工作目錄為 IIS 預設網站位置
WORKDIR C:/inetpub/wwwroot

# 清除 IIS 預設歡迎頁面
RUN powershell -Command "Remove-Item -Recurse -Force C:\inetpub\wwwroot\*"

# 複製應用程式檔案到容器
COPY WebNet/bin/ ./bin/
COPY WebNet/Views/ ./Views/
COPY WebNet/assets/ ./assets/
COPY WebNet/App_Data/ ./App_Data/
COPY WebNet/Global.asax ./Global.asax
COPY WebNet/Web.config ./Web.config

# 建立自簽憑證並綁定到 IIS HTTPS(開發測試用)
RUN powershell -Command " \
    $cert = New-SelfSignedCertificate -DnsName 'localhost' -CertStoreLocation 'Cert:\LocalMachine\My'; \
    New-WebBinding -Name 'Default Web Site' -Protocol https -Port 443; \
    $binding = Get-WebBinding -Name 'Default Web Site' -Protocol https; \
    $binding.AddSslCertificate($cert.Thumbprint, 'My')"

# 複製啟動腳本到容器(檔案已移至 docker/ 資料夾,build context 為專案根目錄)
COPY docker/WebContainer-StartScript.ps1 C:/WebContainer-StartScript.ps1

# 宣告容器只使用 port 443(HTTPS)
EXPOSE 443

# 啟動時執行啟動腳本(判斷使用自簽或正式憑證,然後啟動 IIS)
ENTRYPOINT ["powershell", "-File", "C:\\WebContainer-StartScript.ps1"]

.Net方案目錄 > docker 目錄 > 創建 PowerShell 腳本檔案 WebContainer-StartScript.ps1

# Web容器啟動腳本,每次容器啟動都會執行以下PowerShell 
# 如果有掛載正式憑證(環境變數 CERT_PATH),就匯入並綁定到 IIS HTTPS
# 如果沒有,就使用 Dockerfile 裡預設的自簽憑證

if ($env:CERT_PATH -and (Test-Path $env:CERT_PATH)) {
    Write-Host "Importing SSL certificate from $env:CERT_PATH ..."

    # 匯入 PFX 憑證
    $password = ConvertTo-SecureString -String $env:CERT_PASSWORD -AsPlainText -Force
    $cert = Import-PfxCertificate -FilePath $env:CERT_PATH -CertStoreLocation 'Cert:\LocalMachine\My' -Password $password

    # 移除舊的 HTTPS 繫結,重新綁定正式憑證
    Remove-WebBinding -Name 'Default Web Site' -Protocol https -ErrorAction SilentlyContinue
    New-WebBinding -Name 'Default Web Site' -Protocol https -Port 443
    $binding = Get-WebBinding -Name 'Default Web Site' -Protocol https
    $binding.AddSslCertificate($cert.Thumbprint, 'My')

    Write-Host "SSL certificate bound successfully."
} else {
    Write-Host "No external certificate provided. Using default self-signed certificate."
}

# 啟動 IIS ServiceMonitor(保持容器運行)
& C:\ServiceMonitor.exe w3svc
.Net 方案目錄下的 docker-compose.yml 範例 (描述如何啟動容器)
# 宣告命名 Volume(由 Docker 管理儲存位置,不需指定本機路徑)
# 用途:讓容器內的資料可以持久保存,即使容器被刪除重建,Volume 中的資料依然存在
# 查看:docker volume ls(列出所有 Volume)
# 刪除:docker-compose down -v(加 -v 才會刪除 Volume,不加則保留)
volumes:
  sqldata: # 存放 SQL Server 的資料檔(.mdf/.ldf),供下方 db 服務使用

# 定義要執行的容器服務
services:
  # ===== 資料庫容器 =====
  db: # 服務名稱,也是容器在 Docker 網路中的 DNS 名稱(其他容器可用 "db" 來連線此容器)
    image: webnet-db:v20260325          # 建置出來的映像檔名稱
    container_name: webnet-db-v20260325 # 在 Docker Desktop 裡看到的名字
    build:
      context: .                        # 建置的根目錄(專案根目錄)
      dockerfile: docker/Dockerfile.db  # 使用 docker 資料夾裡的 Dockerfile.db
    # port 對應(本機電腦主機:容器)
    ports:
      - "1433:1433" # 本機電腦的 1433 port 對應 容器內的 1433 port(可用 SSMS 從本機連線至容器內的 SQL Server)
    environment:
      - SA_PASSWORD=YourStrong!Passw0rd # SA 帳號密碼(啟動腳本會讀取此環境變數)
    volumes:
      # 掛載本機的 Backup 資料夾到容器內(Windows 容器不支援掛載單一檔案,只能掛載整個資料夾)
      # :ro 表示容器只能讀取,不能修改本機的檔案
      - "C:/Program Files/Microsoft SQL Server/MSSQL16.SQLEXPRESS/MSSQL/Backup:C:/backup:ro"
      # 使用上方宣告的 sqldata Volume,掛載到容器內的 C:/SQLData
      - sqldata:C:/SQLData
    restart: unless-stopped # 自動重啟,但手動停止後不會再自動重啟

  # ===== 網站容器 =====
  web: # 服務名稱,也是容器在 Docker 網路中的 DNS 名稱(其他容器可用 "web" 來連線此容器)
    image: webnet:v20260325             # 建置出來的映像檔名稱,name:version
    # 容器的名稱(在 Docker Desktop 裡看到的名字)
    container_name: webnet-v20260325    # 容器名稱不能用冒號,改用減號
    # 建置映像檔的設定
    build:
      context: .                         # 建置的根目錄(專案根目錄)
      dockerfile: docker/Dockerfile.web  # 使用 docker 資料夾裡的 Dockerfile.web
    # port 對應(本機電腦主機:容器)
    ports:
      - "8443:443" # 本機電腦的 8443 port 對應 容器內的 443 port
    depends_on:
      - db         # 一鍵啟動時,自動先啟動 db 容器,再啟動 web 容器
    restart: unless-stopped # 自動重啟,但手動停止後不會再自動重啟

 以下cmd指令都不需要額外參數,直接複製貼上執行就好。但要注意必須在.Net 方案目錄下執行(也就是 docker-compose.yml 所在的資料夾)。

建置映像檔:docker compose build

這會讀取 docker-compose.yml 和 Dockerfile,下載基底映像檔並複製本機電腦的應用程式檔案,打包到Docker image。首次約 5-15 分鐘,再次 docker compose build 速度就會很快。

建立容器(不啟動):docker compose create

根據映像檔建立容器,但不會啟動它。

啟動容器:docker compose start

啟動剛才建立的容器。

本機電腦的瀏覽器開啟網址瀏覽容器內的網站:https://localhost:8443

 

客戶主機Windows Server 2022 的部署方式
在客戶主機上執行PowerShell 安裝 Docker(如果尚未安裝)
    Install-WindowsFeature -Name Containers
    Restart-Computer
    Install-Module DockerMsftProvider -Force
    Install-Package Docker -ProviderName DockerMsftProvider -Force
    Restart-Computer

以下實戰我還沒遇過,但這邊先記著當作未來的待辦事項

本機開發用自簽的SSL憑證,客戶主機用正式 SSL 憑證。
同一個映像檔要支援兩種情境,透過啟動容器時的參數不同(判斷是否掛載憑證)來決定。

 本機開發

 Web.config 打包在映像檔裡面(透過 Dockerfile 的 COPY WebNet/Web.config ./Web.config),不需要額外處理。

 客戶主機

 啟動容器時用 -v 掛載客戶專用的 Web.config,覆蓋映像檔裡的那份:

 docker run -d -p 443:443 --name webnet --restart=always ^
   -v C:\certs:C:\certs ^
   -v C:\config\Web.config:C:\inetpub\wwwroot\Web.config ^
   -e CERT_PATH=C:\certs\webnet.pfx ^ 
    -e CERT_PASSWORD=憑證密碼 ^
   webnet-web

客戶主機無法連上網,本機程式的部份網頁檔、檢視View(*.cshtml),透過Volume 將部份檔案部署更新至客戶主機

https://claude.ai/share/2ac09eb0-5a26-47a5-a6d3-bca9d86e83a8