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

前言

上一篇老司机实战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跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2017蓝桥杯省赛---java---C---2(兴趣小组)

题目描述 思路分析 直接进行暴力解决 代码实现 package TEST;import java.math.BigInteger;public class Main {public static void main(String[] args) {// TODO Auto-generated method stubint[] A {12894792, 92774113, 59529208, 22962224,2991600, 83340521, 87365045…

人脸识别活体检测之张张嘴和眨眨眼

暑【这段时间有点忙,终于截止今天2018.06.22完成了人脸识别的最后一道程序——活体检测之眨眨眼和张张嘴】关于人脸识别的内容我之前也写过好几篇博文,其中有: {java实现人脸识别源码} {C#winforms实现windows窗体人脸识别} {人脸识别活体检测…

让智能机器人更智能

Microsoft Bot Framework、LUIS、Azure Bot Service 和 Azure Functions 均已推出。最近到处有人在说:智能机器人是新应用。原因之一就是,智能机器人能够让你轻松、高效地完成常见任务。想一想: 只需让某种数字助理为你执行相关操作&#xff…

2017蓝桥杯省赛---java---C---7 Excel地址)

题目描述 Excel单元格的地址表示很有趣,它使用字母来表示列号。 比如, A表示第1列, B表示第2列, Z表示第26列, AA表示第27列, AB表示第28列, BA表示第53列, …当然Excel的最大列号是…

Excel的基础操作

一、Excel的界面组成部分:标题栏、功能选项卡、单元格名称、功能面板、编辑栏、工 作导航按钮、工作表标签 二、一个工作薄默认包含三个工作表,可以自己添加工作表 三、单元格操作:1.编辑内容:(1)单击需要添加内容的单元格–》输…

有效事件: 可取代数十种设计模式

编辑寄语 当我让 MSDN 杂志高级特约编辑 James McCaffrey 审阅本文的初稿时,他为本文作者提出的一些观点和想法所震怒,愤愤然地离开了。大多数时候,这预示着文稿不通过。但 McCaffrey 指出,软件工程中的新概念遭到摒弃再常见不过&…

2018蓝桥杯省赛---java---C---1(哪天返回)

题目描述 代码实现 package TEST;public class Main {public static void main(String[] args) {int i1,num1,sum1;//num每天挣的钱&#xff0c;sum总共挣的钱while (sum<108){sum(num2);i;//表示天数}System.out.println(i);} }答案 11

PS中缩放工具的细微缩放不可以使用的解决方法

我的PS中的细微缩放是灰色的&#xff0c;就像是这样的&#xff1a; 那么怎么办呢&#xff1f; 解决方法如下&#xff1a; 1.点击PS菜单栏中的“编辑”–>首选项–>性能–》然后吧【启动OpenGL绘图】的复选框勾选上–>确定。 2.重新打开图片就可以了。 希望对大家…

MySQL month()函数

转载自 MySQL month()函数 MySQL MONTH函数介绍 MONTH函数返回一个整数&#xff0c;表示指定日期值的月份。 以下说明了MONTH函数的语法&#xff1a; MONTH(date);MONTH函数接受一个DATE或DATETIME值的参数。 它返回1到12之间的整数&#xff0c;范围从1到12。 如果通过零日…

263. 丑数---LeetCode---JAVA

class Solution {public boolean isUgly(int n) {while(n>0){if(n%20){n/2;}else if(n%30){n/3;}else if(n%50){n/5;}else{break;}}return n1;} }

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

经过上两篇实战Windows Server Docker系列文章&#xff0c;大家对安装Windows Docker服务以及如何打包现有IIS应用为docker镜像已经有了基本认识。接下来我们来简单讲讲一些最基本的运维问题。鉴于到目前为止我们只谈到单服务器部署。这里暂时不涉及集群模式下的复杂生产环境运…

ps中扩展画布的时候,不能选择扩展画布部分的颜色解决方法

在PS中&#xff0c;我们有时候会遇到扩展画布的场景&#xff0c;但是扩展完画布之后我们发现不能改变颜色&#xff0c;这可怎么办。 首先来看一下是什么样的问题&#xff1a; 这个背景是不能选择的。 问题分析&#xff1a;这是因为你创建的画布的时候颜色是透明色的&#xff0…

异或运算(^)

针对二进制&#xff0c;相同的为0&#xff0c;不同的为1 注意事项 前提i位置的数不等于j位置的数 public static void swap(int[] arr,int i,int j){arr[i]arr[i]^arr[j];arr[j]arr[i]^arr[j];arr[i]arr[i]^arr[j];}

jQuery遍历div,判断是否为空,为空时执行某个操作

以下运行结果&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><link rel"stylesheet" type"text/css" href"css/css.css"/>&l…

Dapper源码学习和源码修改

之前ORM比较火热&#xff0c;自己也搞了个WangSql&#xff0c;但是感觉比较low&#xff0c;大家都说Dapper性能好&#xff0c;所以现在学习学习Dapper&#xff0c;下面简单从宏观层面讲讲我学习的Dapper。 再了解一个东西前&#xff0c;先得学会使用&#xff0c;我也不再赘述怎…

php批量评价,彻底杜绝 WordPress 批量垃圾评论留言的三步曲

本文将详细介绍如何采取三步曲彻底告别烦人的 WordPress 批量垃圾评论问题&#xff0c;还你一个干净清爽的后台评论区。刚开始使用 WordPress 程序建站的朋友们肯定或多或少都被其批量垃圾评论困扰过。然后大家就开始寻思解决的办法&#xff0c;找到的网上说法大都是 Akismet A…

MySQL sysdate()函数

转载自 MySQL sysdate()函数 MySQL SYSDATE函数介绍 下面说明了SYSDATE()函数的语法&#xff1a; SYSDATE(fsp);如果函数用于字符串上下文或YYYYMMDDHHMMSS格式&#xff0c;则SYSDATE()函数将返回当前日期时间&#xff0c;格式为“YYYY-MM-DD HH:MM:SS”的值&#xff0c;以…

2018蓝桥杯省赛---java---C---2(猴子分香蕉)

题目描述 思路分析 直接采用暴力破解&#xff0c;先限定范围&#xff0c;然后依次筛选出满足条件的情况。 代码实现 package TEST;public class Main {public static void main(String[] args) {for (int i 5; i < 10000; i) {int temp i;if (temp % 5 1) {temp temp…

纯前端JS实现人脸识别眨眨眼张张嘴案例

在不久之前我发布了一个案例&#xff0c;是java通过百度云人脸识别接口实现活体检测&#xff08;张张嘴和眨眨眼&#xff09;的案例&#xff0c;大家可以去看看&#xff1a;人脸识别活体检测之眨眨眼和张张嘴&#xff0c;今天我就抽空更新一下纯JS的活体检测吧。 首先给大家看一…

年度大片:StackOverflow 2017开发者调查报告

Stack Overflow 发布了 2017 开发者调查报告&#xff0c;此次有超过 64,000 名开发人员参与调查&#xff0c;分别对其技能、工具、学习趋势等数据进行了统计&#xff0c;现将其中一些有趣的数据和趋势撷取出来分享给大家。 一、开发角色 开发类型 大约有四分之三的受访者是 we…