老司机实战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…

MySQL dayofweek()函数

转载自 MySQL dayofweek()函数 DAYOFWEEK函数返回日期的工作日索引值,即星期日为1,星期一为2,星期六为7。 这些索引值对应于ODBC标准。 下面说明了DAYOFWEEK函数的语法: DAYOFWEEK(date)DAYOFWEEK函数接受1个参数,…

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

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

PHP WEB程序设计信息表,PHP WEB程序设计

学习情境1 PHP运行环境搭建1.1 任务引入1.2 任务分析1.2.1 任务目标1.2.2 设计思路1.3 任务实施任务1 WAMP插件方式手动安装任务2 WAMPServer集成环境安装任务3 WAMP常用环境配置1.4 任务小结1.5 知识拓展1.5.1 PHP简介1.5.2 B/S相关知识1.5.3 PHP开发…

让智能机器人更智能

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

MySQL extract()函数

转载自 MySQL extract()函数 简介MySQL EXTRACT函数 EXTRACT()函数提取日期的一部分。下面说明了EXTRACT()函数的语法。 EXTRACT(unit FROM date)EXTRACT()函数需要两个参数:unit和date。 unit是要从日期中提取的间隔。 以下是unit参数的有效间隔。 DAYDAY_H…

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

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

oracle8修改最大连接数,ORACLE查看并修改最大连接数的具体步骤

第一步,在cmd命令行,输入sqlplus第二步,根据提示输入用户名与密码1. 查看processes和sessions参数SQL> show parameter processesNAME TYPE VALUEdb_writer_processes integer 1gcs_serve…

Excel的基础操作

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

MySQL now()函数

转载自 MySQL now()函数 MySQL NOW()函数简介 MySQL NOW()函数以"YYYY-MM-DD HH:MM:DD"或"YYYYMMDDHHMMSS.uuuuuuu"格式的字符串或数字返回配置的时区中的当前日期和时间。 NOW()函数的返回类型取决于使用它的上下文。 例如,在以下语句中&a…

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

编辑寄语 当我让 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

expect() php,Linux expect 的安装

expect是建立在tcl基础上的一个工具&#xff0c;它还提供了一些Tcl所没有的命令&#xff0c;它可以用来做一些linux下无法做到交互的一些命令操作&#xff0c;在远程管理方面发挥很大的作用。因为expect是基于tcl的&#xff0c;所以需要你的系统中安装有tcl如何检查&#xff1f…

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…

oracle 删除时间段的,oracle SQL如何从日期中删除时间

我有一个名为StartDate的列&#xff0c;其中包含以下格式的日期&#xff1a;03-03-2012 15:22我需要的是将其转换为日期。应该是这样的&#xff1a;DD / MM / YYYY我没有成功尝试过的是&#xff1a;selectp1.PA_VALUE as StartDate,p2.PA_VALUE as EndDatefrom WP_Work pLEFT J…

MySQL str_to_date()函数

转载自 MySQL str_to_date()函数 MySQL STR_TO_DATE函数简介 下面说明了STR_TO_DATE()函数的语法&#xff1a; STR_TO_DATE(str,fmt);STR_TO_DATE()根据fmt格式字符串将str字符串转换为日期值。 STR_TO_DATE()函数可能会根据输入和格式字符串返回DATE&#xff0c;TIME或DAT…