[上課筆記] .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