通常我们可以直接使用镜像microsoft/dotnet 作为dotnetcore应用程序的基础镜像,可以直接使用Kerstrel作为Web服务器。但实际情况不总是这样,本文先介绍如何使用powershell将AspNetCore程序部署到IIS,然后在window docker环境下将其打包成windows docker image。
首先我们要引入PowerShell中的WebAdministration模块,这样就可以对IIS进行相关的操作了
Import-Module WebAdministration
在IIS中运行ASP.NetCore程序,先要安装AspNetCoreModule,需要使用DotNetCore.WindowsHosting安装
# 如果你的程序是dotnetcore 2.0就安装这个
Invoke-WebRequest -Uri "https://aka.ms/dotnetcore.2.0.0-windowshosting" -OutFile "DotNetCore.WindowsHosting.exe"
# 安装此exe时,实际上它会弹出一个框要求你点击安装按钮,但这里肯定是希望能silent安装, ArgumentList 就是起这个作用的; -Wait 意思是让这个程序安装完成后再执行下一个程序
Start-Process "DotNetCore.WindowsHosting.exe" -Wait -ArgumentList '/S', '/v', '/qn' -passthru
# 如果你的程序是dotnetcore 2.1就安装这个
Invoke-WebRequest -Uri "https://download.microsoft.com/download/9/3/E/93ED35C8-57B9-4D50-AE32-0330111B38E8/dotnet-hosting-2.1.1-win.exe" -OutFile "dotnet-hosting-2.1.1-win.exe"
Start-Process "dotnet-hosting-2.1.1-win.exe" -Wait -ArgumentList '/S', '/v', '/qn' -passthru
安装完DotNetCore.WindowsHosting之后,需要重启IIS服务
Invoke-Expression "net stop was /y"
Invoke-Expression "net start w3svc"
可以使用以下命令来检测ASPNetCoreModule是否已安装
Get-WebGlobalModule -Name AspNetCoreModule -ErrorAction Ignore
接下来就是要对程序部署,IIS设置
# 创建一个应用程序池,名称为TestApp
New-Item -path IIS:\AppPools\TestApp
# 把应用程序池的.Net版本设置为无托管代码
Set-ItemProperty -Path IIS:\AppPools\TestApp -Name managedRuntimeVersion -Value ''
# 创建一个网站
New-Website -name TestSite -PhysicalPath "C:\TestSite" -ApplicationPool TestApp -Port 80
# 访问网站
Invoke-WebRequest -uri http://localhost -usebasicparsing
安装SSL证书
# 增加HTTPS 绑定到 "*.container.com" 通配的证书
$pwd = ConvertTo-SecureString -String "123123123132" -Force -AsPlainText
Import-PfxCertificate -FilePath "c:\\install\\wildcard.pfx" -CertStoreLocation 'Cert:\LocalMachine\My' -Password $pwd -Verbose
Import-PfxCertificate -FilePath "c:\\install\\wildcard.pfx" -CertStoreLocation 'Cert:\LocalMachine\Root' -Password $pwd -Verbose
$cert = Get-ChildItem cert:\LocalMachine\MY | Where-Object { $_.FriendlyName -like "container.com" }
$binding = New-WebBinding -Name $websiteName -Protocol 'https' -Port 443 -IPAddress '*'
$NewBinding = Get-WebBinding -protocol https
$NewBinding.AddSSLCertificate("$($cert.getcerthashstring())", "MY")
其他powershell命令(这里暂时不使用)
#New-WebBinding -Name "mygod.stage.xxx.com" -IPAddress "*" -Port 80 -HostHeader "mygod.stage.accenture.com" -SslFlags 0 -Protocol "http"
#New-WebBinding -Name "mygod-api.stage.xxx.com" -IPAddress "*" -Port 80 -HostHeader "mygod-api.stage.accenture.com" -SslFlags 0 -Protocol "http"
#Set-WebBinding -Name "mygod.stage.xxx.com" -BindingInformation "*:443:" -PropertyName "HostHeader" -Value "mygod.stage.xxx.com"
#Get-WebBinding
#New-Item -Path "D:\apps\" -Name "myapi" -ItemType "directory"
#Get-Item(Join-Path 'IIS:AppPools\' 'mygod.stage.xxx.com') | select -ExpandProperty processModel | select -expand identityType
#Set-ItemProperty IIS:\AppPools\mygod.stage.xxx.com -name processModel.identityType -Value SpecificUser
#Set-ItemProperty IIS:\AppPools\mygod.stage.xxx.com -name processModel.userName -Value $username
#Set-ItemProperty IIS:\AppPools\mygod.stage.xxx.com -name processModel.password -Value $password
#Set-ItemProperty IIS:\AppPools\mygod.stage.xxx.com -name processModel.identityType -Value SpecificUser
#Set-ItemProperty IIS:\AppPools\mygod.stage.xxx.com -name processModel.userName -Value ""
#Set-ItemProperty IIS:\AppPools\mygod.stage.xxx.com -name processModel.password -Value ""
#cd D:\apps\webapi\
#(type 'appsettings.json') -replace ('VD120761','VLN120761')|out-file appsettings.json
#(type 'appsettings.json') -replace ('MultiSubnetFailover=False','MultiSubnetFailover=True')|out-file appsettings.json
#Invoke-Expression "net stop was /y"
#Invoke-Expression "net start w3svc"
#cat .\appsettings.json
#set-location D:\apps\webapi
#dotnet .\myapi.dll calculate-mapcount
给当前网站的物理路径设置权限
$path = "C:\inetpub\wwwroot"
$acl = Get-Acl $path
$permission = 'IIS_IUSRS', 'FullControl', 'ContainerInherit, ObjectInherit', 'None', 'Allow';
$permission = 'Everyone', 'FullControl', 'ContainerInherit, ObjectInherit', 'None', 'Allow';
$rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permission;
$acl.SetAccessRule($rule);
$acl | Set-Acl -Path $path;
创建一个EventLog试试
New-EventLog -Source "WSR" -LogName "Application"
在C:\Windows\System32\drivers\etc\hosts中增加一条记录,以便用DNS name进行访问
$fqdn = "test.container.com";
$hostPath = 'C:\Windows\System32\drivers\etc\hosts';
$hostFile = Get-Content $hostPath;
$hostEntry = "127.0.0.1 `t $fqdn";
Add-content -path $hostPath -value $hostEntry
ipconfig /flushdns
# 下面的 escape在window系统非常有用,它用以定义在Dockerfile中使用转义字符,Dockerfile中,escape默认为\,这里转义为`,而且必须放在第一行,参考https://blog.csdn.net/chengqiuming/article/details/79007598
# escape=`
# 这里本可以使用如下镜像,用Kerstrel作为WEB服务器,但本文不这样做
#FROM microsoft/dotnet:2.1-aspnetcore-runtime-nanoserver-sac2016 AS base
# 这里使用官方的Windows Server Core作为基础镜像
FROM microsoft/windowsservercore:latest AS base
# 这里是这个build镜像,专用于build我们的源代码
#FROM microsoft/dotnet:2.1-sdk-nanoserver-1803 AS build
FROM microsoft/dotnet:2.1-sdk-nanoserver-sac2016 AS build
WORKDIR /src
COPY ["./webapi.csproj", "."]
RUN dotnet restore "webapi.csproj"
COPY . .
RUN dotnet build "webapi.csproj" -c Release -o /app
# 这里发部程序
FROM build AS publish
RUN dotnet publish "webapi.csproj" -c Release -o /app
FROM base AS final
# 这里在镜像中启用powershell脚本环境
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
LABEL name="WSR" `
release-date="2019-1-4"
# Disable DNS cache so container addresses always fetched from Docker
#RUN Set-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
# Activate Windows features based on the app's requirements.
#RUN Add-WindowsFeature Web-App-Dev, Web-Net-Ext45, Web-Asp-Net45, Web-ISAPI-Ext, Web-ISAPI-Filter, NET-Framework-45-ASPNET
# 将上面使用powershell脚本Copy到镜像中
RUN New-Item -ItemType Directory C:\install;
COPY .\install-website.ps1 C:\install
# DONT TOUCH - Paths used during CI build after solution MSBUILD.exe
# COPY .\bin\Release\PublishOutput C:\inetpub\wwwroot\
COPY --from=publish /app C:\inetpub\wwwroot\
RUN 'Log written in docker build' >> 'C:\Logs\docker-build.log';
#这里就是我们上面使用powershell命令安装dotnetcore程序到IIS的脚本
ENTRYPOINT ["powershell.exe", "C:\\install\\install-website.ps1"]
# 这里可以对你的程序作一些健康检查
# HEALTHCHECK --interval=60s --timeout=60s --start-period=100s --retries=3 CMD C:\install\healthcheck.bat
1.在用COPY命令复制文件时报了一个错
OPY failed: CreateFile \\?\C:\ProgramData\Docker\tmp\docker-builder832533802\mysolution.sln: The system cannot find the file specified.
找了很久,原因是源路径没有设置对,要仔细检查你当前运行的路径和COPY的前半段相对路径组合在一起看是否能找到你需要COPY的源文件。