Docker4Dev #6 使用 Windows Container 运行.net应用

关于d4d系列:之前这个系列叫做docker4dotnet,因为当时主要是为了能够探索在docker上运行.net应用;现在我觉得应该叫做docker4developer,因为我希望能够帮助更多的开发人员使用docker技术。今天这篇就算是新的Docker4Dev系列的开始,后续我会陆续发布更多的帮助开发人员使用容器的文章。

随着 Windows Server 2016 的正式发布,Windows Container也可以被部署到生产环境了。Linux Container存在的时间很久了,但是直到2013年Docker的出现我们才有了一种很简单的方式来使用Container技术,而在Windows平台上,类似的Container技术其实也存在很长时间了,但是由于Windows本身的一些特点,我们一直很难(就算经过复杂的配置)使用类似Linux Container的完整应用级别的隔离。这其中的原因我个人觉得主要是因为Windows的封闭性,造成社区无法按照自己的要求对其进行改进。2013年Docker发布后,对整个IT市场造成的冲击巨大,微软同样也感受到了威胁,对于Container技术的追赶也随即开始,让人感到欣慰的是,微软这次没有再次采用闭门造车的方式,而是采用了更加开放的方法与社区合作,接受社区中已有的工具和方法;Windows Container对于Docker工具链的良好支持就说了这一点。

因此,如果你熟悉Docker,那么这篇文章的内容对你没有什么新奇之处;但是如果你像我一样是个在Windows平台上工作多年的开发人员,就会发觉其中的好处。

你需要怎样的环境?

首先,搭建一个可以运行 Windows Container 的环境有3个选择:Windows Server 2016, Windows 10 和 Nano Server。另外,你需要了解 Windows Container 有2种不同的运行模式:Windows Server Container 和 Hyper-V 模式。这其中的区别请见下图:

windows-container-2-modes

其实在我们运行的时候,你是感觉不到其中的区别的,你仍然使用熟悉的 docker run 命令来启动容器,不过操作系统会根据上面表格所列自动的选择当前平台上的默认Container类型运行你的容器。

如果你希望尝试 Windows Container, 最简单的方式就是安装 Windows 10 (专业版或者企业版),然后安装 Docker for Windows 的工具。具体方法可以参考:

https://docs.docker.com/docker-for-windows/

这里我准备了一个简单的PowerShell脚本,直接运心就可以完成启用Windows 10上的Container和Hyper-V功能,由于Windows 10只能运行Hyper-V Container,所以一定需要打开这个功能才可以。

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
Enable-WindowsOptionalFeature -Online -FeatureName containers -All
Restart-Computer -Force

用Docker支持传统 .net 开发

之所以说“传统”,这主要是为了和 .net core做区分,因为.net core本身是跨平台的,所以完全可以使用 Linux Container 来运行(具体请见之前的d4d系列文章),也就不需要 Windows Container 的支持,当然你也可以使用 Windows Container 来运行 .net core,这完全没有问题。但是我觉得大多数 .net 开发人员还是更加关心自己的 .net 2.0/3.5/4.5 应用如何使用 Container。

在配置好以上所需要的开发环境之后,你就可以用 Visual Studio 进行传统.net应用的开发,并用docker完成Windows Container的镜像打包和运行了。只是有一点,你需要将你的Docker for Windows 工具切换到 Windows Container的支持上才行。

switch-windows-container

一旦完成了切换,你用 docker 所做的所有操作就都转向 Windows Container 了。(注:这其实只是现在的一个折中做法,未来的 docker 工具一定是可以同时操作 Windows 和 Linux 两种 Container 类型的)

首先我们用 Visual Studio 2017 来创建一个 asp.net 4.5的应用程序,然后F5运行一下,确保程序可以正常启动。

create-aspnet45

现在,我们来添加一个Dockerfile,为了区分我把它命名为 Dockerfile.windows

add-docker-windows

以下是这个Dockerfile.windows的内容

FROM harbor-bj.devopshub.cn/microsoft/iis
SHELL ["powershell"]

RUN Install-WindowsFeature Net-Framework-45-ASPNET ; \
  Install-WindowsFeature Web-Asp-Net45

ARG source=.
WORKDIR 'c:\app'

RUN Remove-Website -Name 'Default Web Site'
RUN New-Website -Name 'aspnet45docker' -Port 80 \
 -PhysicalPath 'c:\app' -ApplicationPool '.NET v4.5'

EXPOSE 80
COPY $source .

注意几点:

1. 为了能够更快的下载基础镜像,我这里使用了LEANSOFT在北京的harbor站点;这里我已经预先同步了Docker Hub上的基础镜像。
2. 建议大家先预先下载这个基础镜像,因为 Windows 的基础镜像都很大 (WindowsServerCore 有4个G,NanoServer也有400M)
3. 这个Dockerfile中使用了 PowerShell 作为脚本引擎,所以后续你看到的命令都是 PowerShell 命令,比如: Install-WindowsFeature, New-Website 等等。

说实话,这个Dockerfile写得很顺手,毕竟之前对PowerShell的熟悉程度还是超过了shell script,这可能是 Windows 开发人员的好消息。

现在你就可以用熟悉的方式“发布站点”到本地文件夹,然后在里面进行 docker build 了,为了保证这个Dockerfile.windows可以被正常的复制到发布站点中,我还添加了一个Post-Build 脚本,确保每次发布都自动复制这个Dockerfile.windows 文件。

post-build

在发布完成的目标目录内运行以下命令就可以打包了

docker build -f Dockerfile.windows -t aspnet45web01:win-v1 .

docker-build-windows

好了,现在启动Container

docker run -itd -p 81:80 aspnet45web01:win-v1

docker-run

进行到这里,用过 Docker for Windows 的同学一定会打开浏览器 http://localhost:81 来访问站点,但是你啥也看不到;这是因为 Docker for Windows 对 Windows Container 的支持还不够完整,没有进行 localhost 的自动映射,所以你需要使用 docker inspect 来获取容器的 ip 地址,然后通过 ip地址直接访问。

docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" <container id>

打开以上命令获取的ip地址,注意不要用 81 端口,而使用容器本身的80端口,因为我们是直接对容器进行访问。现在你就可以看到一个传统的.net 4.5应用运行在 Windows Container中了,如果你注意看了我的 Dockerfile,你就知道这个站点实际是跑在 IIS 上面的。

app-running

一点感受

Windows Container虽然已经可以投入生产了,但是就和 Docker 刚刚出现时一样存在一些问题,最大的问题是镜像文件太大。上面说了,WindowServerCore镜像4个G,这确实是有点夸张。我觉得微软的目的是为了能够用同样的镜像同时支持Windows Server Container和Hyper-V Container,毕竟Hyper-V Container是作为一个VM存在的,用一个完整的操作系统镜像就可以同时在2中模式上运行,这样当然是有好处的,因为大家不用考虑不同的运行模式而改用不同的基础镜像。但是我觉得从技术上,如果采用 Windows Server Container,微软应该是可以提供非常小的基础镜像,类似 docker 提供的空镜像,这样对第一次部署容器会有很大的性能提升。

但是话说回来,当你第一完成一个容器部署后,因为基础镜像已经存在,每次更新的数据就只有很小的部分(只是应用程序本身),这样后续的部署速度还是很快的。

另外,对于Hyper-V Container的存在的目的,我觉得除了可以提供更好的容器隔离能力(因为是VM,所以根本就是2台机器,不存在共享内核的问题),另外一个重要的目的就是在Windows平台上支持Linux Container的运行。希望微软的动作可以更快一点,毕竟你有全球最好的开发人员,没有什么是技术上做不到的。


推荐一个培训

【基于Docker的DevOps实战培训】是由徐磊老师主讲的三天封闭式课程,地点北京,时间2017年03月24-26日。课程结合了徐磊老师多年来在DevOps上的实践经验和Docker技术,具有很强的实战意义。详细内容及报名方式点击以下链接:

http://devopshub.cn/2017/01/16/docker-devops-training/

相关文章


请关注微信公众号 【devopshub】,获取更多关于DevOps研发运维一体化的信息

qrcode_for_gh_b7c158df1fd1_430