长沙麓谷建设发展有限公司网站,一台服务器做两个网站,扬中话,wordpress 项目管理插件前言
上一篇老司机实战Windows Server Docker#xff1a;1 初体验之各种填坑介绍了安装docker服务过程中的一些小坑。这一篇#xff0c;我们来填一些稍大一些的坑#xff1a;如何docker化一个现有的iis应用。
问题分析
听说Windows支持原生docker了#xff0c;大家一定都…前言
上一篇老司机实战Windows Server Docker1 初体验之各种填坑介绍了安装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:
env1Dev (from appSettings in web.config)
env2Dev (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 env1LIVE1 -e env2LIVE2 -e HOSTS1.2.3.4:TEST.COM iis-demo:1.0
这里的参数分别表示
指定容器ip172.24.128.2允许80端口被外部访问将容器内的c:/inetpub/logs/LogFiles目录mount到宿主机的c:/temp设置3个系统环境变量env1env2HOSTS
稍等片刻等待容器实例运行然后在宿主机的浏览器中访问可以看到如下的内容
Hello Docker!Configuration:
env1LIVE1 (from appSettings in web.config)
env2Dev (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解析对于希望方便查看的日志我们可以通过volumemount到宿主机的目录同样的我们也可以mount应用自己的数据到宿主机这样容器实例重启时应用的状态也能保持因为可以在docker run时传入参数被应用读取我们可以用同一个docker image在不同的环境开发、测试、生产指定不同的参数比如数据库连接字串网络方面关于如何从外部系统访问容器内部我们会在后续篇章详细讨论这里因为可以将自定义hosts传递进容器所以容器访问外部系统的任何地址都不用担心无法解析
应该说我们已经解决了大多数前面提到但实例运行时需要解决的问题了。然而别忘了这一篇里我们只针对单服务器单容器实例。在实际的部署案例中是绝不允许单点无法扩展的。
后面几篇我会展开讲讲这一篇跳过的一些非常重要的话题例如网络配置、远程管理、负载均衡、实时监控、以及更高级的容器编排和集群实现等等敬请期待
凌晨1点多了困了不过我会很快回来的 相关文章
老司机实战Windows Server Docker1 初体验之各种填坑Docker基础入门及示例LinuxNginxAsp.net Core部署
原文地址https://www.cnblogs.com/teddyma/p/Windows-Server-Docker-2.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注