我們有一些服務是 dotnet framework 的,不能直接跑在 docker linux container 下麵,最近一直在折騰把它部署在 windows container 下,折騰的有點噁心,記錄一下。 ...
windows container 踩坑記
Intro
我們有一些服務是 dotnet framework 的,不能直接跑在 docker linux container 下麵,最近一直在折騰把它部署在 windows container 下,折騰的有點噁心,記錄一下。
Windows Container 介紹
Windows Container 是微軟在 Windows 上的虛擬化實踐,它可以提供操作系統級別的虛擬化。
通過我們說的容器化大多是指 Linux Container,基於 linux 的 container 實踐,除此之外還有 windows container,如果你使用的是 windows 且使用過 Docker for Desktop,你也許會註意到 docker 右鍵的時候會有一個 “Switch to windows container” 的選項。
Windows container 架構:
Windows container 分為兩大部分: windows container on windows(下文簡稱 Windows Container), linux container on windows(下文簡稱 Linux Container), 我們今天將要用到的是 Windows container.
上圖所示的兩種方式對應著 Docker for Desktop 里 Windows Container 和 Linux Container 兩種 docker 容器化運行時,兩種運行時不能同時使用,可以切換,切換過程中數據是不會丟失的,你不可以在 windows container 環境下操作 linux container 的鏡像與容器,更不能在 linux container 環境 下操作 windows container 的鏡像和容器,兩者架構上不一致。
windows container 是相當於 docker 在 linux 下的原生實現,linux container 是通過 Hyper-V 托管了一個小型虛擬機以實現 linux 環境。
你應該知道, 有兩個不同的容器類型 (也稱為運行時)。
Windows Server 容器通過進程和命名空間隔離技術提供應用程式隔離, 這就是這些容器也稱為進程隔離的容器的原因。 Windows Server 容器與容器主機和該主機上運行的所有容器共用內核。 這些進程隔離的容器不提供敵意安全邊界, 不應用於隔離不受信任的代碼。 由於共用內核空間,這些容器要求具有相同的內核版本和配置。
Hyper-v 隔離通過在高度優化的虛擬機中運行每個容器來擴展 Windows Server 容器提供的隔離。 在此配置中, 容器主機不與同一主機上的其他容器共用其內核。 這些容器旨在托管敵對多租戶,並且具有與虛擬機相同的安全保證。 由於這些容器不與主機上的主機或其他容器共用內核, 因此它們可以運行具有不同版本和配置 (受支持版本內) 的內核。 例如, Windows 10 上的所有 Windows 容器都使用 Hyper-v 隔離來利用 Windows Server 內核版本和配置
儘管兩者在技術架構上有差異,但是 docker 的基本操作都是適用的,如果你的磁碟不夠大網速不夠好,不建議直接在自己電腦上嘗試 windows container,windows container 大部分是基於 windows-sever 的鏡像,動則十幾個G,下載鏡像都不一定能下載成功。
GetStarted
部署一個簡單的 dotnet framework 應用到 windows 容器
docker pull microsoft/iis
拉一個 iis 的 docker 鏡像
docker run --rm -p 8080:80 --name=iis microsoft/iis:latest
docker run --it iis powershell
看著上面的命令是不是感覺很熟悉啊,下麵再看一個 Dockerfile
這是一個 asp.net 的應用的 dockerfile,來自微軟的官方示例
FROM mcr.microsoft.com/dotnet/framework/sdk:4.8 AS build
WORKDIR /app
# copy csproj and restore as distinct layers
COPY *.sln .
COPY aspnetapp/*.csproj ./aspnetapp/
COPY aspnetapp/*.config ./aspnetapp/
RUN nuget restore
# copy everything else and build app
COPY aspnetapp/. ./aspnetapp/
WORKDIR /app/aspnetapp
RUN msbuild /p:Configuration=Release
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.8 AS runtime
WORKDIR /inetpub/wwwroot
COPY --from=build /app/aspnetapp/. ./
踩的坑
項目是 AspNetCore 只是項目是 dotnet framework471 的,並且有引用幾個 netstandard2.0 的項目,
在 msbuild 的時候出錯,尚未找到解決方法,提了一個 issue 還沒回覆
https://github.com/microsoft/dotnet-framework-docker/issues/315
看到有人說要引用 “Microsoft.Net.Compilers” 這個包,在項目裡加上了這個包的引用還是有問題,這個問題很神奇,本地dotnet build
/msbuild
都是正常的C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\Roslyn\Microsoft.CSharp.Core.targets(59,5): error MSB6006: "csc.exe" exited with code -2146232576
msbuild 有問題之後便想用
dotnet build
來編譯,最初嘗試安裝 dotnet core 後來發現這個 framework 鏡像里已經安裝 dotnet core sdk,太好了不用再自己裝了,後來用dotnet build
代替了 msbuildhost 應用
- dotnet 不能執行 dotnet framework 生成的 exe,原本想著像在 linux 下麵跑 dotnet core 一樣,直接
dotnet <xxx.dll>
使用 kestrel 來托管,然而並不能直接運行,起初按錯誤提示以為要手動加一個 runtimeconfig.json 來指定框架類型及版本,後來才知道 runtimeconfig.json 只支持 dotnetcore,詳見https://github.com/dotnet/core-setup/issues/7149 - 後來還是放到 iis 下麵,當時使用的是
microsoft/iis
這個鏡像,發現放上去之後不能運行,報 500 錯誤,後來又裝 dotnetcore-windows-hosting ,還是不行最終在 Event-Log 中發現沒有framework471 ... - 後來使用
mcr.microsoft.com/dotnet/framework/aspnet:4.7.1
這個鏡像,然後在安裝 dotnetcore-windows-hosting 的時候又是一波多折。。最後先安裝了 chocolatey , chocolatey 是 windows 上的一個包管理器,像管理nuget包一樣管理你PC上的軟體,然後使用choco install dotnetcore-windowshosting -y
來安裝 dotnetcore-windowshosting 模塊。
Solution
最終使用的 Dockerfile 如下:
FROM mcr.microsoft.com/dotnet/framework/sdk:4.7.1 AS build
WORKDIR /app
# copy csproj and restore as distinct layers
COPY Projects/*.csproj ./Projects/
COPY nuget.config ./
RUN dotnet restore ./Projects/Projects.csproj
# copy everything else and build app
COPY . .
WORKDIR /app/Projects
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/framework/aspnet:4.7.1
WORKDIR /inetpub/wwwroot
# install choco
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
# install dotnetcore-windowshosting
RUN choco install dotnetcore-windowshosting -y
RUN powershell -NoProfile -Command Remove-Item -Recurse C:\inetpub\wwwroot\*
COPY --from=build /app/Projects/out/ ./
Memo
折騰起來真是麻煩,可以直接上 dotnetcore 還是直接上 dotnetcore 吧
Tips
windows container 里 RUN
是相當於在 powershell 中執行命令
Reference
- https://docs.microsoft.com/zh-cn/virtualization/windowscontainers/quick-start/quick-start-windows-10
- https://chocolatey.org/install
- https://github.com/microsoft/dotnet-framework-docker
- https://github.com/microsoft/dotnet-framework-docker/tree/master/samples
- [https://docs.microsoft.com/en-us/virtualization/windowscontainers/](https://docs.microsoft.com/en-us/virtualization/windowscontainers/