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

你应该知道, 有两个不同的容器类型 (也称为运行时)。

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

windows container 踩坑记的更多相关文章

  1. djangorestframework+vue-cli+axios,为axios添加token作为headers踩坑记

    情况是这样的,项目用的restful规范,后端用的django+djangorestframework,前端用的vue-cli框架+webpack,前端与后端交互用的axios,然后再用户登录之后,a ...

  2. EOS踩坑记

    [EOS踩坑记] 1.每个account只能更新自己的contract,即使两个account的秘钥相同,也不允许. 如下,使用alice的权限来更新james的contract.会返回 Missin ...

  3. 十年老苹果(A1286)强升Catalina及Win10踩坑记(续)

    背景 自上次发布十年老苹果(A1286)强升Catalina及Win10踩坑记以来,因为后半部分-----系统安装上的细节描述过于简略,一些朋友在安装过程中总是又遇到坑,由此特意详述这一过程,让园友少 ...

  4. WinUI 3 踩坑记:前言

    WinUI 3 (Windows App SDK 于 2021 年 11 月发布了第一个正式版 v1.0.0 [1],最新版本是 v1.1.5 [2].我的基于 WinUI 3 的个人项目 寻空 从年 ...

  5. WinUI 3 踩坑记:从创建项目到发布

    本文是 WinUI 3 踩坑记 的一部分,该系列发布于 GitHub@Scighost/WinUI3Keng,若内容出现冲突以 GitHub 上的为准. 创建项目 现在 WinUI 3 的入门体验比刚 ...

  6. WinUI 3 踩坑记:第一个窗口

    本文是 WinUI 3 踩坑记 的一部分,该系列发布于 GitHub@Scighost/WinUI3Keng,文中的代码也在此仓库中,若内容出现冲突以 GitHub 上的为准. WinUI 3 应用的 ...

  7. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  8. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  9. 【踩坑记】从HybridApp到ReactNative

    前言 随着移动互联网的兴起,Webapp开始大行其道.大概在15年下半年的时候我接触到了HybridApp.因为当时还没毕业嘛,所以并不清楚自己未来的方向,所以就投入了HybridApp的怀抱. Hy ...

随机推荐

  1. 浏览器中实现3D全景浏览

    如果你用过网页版的百度地图,你大概3D全景图浏览是一种怎样的酷炫体验:在一个点可以360度环顾周围的建筑.景色,当然也可以四周移动,就像身临其境. 科普 全景图共分为三种: ①球面全景图 利用一张全景 ...

  2. LINQ查询表达式---------group子句

    LINQ查询表达式---------group子句 LINQ表达式必须以from子句开头,以select或group子句结束.使用guoup子句来返回元素分组后的结果.group 子句返回一个 IGr ...

  3. C# Excel导入Access

    /// <summary> /// 导入 /// </summary> private void btn_In_Click(object sender, EventArgs e ...

  4. 微信小程序把玩(三十二)Image API

    原文:微信小程序把玩(三十二)Image API 选择图片时可设置图片是否是原图,图片来源.这用的也挺常见的,比如个人中心中设置头像,可以与wx.upLoadFile()API使用 主要方法: wx. ...

  5. 解决C++项目使用sqlite中文乱码问题

    我参考的是这篇文章:https://www.2cto.com/database/201411/354891.html 理论是:sqlite使用的是UTF-8,C++中用的字符串是ascii或unico ...

  6. .NET重思(三)-数组列表与数组的区别,栈集合和队列结合的区别

    数组列表和数组十分相似,区别在于数组列表的容量是可以动态变化的,而数组的容量是固定的.数组即Array类,数组列表即ArrayList类,两者十分相似.不过,Array类在System命名空间下,Ar ...

  7. VC 使用msxml6.dll动态链接库中的函数读写XML文件

    VC 使用msxml6.dll动态链接库中的函数读写XML文件 目录 1 引言 2 .dll使用方法 3 常用函数总结 4 实例应用 5 运行效果预览 6 补充说明 7 不足之处 8 更新   引言: ...

  8. zyltimer与ZylIdleTimer

    http://www.zylsoft.com/zyltimer.htmhttp://www.zylsoft.com/products.htm

  9. Visual C++ 异常(Exception)常见问题 (原文标题:A Visual C++ Exception FAQ)

    Visual C++ 异常(Exception)常见问题 版权:Doug Harrison 2001 – 2007 翻译:magictong(童磊) 2011年3月 原文地址:http://membe ...

  10. QT中获取选中的radioButton的两种方法(动态取得控件的objectName之后,对名字进行比较)

    QT中获取选中的radioButton的两种方法   QT中要获取radioButton组中被选中的那个按钮,可以采用两种如下两种办法进行: 方法一:采用对象名称进行获取 代码: 1 QRadioBu ...