【TeamCity】使用TeamCity搭建ASP.NET Core + SVN 的 CICD环境

您所在的位置:网站首页 搭建CICD环境 【TeamCity】使用TeamCity搭建ASP.NET Core + SVN 的 CICD环境

【TeamCity】使用TeamCity搭建ASP.NET Core + SVN 的 CICD环境

2024-07-10 10:34| 来源: 网络整理| 查看: 265

引言:

最近公司让我使用TeamCity搭建公司的CICD环境,但是国内对于使用TeamCity搭建CICD环境的教程或者博客很少,在搭建的过程中遇到的坑颇多,查找解决方案时很是费力。最终在多番折腾下终于搭建完成,写此博客记录 一番,也希望能为后续使用TeamCity的朋友提供些许帮助。

环境描述:ASP.NET Core + SVN + Windowes Server + IIS 

使用TeamCity搭建CICD环境,实现ASP.NET Core 的自动构建、自动发布到测试环境

这里TeamCity和TeamCityBuildAgent部署在同一台服务器(A)上,站点部署在另外一台服务器(B)上,两台均为Windows Server 2016服务器。

目标: CICD策略是开发分支有提交立刻进行集成,构建、测试。 每天凌晨进行代码的构建、发布,保证每天都将最近代码发布到测试环境 (后期待做)加入静态代码检测和单元测试覆盖率检测 (后期待做)固定版本迭代周期,定期发布代码至生产环境

本文只讲1.2前两个目标的配置,3、4两点待后期完成后再开一篇。

实现重点:

  1.为保证发布能顺利完成,需要在发布前停止站点,发布完成后重新启动站点,否则会出现文件被IIS进程占用的情况导致发布失败

  2.对发布前的站点进行备份,如果发布期间出现问题导致发布失败,要对代码进行回滚操作

 

正文开始

 

 一、安装TeamCity和TeamCityAgent

  这一步直接在官网选择对应的版本进行安装即可,也可以选择docker安装,官网提供了相应的脚本,这里是我的脚本,增加持久化映射:

docker run -d --name teamcity-server-instance -v E:/DockerVolume/teamcity/datadir:/data/teamcity_server/datadir -v E:/DockerVolume/teamcity/logs:/opt/teamcity/logs -p 8111:8111 jetbrains/teamcity-server

  安装完成之后,可通过访问ip:8111,我这里是localhost:8111,进入后等待初始化完成,进行相关配置,我这里都是默认配置,此处省略。

二、项目初始化配置

  1.通过点击站点右上角的Administration进入到管理菜单,点击Create project进行项目的创建

 

   2.进入配置页面,配置VCS,进入下一步,配置项目相关信息

 

 

 

   3.配置完成后,TeamCity会自动检测项目,并给出推荐构建步骤,可以根据自己项目的具体情况进行选择和修改

 

三、配置构建步骤-Build阶段   1.配置构建步骤

本项目build阶段的构建步骤共三步,restore、build、test,TeamCity在配置是提供了一定程度的只能提示,可以通过点击输入框后面的方便的选择环境变量、路径和其他提示,配置如下:

 

 

  1.restore 注意配置nuget路径

 

   2.build 注意配置nuget路径和选择对应的Configuration,这里我选择Release

 

 

  3.test

 

   2.配置构建的触发器,使每次提交均会出发构建

 

 

 

 

四、配置构建步骤-Deploy阶段

  发布阶段的构建步骤如下:

build 项目 停止站点并备份 发布到CI服务器的临时文件夹 通过FTP上传到web服务器 标记发布状态 检查发布状态,如果失败则进行回滚操作 重新启动站点 设置发布结果(如果发布失败则报告CI发布错误),清理备份文件夹

  接下来描述一下每个构建步骤设置的脚本

  1.build项目,该步骤同三、配置构建步骤-Build阶段中的build配置相同,此处不再赘述

  2.停止站点并备份,为何在此时便停止站点呢?因为如果先进行发布到CI服务器再进行停止,仍然会有一定的几率出现文件被占用的问题,所以将此步骤提前,此步骤中使用Powershell脚本对站点进行管理和备份,并使用配置参数优化脚本,脚本如下:

1 $password='%Deployment.RemoteServer.Password%' 2 $userName='%Deployment.RemoteServer.UserName%' 3 $server='%Deployment.RemoteServer.IP%' 4 $pass=ConvertTo-SecureString -String $password -AsPlainText -Force 5 $cre=New-Object pscredential($userName, $pass) 6 $session=New-PSSession -ComputerName $server -Credential $cre -Authentication Basic 7 8 Invoke-Command -Session $session -ScriptBlock{ 9 import-module webadministration 10 set-location IIS:\ 11 $site=Get-Item 'IIS:\Sites\{websiteName}' 12 # 停止站点 13 $site.Stop() 14 # 开始对站点备份 15 $websitePath = $site.physicalPath 16 write-host "检测到站点路径:" $websitePath 17 $bakPath = $websitePath+'.Bak' 18 if(Test-Path $bakPath) 19 { 20 write-host "备份站点路径已存在" $bakPath 21 Remove-Item $bakPath -Recurse 22 write-host "已删除备份站点" 23 } 24 write-host "开始备份站点到" $bakPath 25 Copy-Item $websitePath $bakPath -Recurse 26 write-host "备份完成" 27 #备份结束 28 }

 

  

 

 

   3.发布到CI服务器的临时文件夹

  

 

 

   4.通过FTP上传到web服务器,此步骤需要在web服务器搭建Ftp站点,并指向web站点所在的文件夹

  

 

 

   

  5.标记发布状态,当前面所有步骤均构建成功时,则执行此脚本标记发布状态为SUCCESS,否则不执行,这里使用的时TeamCity的特性,详情可参考官方文档。此步骤的其他环境配置同步骤2的配置相同,此处省略,仅描述powershell脚本内容:

1 echo "##teamcity[setParameter name='env.BUILD_STATUS' value='SUCCESS']" 2 Write-Host "发布成功,设置环境变量:" env.BUILD_STATUS: $env.BUILD_STATUS 3 #SUCCESS

 

  6.检查发布状态,如果失败则进行回滚操作,此步骤的其他环境配置同步骤2的配置相同,此处省略,仅描述powershell脚本内容:

1 $password='%Deployment.RemoteServer.Password%' 2 $userName='%Deployment.RemoteServer.UserName%' 3 $server='%Deployment.RemoteServer.IP%' 4 $pass=ConvertTo-SecureString -String $password -AsPlainText -Force 5 $cre=New-Object pscredential($userName, $pass) 6 $session=New-PSSession -ComputerName $server -Credential $cre -Authentication Basic 7 if($env:BUILD_STATUS -ne "SUCCESS") 8 { 9 Write-Host "发布失败,准备回滚" 10 Invoke-Command -Session $session -ScriptBlock{ 11 import-module webadministration 12 set-location IIS:\ 13 $site=Get-Item 'IIS:\Sites\XMGISPlatformNETCore' 14 $websitePath = $site.physicalPath 15 write-host "检测到站点路径:" $websitePath 16 $bakPath = $websitePath+'.Bak' 17 if(Test-Path $bakPath) 18 { 19 write-host "备份站点路径存在,可以回滚" $bakPath 20 write-host "删除当前站点文件" 21 Remove-Item $websitePath/* -Recurse -Force 22 write-host "删除完成" 23 write-host "开始回滚" 24 Copy-Item $bakPath/* $websitePath -Recurse 25 write-host "回滚完成" 26 } 27 } 28 } 29 else 30 { 31 Write-Host '发布成功,无需回滚' 32 }

 

  7.重新启动站点,仅描述powershell脚本内容:

1 $password='%Deployment.RemoteServer.Password%' 2 $userName='%Deployment.RemoteServer.UserName%' 3 $server='%Deployment.RemoteServer.IP%' 4 $pass=ConvertTo-SecureString -String $password -AsPlainText -Force 5 $cre=New-Object pscredential($userName, $pass) 6 $session=New-PSSession -ComputerName $server -Credential $cre -Authentication Basic 7 8 Invoke-Command -Session $session -ScriptBlock{ 9 import-module webadministration 10 set-location IIS:\ 11 $site=Get-Item 'IIS:\Sites\{websiteName}' 12 $site.Start() 13 }

 

  8.标记发布结果(如果发布失败则报告CI发布错误),清理备份文件夹,此步骤根据步骤5设置的发布结果来判断此次发布是否成功,如果成功,则清理备份站点,否则标记发布结果为失败。仅描述powershell脚本内容:

1 if($env:BUILD_STATUS -ne "SUCCESS") 2 { 3 write-host "发布失败" 4 exit(-1) 5 } 6 else 7 { 8 write-host "发布完成,清理备份文件夹" 9 $password='%Deployment.RemoteServer.Password%' 10 $userName='%Deployment.RemoteServer.UserName%' 11 $server='%Deployment.RemoteServer.IP%' 12 $pass=ConvertTo-SecureString -String $password -AsPlainText -Force 13 $cre=New-Object pscredential($userName, $pass) 14 $session=New-PSSession -ComputerName $server -Credential $cre -Authentication Basic 15 16 Invoke-Command -Session $session -ScriptBlock{ 17 import-module webadministration 18 set-location IIS:\ 19 $site=Get-Item 'IIS:\Sites\{websiteName}' 20 21 $websitePath = $site.physicalPath 22 $bakPath = $websitePath+'.Bak' 23 if(Test-Path $bakPath) 24 { 25 write-host "备份站点路径已存在" $bakPath "准备删除" 26 Remove-Item $bakPath -Recurse 27 write-host "已删除备份站点" 28 } 29 write-host "清理完毕" 30 } 31 32 }

 

  配置参数的设置如下:

  

   在Deploy结果,我加入了重试触发器,当构建失败时,将在10秒后重试,连续重试3次,配置如下:

 

  

踩坑记录   关于发布前停止站点问题和Powershell远程连接服务器问题

为保证在部署过程中不因为IIS进程占用文件导致部署失败,要在部署前停止IIS站点,在部署成功后重新启动IIS站点。

根据官方文档:

When ASP.Net detects that a file by the name of "App_Offline.htm" exists, it will automatically bring down the app domain hosting the application. When the publish process is completed, the App_Offline.htm file will be removed and the site will be online again.

即当IIS检测到文件中包含App_Offline.htm文件时会自动停止进程,当发布完成,检测到该文件被删除后,IIS会自动启动进程。

但是在我使用TeamCity使用FTP进行发布时,虽然TeamCity会在发布时帮我我们发送App_Offline.htm文件,但是仍然会因为未知原因(初步怀疑:该文件提前被删除,站点提前被启动)导致会出现文件被占用问题,错误如下:

[Step 4/4] Deployment problem: Failed to upload artifacts via FTP. Reply was: 550 The process cannot access the file because it is being used by another process.

 

所以决定在发布站点之前使用PowerShell脚本来停止IIS站点,但在执行脚本时出现错误:

New-PSSession : [ip] 连接到远程服务器 ip 失败,并显示以下错误消息: WinRM 客户端无法处理该请求。如果身份验证方案与 Kerberos 不同,或者客户端计算机未加入到域中, 则必须使用 HTTPS 传输或者必须将目标计算机添加到 TrustedHosts 配置设置。 使用 winrm.cmd 配置 TrustedHosts。请注意,TrustedHosts 列表中的计算机可能未经过身份验证。 通过运行以下命令可获得有关此内容的更多信息: winrm help config。 有关详细信息,请参阅 about_Remote_Troubleshooting 帮助主题。所在位置 行:4 字符: 10+ $session=New-PSSession -ComputerName $server -Credential $cre+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotingTransportException + FullyQualifiedErrorId : ServerNotTrusted,PSSessionOpenFailedInvoke-Command : 无法对参数“Session”执行参数验证。参数为 Null 或空。请提供一个不为 Null 或空的参数,然后重试该命令。所在位置 行:6 字符: 25+ Invoke-Command -Session $session -ScriptBlock{+ ~~~~~~~~ + CategoryInfo : InvalidData: (:) [Invoke-Command],ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.InvokeCommandCommand

可以通过以下命令将ip加入信任列表,注意,此命令要在客户端执行,而不是在要连接的服务端执行

Set-Item wsman:\localhost\Client\TrustedHosts -value 120.26.6.*

配置完成后,可以在本地实现远程关闭启动IIS站点,但是在TeamCity中仍然无法启动,错误如下:

[15:25:46][Step 4/7] New-PSSession : [10.26.6.193] 连接到远程服务器 10.26.6.193 失败,并显示以下错误 [15:25:46][Step 4/7] 消息: WinRM 无法处理该请求。使用 Negotiate 身份验证时发生错误代码为 0x8009030d [15:25:46][Step 4/7] 的以下错误: 指定的登录会话不存在。可能已被终止。 [15:25:46][Step 4/7] 可能的原因为: [15:25:46][Step 4/7] -指定的用户名或密码无效。 [15:25:46][Step 4/7] -未指定身份验证方法和用户名时,使用了 Kerberos。 [15:25:46][Step 4/7] -Kerberos 接受域用户名,但不接受本地用户名。 [15:25:46][Step 4/7] -远程计算机名和端口的服务主体名称(SPN)不存在。 [15:25:46][Step 4/7] -客户端和远程计算机位于不同的域中,并且两个域之间没有信任关系。 [15:25:46][Step 4/7] 检查上述问题之后,尝试以下操作: [15:25:46][Step 4/7] -检查事件查看器中与身份验证有关的事件。 [15:25:46][Step 4/7] -更改身份验证方法;将目标计算机添加到 WinRM TrustedHosts 配置设置中或 使用 HT [15:25:46][Step 4/7] TPS 传输。 [15:25:46][Step 4/7] 请注意,TrustedHosts 列表中的计算机可能未经过身份验证。 [15:25:46][Step 4/7] -有关 WinRM 配置的详细信息,请运行以下命令: winrm help config。 有关详细信息, [15:25:46][Step 4/7] 请参阅 about_Remote_Troubleshooting 帮助主题。 [15:25:46][Step 4/7] Other Possible Cause: [15:25:46][Step 4/7] -The domain or computer name was not included with the specified credential, [15:25:46][Step 4/7] for example: DOMAIN\UserName or COMPUTER\UserName. [15:25:46][Step 4/7] 所在位置 行:1 字符: 10 [15:25:46][Step 4/7] + $session=New-PSSession -ComputerName $server -Credential $cre [15:25:46][Step 4/7] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [15:25:46][Step 4/7] + CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:Re [15:25:46][Step 4/7] moteRunspace) [New-PSSession], PSRemotingTransportException [15:25:46][Step 4/7] + FullyQualifiedErrorId : 1312,PSSessionOpenFailed [15:25:46][Step 4/7] Process exited with code 1

根据提示,对两台服务进行了配置,并在使用远程登陆时指定认证方式为Basic

配置如下(此配置修改须在管理员模式下执行,否则无法修改):

1 //快速在服务端运行winrm 2 c:\> winrm quickconfig 3 4 //查看winrm的运行情况 5 c:\> winrm e winrm/config/listener 6 7 //查看winrm的配置 8 c:\> winrm get winrm/config 9 10 //将service中的基本身份验证设置为true,允许 11 c:\> winrm set winrm/config/service/auth @{Basic="true"} 12 13 // 将service中的allowUnencrypted设置为true,允许未加密的通讯 14 c:\> winrm set winrm/config/service @{AllowUnencrypted="true"} 15 16 //将client中的基本身份验证设置为true,允许 17 c:\> winrm set winrm/config/client/auth @{Basic="true"} 18 19 // 将client中的allowUnencrypted设置为true,允许未加密的通讯 20 c:\> winrm set winrm/config/client @{AllowUnencrypted="true"}

最终配置如下图:

客户端:

 

 

 

 服务端:

 

 最终的停止IIS站点的脚本如下,启动站点的脚本只要修改最后的函数即可:

1 $server='server ip' 2 $pass=ConvertTo-SecureString -String 'serverpassword' -AsPlainText -Force 3 $cre=New-Object pscredential('serverUser', $pass) 4 $session=New-PSSession -ComputerName $server -Credential $cre -Authentication Basic 5 6 Invoke-Command -Session $session -ScriptBlock{ 7 import-module webadministration 8 set-location IIS:\ 9 $site=Get-Item 'IIS:\Sites\{websiteName}' 10 $site.Stop() 11 }

 

 

 

参考:

https://www.cnblogs.com/gamewyd/p/6805595.html

https://www.cnblogs.com/weloveshare/p/5569719.html

 

 


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3