前面两篇(简单运维1、简单运维2)介绍了一些Windows Server Docker相关的基本运维知识。今天这一篇,Windows Server Dockerfile葵花宝典,涵盖了许多典型场景的Windows Server下的Dockerfile实例,并且每一个都包含可直接运行的代码实例,完全开源,并且新示例持续添加中。也希望大家能一起贡献经验。

示例源码

Github Repo: windows-dockerfile-lab

所有示例均经过Windows Server 2016环境实际测试。如果你需要了解如何配置一个Windows Server Docker的测试环境,可以参考本系列的第一篇。

咱们从一些基础的Dockerfile命令说起:

ENTRYPOINT和CMD

源码:entrypoint_and_cmd

FROM microsoft/windowsservercore#usually, ENTRYPOINT should be fixed and CMD to be overridden when necessary
#always use the exec form instead of shell mode for ENTRYPOINT and CMD commands and paramsENTRYPOINT ["ping", "-n", "3"]
CMD ["baidu.com"]#to build, execute: docker build -t entrypoint_and_cmd .
#to override CMD, execute: docker run --rm entrypoint_and_cmd 360.cn

每一个Dockerfile必须的两个命令是FROM命令,和ENTRYPOINT/CMD。FROM命令无需多说,就是指定当前docker image的爹是谁。这里重点说说,ENTRYPOINT和CMD命令。ENTRYPOINT和CMD都可以用来指定docker容器实例启动时执行的启动程序,这两个命令可以分别使用,但是一般推荐组合使用。

以上面的示例为例,这里组合使用了ENTRYPOINT和CMD,运行时的效果是什么呢?

如果我们在命令行执行docker run entrypoint_and_cmd启动这个docker容器,它就相当于执行了下面这一行命令:

ping -n 3 baidu.com

而如果我们用docker run entrypoint_and_cmd 360.cn启动这个容器,则相当于执行了下面这条命令:

ping -n 3 360.cn

也就是说,通过CMD指定的部分,在执行docker run时,如果在参数中的image名字后面指定了一些参数,这些参数会覆盖Dockerfile中定义的CMD后面的命令。

限于篇幅,本文中演示的示例,都是解决相同问题的最佳实践或者推荐实践。但是不会扩展讲太多为什么这是最佳实践,但是我会附上一些参考资料,感兴趣的朋友可以自行阅读。以上面的ENTRYPOINT和CMD的区别问题,更多延伸内容,请参考这篇文章:Dockerfile: ENTRYPOINT vs CMD

ADD和COPY

源码:add_and_copy

FROM microsoft/windowsservercore#on windows, ADD & COPY almost the sameADD test_folder /test_folder_add
COPY test_folder /test_folder_copyADD test_folder /test_folder_add2
COPY test_folder /test_folder_copy2#unlike on linux, ADD doesn't support uncompressing zip files on windowsADD test_folder.zip /
COPY test_folder.zip /ADD test_folder.zip /test_folder_add2.zip
COPY test_folder.zip /test_folder_copy2.zip#how to ADD or COPY files containing space in the nameADD ["file name with space.txt", "/"]
COPY ["file name with space.txt", "/file name with space copy.txt"]#overwriting files also worksADD test.txt /test_overwrite_add.txt
ADD test_overwrite_add.txt /test_overwrite_add.txtCOPY test.txt /test_overwrite_copy.txt
COPY test_overwrite_copy.txt /test_overwrite_copy.txt#add files with wildchar also worksADD wildchar* /
RUN del wildchar*
COPY wildchar* /#the only obvious difference of ADD and COPY on windows is, you can use ADD for downloading files, but not COPYADD https://github.com/jquery/jquery/archive/3.2.1.zip /
ADD https://github.com/jquery/jquery/archive/3.2.1.zip /3.2.1_2.zipENTRYPOINT ["cmd", "/c", "dir"]#to build, execute: docker build -t add_and_copy .#to run, execute: docker run --rm add_and_copy

ADD和COPY也是几乎每个Dockerfile都会用到的命令,它们的作用其实非常类似,就是将文件或者目录从docker client执行的机器复制到正在编译的docker image中。这两个命令只有一些细小差别:

  • ADD命令可用于从一个URL下载文件,而COPY命令不行;

  • 在Linux下的docker中,ADD命令还有一个特殊能力,就是如果ADD一个zip压缩包的话,docker build时它能做自动解压缩,但是在Windows Docker下,没有这个效果;

合并和减少RUN命令

源码:merge_and_reduce_run

FROM microsoft/windowsservercore#run 2 commands in sequence even if the firts one fails, but not the second fails
RUN cd notexists & md folder1#run 2 commands in sequence only if both succeed
RUN md folder2 && md folder3#run 2 commands in sequence only if at least one succeeds
RUN md folder4 || cd notexists#if one line of RUN is too long, breakdown into multiple lines with \ at the end
#so that it is more friendly for code review
RUN echo 1 \         2 \         3 ENTRYPOINT ["cmd", "/c", "dir"]#to build, execute: docker build -t merge_and_reduce_run .
#to run CMD, execute: docker run --rm merge_and_reduce_run

在执行docker build的时候,我们一定能注意到它有step 1,step 2……每个step对于docker build来说,实际上就是创建一个临时的docker image,只执行了一个RUN,所以,如果我们不注意,将每个细小的步骤都写一个RUN的话,最后就会发现,我们的Dockerfile的build变得非常慢,因为步骤太多了。所以,我们应该合理地合并没必要分开RUN的命令。

但是,合并的两个命令到一个RUN里,其实没表面那么简单。以上面的示例为例,前面三个主要是说如何合并多个windows cmd命令:

  • &连接的两个命令代表即使前一个命令执行失败,只要后一个命令执行成功,这个RUN就不算失败;

  • &&连接的两个命令代表两个命令都必须执行成功,整个RUN才成功;

  • ||连接的两个命令代表只要任意一个执行成功,就算整个RUN成功;

注意,所谓RUN成功指的是,如果RUN失败的话,docker build就会中断执行。因此,我们要根据实际情况,只允许可以失败的命令失败,确保重要的命令必须成功。

当然,除了合并windowns cmd命令,我们也可以合并多个powershell命令到一个RUN,例如:

RUN powershell -command "command1;command2;command3"

或者,如果有比较复杂的多个命令,我们最好把多个命令写成一个.cmd或者.ps1脚本,这样,Dockerfile就只需要一个RUN了。

另外,对于一行RUN太长的情况,最好通过""分割成多行书写,这主要是为了方便做代码的Review,这样在diff工具里,能更清晰的显示到底改了什么参数。

到目前为止的sample,其实都不不算Windows Docker特定的案例,相比Linux下,其实都很类似,属于基础中的基础。下面,我们就开始介绍一些Windows下特有的案例:

unzip

源码:unzip

FROM microsoft/windowsservercoreCOPY test_folder.zip /#unzipRUN powershell -Command "expand-archive -Path 'c:\test_folder.zip' -DestinationPath 'c:\'"ENTRYPOINT ["cmd", "/c", "dir"]#to build, execute: docker build -t unzip .#to run CMD, execute: docker run --rm unzip

前面我们说到,ADD命令在Windows Docker下不支持解压缩zip文件。那么,在Windows下如何解压缩呢?最简单的方法,就是使用Expand-Archive这个powershell命令。

set_hosts

源码:set_hosts

FROM microsoft/iis#install ASP.NET 4.5RUN dism /online /enable-feature /all /featurename:IIS-ASPNET45 /NoRestart#deploy webapp
COPY iis-demo /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 script
COPY scripts /scripts
ENTRYPOINT ["C:\\scripts\\SetHostsAndStartMonitoring.cmd"]#to build, execute: docker build -t set_hosts .
#to run, execute: docker run --rm --env-file ./hosts.env set_hosts

在前面的文章中,我们提到过Windows下的Docker目前不支持docker run的--add-host参数。所以,这里我们提供了一个基于环境变量,这里用一个环境变量文件(./hosts.env ),设置Windows系统的hosts文件的方法。其中读取环境变量并设置hosts的代码,其实就是下面的powershell脚本:

If ($env:HOSTS) {  $hosts = $env:HOSTS.Replace(",", "`r`n");  $hosts | Set-Content "C:\Windows\System32\drivers\etc\hosts""Applied hosts: `r`n" + $hosts;
}

gacutil

源码:gacutil

FROM microsoft/windowsservercore#copy minimized gacutil binary to container
COPY tools.zip /
RUN powershell -Command "expand-archive -Path 'c:\tools.zip' -DestinationPath 'c:\'"#install a DLL to GAC with gacutil
COPY Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll /
RUN /tools/gacutil.exe /i Microsoft.VisualStudio.QualityTools.UnitTestFramework.dllENTRYPOINT ["cmd", "/c", "/tools/gacutil.exe", "/l", "Microsoft.VisualStudio.QualityTools.UnitTestFramework"]#to build, execute: docker build -t gacutil .
#to run, execute: docker run --rm gacutil

gacutil是常用的通过命令行注册.NET DLL到GAC的工具。但是这个工具包含在.Net Framework SDK中,并不包含于.NET Framework的分发库中。而为了注册几个DLL而让docker容器里面安装一个臃肿的.NET SDK实在有点难受。因此,这个示例包含了从.NET Framework SDK中抽取出来的单独的gacutil工具,只有94k大小。

enable_eventlog

源码:enable_eventlog

FROM microsoft/windowsservercore#enable eventlog
RUN powershell.exe -command Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Control\WMI\Autologger\EventLog-Application Start 1# list latest 10 system eventlog
CMD powershell -command "Get-EventLog system -newest 10 | Format-List"#to build, execute: docker build -t enable_eventlog .
#to run, execute: docker run --rm enable_eventlog

这个太简单了,不多解释了,就是通过powershell设置了一个注册表值。

enable_wcf

源码:enable_wcf

FROM microsoft/iis#install ASP.NET 4.5RUN dism /online /enable-feature /all /featurename:IIS-ASPNET45 /NoRestart#install WCF features, here we only enabled http and tcp protocol
#for the full list of features you can enable, execute "dism /online /get-features" on a windows server machine
RUN dism /online /enable-feature /featurename:WCF-HTTP-Activation45 /all
RUN dism /online /enable-feature /featurename:WCF-TCP-Activation45 /all#enable WCF protocols
RUN /windows/system32/inetsrv/appcmd.exe set config -section:system.applicationHost/sites /[@0].[@0].enabledProtocols:"http,net.tcp"ENTRYPOINT ["c:\\ServiceMonitor.exe", "w3svc"]#to build, execute: docker build -t enable_wcf .
#to run, execute: docker run --rm enable_wcf

在远古的SOA时代(好像就在眼前,悲伤),WCF是.NET下最热门的技术之一,现在是江河日下了。不过,如何通过命令行enable WCF并设置IIS里的protocols呢?
另外,提一下,上面这行ENTRYPOINT ["c:\ServiceMonitor.exe", "w3svc"]其实不是必须的,因为microsoft/iis这个image其实默认就是执行的这个ENTRYPOINT。这其实是在监控w3svc这个Windows Service的运行,我们当然也可以用它来监控我们自己的Windows Service的,这里顺便提一下。

set_iis_ssl

源码:set_iis_ssl

FROM microsoft/iis#install ASP.NET 4.5RUN dism /online /enable-feature /all /featurename:IIS-ASPNET45 /NoRestart#setup SSL in IISADD iis-test.pfx \iis-test.pfxADD SetSSL.ps1 \SetSSL.ps1#set entrypoint scriptADD SetSSLAndStart.cmd \SetSSLAndStart.cmd
ENTRYPOINT ["C:\\SetSSLAndStart.cmd"]#to build, execute: docker build -t set_iis_ssl .
#to run, execute: docker run --rm -e "SSL_PASS=test" -p 443:443 set_iis_ssl

通过命令行设置IIS的SSL,这个可能干过的不多,但现在SSL几乎是大多数主流网站的标配了,在docker容器里部署网站,也是必不可少的。其中,主要的逻辑,在SetSSLAndStart.cmd中调用SetSSL.ps1执行:

cmd /c "certutil -p %SSL_PASS% -importPFX c:\iis-test.pfx"$addr=[System.Net.Dns]::GetHostAddresses([System.Environment]::MachineName).IPAddressToString
$env:ssl_addr=$addr[1]+":443"cmd /c 'netsh http add sslcert ipport=%ssl_addr% certstorename=MY certhash=C97E4D29C00D9B250EADCFE27D50F09FA76599B0 appid="{4dc3e181-e14b-4a21-b022-59fc669b0914}"'New-WebBinding -name "Default Web Site" -Protocol https  -HostHeader * -Port 443 -SslFlags 1

需要注意的是,这里SSL_PASS包含的证书密码,是读取的一个环境变量。因为,pfx格式的证书中包含非常重要的私钥,我们不可以将密码写在脚本中,必须在docker run的时候传入。另外,netsh http add sslcert的参数中,certhash这个参数的值,这里hardcode了iis-test.pfx这个证书的hash值,如果你要安装的是你自己的证书,需要用你自己证书的hash值替换。对于已经安装于当前机器的自定义证书,我们可以通过下面的powershell命令,列出所有的证书和它们的hash值:

Get-ChildItem cert:\LocalMachine\My

再有,这里的SSL我们是设置到机器当前的ip,除了将SSL通过ipport参数绑定到ip,我们也可以通过hostnameport将SSL绑定到hostname,具体请参考netsh http add sslcert的相关文档。另外,这个示例的部分代码参考了这篇文章

本篇完!不过,本文今后还会持续更新,后面有新的Windows Server Dockerfile的武功心法,我会陆续补充到这篇文章,大家也可以关注相关的Github Repo获取更新。

相关文章:

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

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

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

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

  • .Net大户的选择:Windows Container在携程的应用

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

  • Docker基础入门及示例

  • Linux+Nginx+Asp.net Core部署

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


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

老司机实战Windows Server Docker:5 Windows Server Dockerfile葵花宝典相关推荐

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

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

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

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

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

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

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

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

  5. 说一说windows原生docker及windows Server Container , Hyper Container 之间的关系(学习总结)...

    前一段时间学习netcore的时候解除到了docker,感觉真是不错的技术.百度了不少教程.因为我用windows就下载安装了一下试试.但是没有安装成功,才发现 需要安装virtualbox虚拟机,与 ...

  6. 在Linux和Windows的Docker容器中运行ASP.NET Core

    译者序:其实过去这周我都在研究这方面的内容,结果周末有事没有来得及总结为文章,Scott Hanselman就捷足先登了.那么我就来翻译一下这篇文章,让更多的中文读者看到.当然Scott遇到的坑我也遇 ...

  7. Windows Server Containers 支持 Windows 开发者使用 Docker

    在过去几年里,Docker 和容器已成为全球开发界和企业最热门的话题之一.去年秋天发布的 Windows Server 2016 支持 Windows 开发者使用容器,使得这一热门话题再次升温.Win ...

  8. Windows Server 2016上具有Docker容器SQL Server

    In this article let's see how to install a SQL Server Instance using a Docker container in Windows s ...

  9. 使用 Docker 运行 SQL Server 容器映像 在Windows操作系统上,重设置密码和操作数库

    快速入门:使用 Docker 运行 SQL Server 容器映像 2020/09/07 V O G M Choose your command shell 适用于: 是SQL Server(所有支持 ...

最新文章

  1. python-sendcmd主动模式访问ftp——修改port中IP地址信息
  2. linux下通过rsync+inotify 实现数据实时备份(远程容灾备份系统)
  3. 停车场管理系统代码_jsp19109商场商铺停车场服务系统-SSM-Mysql
  4. mysql表恢复报错binlog_mysqlbinlog 恢复报错ERROR at line 24826643: Unknown command '\'汗血宝马...
  5. redis数据丢失_有效避免数据丢失!Redis持久化方案选择详解
  6. 如何检测支付宝接口中notify_url.php有没有返回,微信小程序支付成功,但是notify_url接收不到回调如何排查此问题?...
  7. android contentresolver 批量,Android之使用ContentResolver对通信录中的数据进行简单操作...
  8. T-SQL: Batches
  9. pat1062. Talent and Virtue (25)
  10. jxta-P2P学习
  11. 北理工嵩天Python面向对象程序设计笔记
  12. geojson 河流_openlayers之点,线,面(以城市,河流,省份为例,分别对应点线面)...
  13. 层次分析法(AHP)介绍
  14. 学习笔记:OriTripletLoss函数的解析 源码解析
  15. 图片怎么修改尺寸大小?在线调整图像大小的方法
  16. vue的多标签页实现
  17. 哪个牌子的蓝牙耳机音质好?音质比较好的蓝牙耳机排名
  18. 内科大和内农大计算机,内蒙古八大高校排名,“内大”第一实至名归,“内财”垫底上榜...
  19. 断网的html页面,断网情况下,前端页面处理
  20. FreeRTOS 队列管理

热门文章

  1. jQuery子页面获取父页面元素
  2. 实验三《实时系统的移植》 20145222黄亚奇 20145213祁玮
  3. [Linux]Linux下安装和配置solr/tomcat/IK分词器 详细实例二.
  4. eclipse创建maven多模块项目(单个类似)
  5. Objective-C 学习记录6--dictionary
  6. iOS开发  plist字段列表,很全
  7. oracle express介绍
  8. WTMPlus 1.4 Uniapp来了
  9. 使用IQueryable扩展方法实现复杂查询条件
  10. .NET Core使用FluentEmail发送邮件