前言

上一篇老司机实战Windows Server Docker:1 初体验之各种填坑介绍了安装docker服务过程中的一些小坑。这一篇,我们来填一些稍大一些的坑:如何docker化一个现有的iis应用。

问题分析

听说Windows支持原生docker了,大家一定都很兴奋。然而,大家想过没有,Windows Server Docker最适合什么场景呢?部署.NET Core应用?为什么不选择Linux下的docker?正常的决策者脑袋被门挤了才会花钱额外买Windows Server的license,用来部署.NET Core吧?所以,在本人看来,Windows Server Docker最大的价值,还是在于部署传统基于WindowsServerCore的应用。这样的应用一般有两大类,一类是基于iis的网站应用;另一类是Windows Service。本文主要关注基于iis的应用的docker部署。

那么,部署一个iis应用到docker,是不是只要起一个iis的docker容器实例,远程连接,并且,copy文件进去,能通过容器内的iis访问就行了?如果,有人问这样的问题,那么,说明他还完全没有容器的思维。上面说的这个,其实就成了将容器当虚拟机用了,这将极大地限制了docker原有的灵活扩展能力。因此,可以说是使用Windows docker最糟糕的姿势之一了。

要正确部署一个iis应用到Windows Server Docker,并不是表面那么简单。限于篇幅,并且为了更专注,本文先不涉及容器编排、负载均衡、images的构建和管理等问题(这些要考虑的问题还有很多,以后我们单独聊),这里只关注如何将一个基于iis的应用正确运行于单个Windows Server Docker实例中。即便如此,一般至少也要解决下面这些问题:

  • Dockerfile:如何通过Dockerfile部署应用文件和设置操作系统和IIS配置,如何为不同的运行环境(开发,测试,生产)配置不同参数;

  • 查看系统日志:典型的系统日志包含IIS Logs、Windows Event Log和应用的异常日志;

  • 重启容器实例:当容器实例重启时,如何保证被部署的应用能保持之前的工作状态,能继续服务;

  • 网络路由:包括容器内部如何访问外部系统、docker宿主机如何访问容器内部、外部系统如何访问容器内部;

应用示例

为便于理解和演示,我在github上写了一个简单的示例应用:windows-docker-iis-demo

这个应用只包含一个页面,在我本机运行时,显示类似下面的内容:

Hello Docker!Configuration:
env1=Dev (from appSettings in web.config)
env2=Dev (from OS environment variable)Content of C:\Windows\System32\drivers\etc\hosts:# Localhost (DO NOT REMOVE)127.0.0.1

   localhost
::1 localhost ip6-localhost ip6-loopback

其中env1为web.config中的appSettings值,env2读取的系统环境变量,页面最下面打印出当前Windows系统的的hosts。

定义Dockerfile如下:

FROM microsoft/iis# install ASP.NET 4.5RUN dism /online /enable-feature /all /featurename:IIS-ASPNET45 /NoRestart# enable windows eventlog
RUN powershell.exe -command Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\WMI\Autologger\EventLog-Application Start 1# set IIS log fieldsRUN /windows/system32/inetsrv/appcmd.exe set config /section:system.applicationHost/sites /siteDefaults.logFile.logExtFileFlags:"Date, Time, ClientIP, UserName, SiteName, ServerIP, Method, UriStem, UriQuery, HttpStatus, Win32Status, TimeTaken, ServerPort, UserAgent, Referer, HttpSubStatus"  /commit:apphost# deploy webapp
COPY publish /inetpub/wwwroot/iis-demo
RUN /windows/system32/inetsrv/appcmd.exe add app /site.name:"Default Web Site" /path:"/iis-demo" /physicalPath:"c:\inetpub\wwwroot\iis-demo"# set entrypoint scriptADD SetHostsAndStartMonitoring.cmd \SetHostsAndStartMonitoring.cmd
ENTRYPOINT ["C:\\SetHostsAndStartMonitoring.cmd"]# declare volumes
VOLUME ["c:/inetpub/logs/LogFiles"]

我们分别来理解一下Dockerfile每一段的含义:

  • 首先是安装ASP.NET 4.5;

  • 接着,开启Windows EventLog;

  • 第三步,我们修改了默认的IIS Logs字段列表;

  • 第四步,将当前目录下的publish目录的内容复制到容器的/inetpub/wwwroot/iis-demo目录,并且在iis中添加对应的iis-demo应用;

  • 第五步,设置一个自定义的启动脚本;

  • 最后,声明了一个VOLUME,以便将IIS Logs保存到容器外的宿主机上;

启动脚本SetHostsAndStartMonitoring.cmd的内容如下:

powershell -executionpolicy bypass -Command "If ($env:HOSTS) { $hosts = $env:HOSTS.Replace(':', ' ').Replace(',', '\r\n'); $hosts | Set-Content 'C:\Windows\System32\drivers\etc\hosts'; 'Applied hosts: ' + $hosts" }powershell -executionpolicy bypass -Command "if ($env:env1) { (Get-Content 'c:\inetpub\wwwroot\iis-demo\web.config').replace('Dev', $env:env1) | Set-Content 'c:\inetpub\wwwroot\iis-demo\web.config' }; c:\ServiceMonitor.exe w3svc

其中,第一部分读取HOSTS这个系统环境变量,覆盖当前系统的hosts文件;第二步读取env1环境变量,覆盖web.config中的对应配置;最后调用继承自microsoft/iis image的ServiceMonitor.exe命令,监控iis主进程,直到其退出。

下面,我们来试着build这个docker。因为到目前为止(本系列的第一篇+第二篇),我们还只能从这台Windows Server机器上执行docker命令,以后的文章会讲到如何从远程server build以及如何集成到CI工具进行build,这里先绕过。我们在VS2015中编译这个webapp,并且发布到publish目录。然后,复制整个windows-docker-iis-demo目录到这台docker宿主机的C盘根目录,以便进行docker build。这个当然不是build docker image的正常姿势,只是因为我们还没提到其他方式,我们先粗糙一点,把它build出来,以便可以运行。

在我们的Windows Server 2016机器上,打开一个administrator模式的powershell窗口,cd到c:\windows-docker-iis-demo目录,然后执行docker build命令制作image:

docker build -t iis-demo:1.0 .

编译成功后,执行docker images,可以看到多了一个iis-demo:1.0的docker image。接着,让我们在宿主机的C盘创建一个temp目录(为下面的volume使用,mount到容器内部的iis日志),然后执行下面的命令运行一个iis-demo的docker instance:

docker run --ip 172.24.128.2 -p 80 -v "c:/temp:c:/inetpub/logs/LogFiles" -e "env1=LIVE1" -e "env2=LIVE2" -e "HOSTS=1.2.3.4:TEST.COM" iis-demo:1.0

这里的参数分别表示:

  • 指定容器ip=172.24.128.2

  • 允许80端口被外部访问

  • 将容器内的c:/inetpub/logs/LogFiles目录mount到宿主机的c:/temp

  • 设置3个系统环境变量env1,env2,HOSTS

稍等片刻,等待容器实例运行,然后在宿主机的浏览器中访问,可以看到如下的内容:

Hello Docker!Configuration:
env1=LIVE1 (from appSettings in web.config)
env2=Dev (from OS environment variable)Content of C:\Windows\System32\drivers\etc\hosts:1.2.3.4 TEST.COM

对比前面在开发环境运行的结果,我们可以看到有一些有意思又诡异的区别:

  • 首先,通过前面的启动脚本SetHostsAndStartMonitoring.cmd读取的环境变量env1和HOSTS都生效了;

  • 然而,在程序中运行时读取的环境变量env2没有生效(这个好坑人!!意味着,无法直接在webapp中读取docker run传递进来的环境变量。一开始怀疑是因为webapp的进程启动时间早于docker run指定的环境变量生效的时间,但是即使进到容器里recycle 对应的apppool,还是不生效,具体原因有待后续验证了);

另外,在宿主机的c:\temp目录,我们可以看到从容器实例写道外部的iis log。

好了,看看至此我们已经解决了哪些最开始提到的问题了:

  • 首先,我们实现了在docker run时,指定不同的参数,传递进容器,比如覆盖web.config中的设置,又比如,设置了额外的hosts文件中的dns解析;

  • 对于希望方便查看的日志,我们可以通过volume,mount到宿主机的目录;

  • 同样的,我们也可以mount应用自己的数据到宿主机,这样容器实例重启时,应用的状态也能保持;

  • 因为可以在docker run时传入参数被应用读取,我们可以用同一个docker image,在不同的环境(开发、测试、生产)指定不同的参数,比如,数据库连接字串;

  • 网络方面,关于如何从外部系统访问容器内部,我们会在后续篇章详细讨论,这里,因为可以将自定义hosts传递进容器,所以容器访问外部系统的任何地址,都不用担心无法解析;

应该说,我们已经解决了大多数前面提到但实例运行时需要解决的问题了。然而,别忘了,这一篇里,我们只针对单服务器,单容器实例。在实际的部署案例中,是绝不允许单点,无法扩展的。

后面几篇,我会展开讲讲这一篇跳过的一些非常重要的话题,例如网络配置、远程管理、负载均衡、实时监控、以及更高级的容器编排和集群实现等等,敬请期待!

凌晨1点多了,困了,不过我会很快回来的!

相关文章:

  • 老司机实战Windows Server Docker:1 初体验之各种填坑

  • Docker基础入门及示例

  • Linux+Nginx+Asp.net Core部署

原文地址:https://www.cnblogs.com/teddyma/p/Windows-Server-Docker-2.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

老司机实战Windows Server Docker:2 docker化现有iis应用的正确姿势相关推荐

  1. 老司机实战Windows Server Docker:5 Windows Server Dockerfile葵花宝典

    前面两篇(简单运维1.简单运维2)介绍了一些Windows Server Docker相关的基本运维知识.今天这一篇,Windows Server Dockerfile葵花宝典,涵盖了许多典型场景的W ...

  2. 老司机实战Windows Server Docker:4 单节点Windows Docker服务器简单运维(下)

    上篇中,我们主要介绍了使用docker-compose对Windows Docker单服务器进行远程管理,编译和部署镜像,并且设置容器的自动启动.但是,还有一些重要的问题没有解决,这些问题不解决,就完 ...

  3. 老司机实战Windows Server Docker:3 单节点Windows Docker服务器简单运维(上)

    经过上两篇实战Windows Server Docker系列文章,大家对安装Windows Docker服务以及如何打包现有IIS应用为docker镜像已经有了基本认识.接下来我们来简单讲讲一些最基本 ...

  4. 老司机实战Windows Server Docker:1 初体验之各种填坑

    前言 Windows Server 2016正式版发布已经有近半年时间了,除了看到携程的同学分享了一些Windows Server Docker的实践经验,网上比较深入的资料,不管是中文或英文的,都还 ...

  5. Windows Server 2016 安装 Docker

    必备条件 若要在 Windows Server 上运行容器,需要一台运行 Windows Server(半年频道).Windows Server 2019 或 Windows Server 2016 ...

  6. 老毛桃还原windows server 2012 R2服务器

    背景 重启了一下windows server 2012 R2,导致无法进入系统. 一直处于重新启动状态,总是出现"你的电脑遇到问题,需要重新启动"的提示. 也无法进入完全模式.无法 ...

  7. Windows server 2012 R2系统怎么安装IIS管理器?

    Windows server 2012 R2系统怎么安装IIS管理器?今天飞飞和你分享.服务器大本营,技术文章内容集合站发车啦! 首先我们用电脑自带的远程连接桌面工具进入服务器,在任务栏左下角有个服务 ...

  8. Windows Server 2012 R2桌面化详细设置图解

    Windows Server 2012 R2桌面化详细设置图解 一.任务栏左下角启动服务器管理器,然后进行设置. 1.登录不显示服务器管理器 2.本地服务器,看到右边的IE增强的安全配置,如图所示,关 ...

  9. 阿里云服务器Windows Server 2019 安装Web服务器(IIS)教程

    最近买了一个阿里云Windows server 2019服务器来搭建云服务器,过程给大家分享一下互相学习,让小白快速上手! 一.本地电脑远程登录阿里云Windows server 2019服务器 参见 ...

最新文章

  1. python使用imbalanced-learn的ADASYN方法进行上采样处理数据不平衡问题
  2. MIT开发AI新工具,替设计师“省材料钱”:支持实时预览、兼容CAD软件丨开源...
  3. 每周一书《Oracle 12 c PL(SQL)程序设计终极指南》
  4. React开发(264):react使用国际化
  5. iOS开发中 常用枚举和常用的一些运算符(易错总结)
  6. UNIX环境高级编程——pthread_create的问题
  7. Win7下安装配置OpenCV2.3+Visual Studio 2008
  8. 联合、枚举和类型别名 - C++快速入门13
  9. python多重继承super父类参数_多重继承如何处理super()和不同的参数?
  10. 以太坊上DeFi协议总锁仓量环比上升4.37%
  11. php double 类型 浮点数相减
  12. 友盟消息推送UPush
  13. 开源GIS(五)——openlayers中interaction的select、draw与modify
  14. 飞秋(FeiQ)与飞鸽传书(IP Messenger)区别
  15. 机器学习算法工程师面试问题汇总(持续更新)
  16. String.indexOf 用法
  17. 使用Texmacs帮助您写格式规范统一的BLOG
  18. 3d建模做一单多少钱?做外包赚钱吗?
  19. linux系统python截图不显示中文_Linux系统通过python访问SQL SERVER,无法显示数据库内中文的问题...
  20. 高中数学必修五:数列压轴小题秒杀技巧

热门文章

  1. Linux实战考试题:批量创建用户和密码-看看你会么?
  2. NO.106 需求的状态、研发阶段及注意事项。
  3. Vertex Texture Fetch(VTF) Fragment Texture Fetch ( FTF )
  4. cake-build -.Net Core 跨平台构建自动化系统。
  5. Xamarin效果第四篇之CollectionView子项右侧布局
  6. C# WPF Caliburn.Micro框架下利用Mef加载其它项目界面
  7. 使用FuncT, TResult 委托实现API日志的记录
  8. 这个世界,正在悄悄惩罚那些不注意身体的人
  9. Blazor 火了,不禁让人想起已死的Silverlight !
  10. 【招聘(深圳)】轻岁 诚聘.NET Core开发