zoukankan      html  css  js  c++  java
  • 【TeamCity】使用TeamCity搭建ASP.NET Core + SVN 的 CICD环境

    引言:

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

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

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

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

    目标:

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


    本文只讲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阶段

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

    1. build 项目
    2. 停止站点并备份
    3. 发布到CI服务器的临时文件夹
    4. 通过FTP上传到web服务器
    5. 标记发布状态
    6. 检查发布状态,如果失败则进行回滚操作
    7. 重新启动站点
    8. 设置发布结果(如果发布失败则报告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:SitesXMGISPlatformNETCore'
    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。请注意,Trus
    tedHosts 列表中的计算机可能未经过身份验证。 通过运行以下命令可获得有关此内容的更多信息: 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,PSSessionOpenFailed
    Invoke-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:localhostClientTrustedHosts -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: DOMAINUserName or COMPUTERUserName.
    [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

     
  • 相关阅读:
    采用商业智能提升企业的数字营销策略
    采用商业智能提升企业的数字营销策略
    《PostgreSQL服务器编程》一一1.3 超越简单函数
    《PostgreSQL服务器编程》一一1.3 超越简单函数
    《PostgreSQL服务器编程》一一1.3 超越简单函数
    《PostgreSQL服务器编程》一一1.3 超越简单函数
    2017 全球半导体预估跳增 11.5%,存储器最夯
    2017 全球半导体预估跳增 11.5%,存储器最夯
    如何从零学习PostgreSQL Page结构
    转成json必须是unicdoe字符
  • 原文地址:https://www.cnblogs.com/c-supreme/p/12856168.html
Copyright © 2011-2022 走看看