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
代替了 msbuild -
host 應用
- 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/