windows container 踩坑記


windows container 踩坑記

Intro

我們有一些服務是 dotnet framework 的,不能直接跑在 docker linux container 下面,最近一直在折騰把它部署在 windows container 下,折騰的有點惡心,記錄一下。

Windows Container 介紹

docker for windows

Windows Container 是微軟在 Windows 上的虛擬化實踐,它可以提供操作系統級別的虛擬化。
通過我們說的容器化大多是指 Linux Container,基於 linux 的 container 實踐,除此之外還有 windows container,如果你使用的是 windows 且使用過 Docker for Desktop,你也許會注意到 docker 右鍵的時候會有一個 “Switch to windows container” 的選項。

Switch to windows container

Windows container 架構:

Windows Container Architecture

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 容器類型

你應該知道, 有兩個不同的容器類型 (也稱為運行時)。

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 的項目,

  1. 在 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

  2. 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM