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 还没回复
看到有人说要引用 “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,详见 - 后来还是放到 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
- [](
下一篇: 回调函数的作用