.Net在Windows上使用Jenkins做CI/CD的那些事

背景
最近入職了一家新公司,公司各個(gè)方面都讓我非常的滿意,我也懷著緊張與興奮的心情入職后,在第一天接到了領(lǐng)導(dǎo)給我的第一個(gè)任務(wù)——把整個(gè)項(xiàng)目的依賴引用重新整理并實(shí)施項(xiàng)目的CI/CD。
本篇的重點(diǎn)主要分享這次在Windows平臺(tái)使用Jenkins做.Net Framework的自動(dòng)化,真是所謂一波N折。
有關(guān)注過我的博客的朋友們,應(yīng)該知道我之前都是在Linux上實(shí)施.Net Core,好不容易把Linux技能點(diǎn)起來,現(xiàn)在玩回Windows+.Net Framework感覺有一種回到鉆木取火的年代。
在實(shí)施過程中讓我感悟最多的是,dotnet core命令的便捷性,Linux運(yùn)維的便捷性,下文我有很多構(gòu)建腳本都是shell腳本來的,當(dāng)時(shí)想著學(xué)習(xí)一次就不需要學(xué)習(xí)bat腳本了,最終還是躲不過。
在遠(yuǎn)程傳送并遠(yuǎn)程執(zhí)行命令我折騰得最久,開始想著用FTP與Telnet,誰知道Telnet命令沒有附帶賬號(hào)密碼參數(shù),腳本不好寫,后改成PsExec.exe,使用過程中很多奇怪的問題,后來不得不去折騰OpenSSH,說實(shí)話還是SSH好用,直接代替了FTP與PsExec。中間還遇到Jenkins使用本機(jī)賬號(hào)執(zhí)行的權(quán)限問題。所有“坑”的我在下面步驟盡可能給大家規(guī)避了。
引用整理

項(xiàng)目(包含所以依賴的項(xiàng)目)依賴引用丟失,主要體現(xiàn)以下幾點(diǎn):
官方依賴包沒有使用NuGet
內(nèi)部項(xiàng)目引用通過本地引用,項(xiàng)目沒有拉取則編譯失敗
NuGet包多個(gè)版本的引用
同屬一個(gè)解決方案,但是項(xiàng)目分散到各個(gè)倉(cāng)庫(kù)
依賴沒有規(guī)范化對(duì)軟件工程主要帶來以下幾點(diǎn)影響:
缺少代碼或者代碼路徑不一致則無法正常編譯通過
對(duì)于新人同事不友好
實(shí)現(xiàn)CI/CD會(huì)有很大的阻力
解決方案與順序:
整理組件庫(kù)到統(tǒng)一解決方案,日后有需要拆分再按需拆分,優(yōu)先保證需要依賴的在一個(gè)方案。
實(shí)現(xiàn)組件庫(kù)的自動(dòng)發(fā)布到私有Nuget
整理API項(xiàng)目的依賴,拋棄以前本地依賴的方式,統(tǒng)一使用Nuget
實(shí)現(xiàn)API項(xiàng)目的自動(dòng)發(fā)布到IIS
工具準(zhǔn)備
| 工具名稱 | 下載地址 | 描述 |
| jdk-8u261-windows-i586.exe | https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html | Jenkins依賴 |
| nuget.exe CLI | ?https://dist.nuget.org/win-x86-commandline/latest/nuget.exe | 發(fā)布、還原.Net依賴包 |
| MsBuild | https://visualstudio.microsoft.com/zh-hans/vs/community/ | msbuild在vs安裝程序里 |
| Jenkins | https://www.jenkins.io/zh/download/ | |
| git | https://git-scm.com/download/win | |
| ?OpenSSH服務(wù)端 | https://github.com/PowerShell/Win32-OpenSSH/releases | ?遠(yuǎn)程傳輸與遠(yuǎn)程執(zhí)行命令 |
物理部署圖

文章會(huì)分享跨網(wǎng)絡(luò)環(huán)境的場(chǎng)景,我們使用了Gitee的企業(yè)倉(cāng)儲(chǔ),Jenkins與Nuget.Server會(huì)放在阿里云服務(wù)器,機(jī)房會(huì)開放一臺(tái)服務(wù)器與阿里云服務(wù)器進(jìn)行SSH的通信。
以上是基本的信息概要,下面會(huì)進(jìn)入具體的實(shí)施步驟。
NuGet.Server的部署
新建一個(gè)ASP.Net Web應(yīng)用程序(.NetFramework),并選擇空模板,搜索NuGet.Server選擇3.4.1版本安裝后,打開Web.config文件設(shè)置apiKey,然后就可以部署到47.115.111.58的IIS了。
官方部署文檔可以查看?https://docs.microsoft.com/zh-cn/nuget/hosting-packages/nuget-server


?
安裝MsBuild
在服務(wù)器47.115.111.58打開通過上面表格的鏈接下載VS的安裝包,點(diǎn)開單個(gè)組件選項(xiàng)卡,勾選Msbuild,等待一會(huì)即可完成。

配置nuget.exe CLI
在服務(wù)器47.115.111.58根據(jù)上面表格nuget.exe CLI,下載后放到一個(gè)合適的文件目錄,并在【環(huán)境變量配置】配置好路徑,打開cmd并輸入指令nuget help出現(xiàn)以下畫面證明成功。

添加NuGet還原源配置項(xiàng)
在部署Jenkins服務(wù)器47.115.111.58,打開C:\Windows\system32\config\systemprofile\AppData\Roaming\NuGet\NuGet.Config,沒有的化可以自己建一個(gè),輸入以下腳本。
如果沒有配置好,接下來的應(yīng)用項(xiàng)目可能會(huì)編譯時(shí)還原包失敗導(dǎo)致無法編譯通過。
"1.0" encoding="utf-8"?>
"nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
"私有NuGet服務(wù)" value="http://47.115.11.58:8008/nuget" />
"Microsoft Visual Studio Offline Packages" value="C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\" />
安裝OpenSSH服務(wù)端
根據(jù)上面表格的地址下載解壓后,在服務(wù)器47.115.151.108以管理員啟動(dòng)CMD
?
cd C:\tools\OpenSSH-Win64
#安裝服務(wù)端
powershell.exe -ExecutionPolicy Bypass -File install-sshd.ps1
#啟動(dòng)服務(wù)
net start ssh-agent
sc config ssh-agent start= auto
net start sshd
sc config sshd start= auto
#防火墻打開22端口
#大于等于 Windows Server 2012
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
#小于 Windows Server 2012
netsh advfirewall firewall add rule name=sshd dir=in action=allow protocol=TCP localport=22
這樣就可以通過administrator賬號(hào)或者管理員賬號(hào)在客戶端用ssh登錄了。
以上是各個(gè)服務(wù)器基本依賴安裝。
安裝Jenkins
在服務(wù)器47.115.111.58,先把jdk與git安裝好后,點(diǎn)開Jenkins安裝,選擇默認(rèn)路徑下一步,遇到設(shè)置服務(wù)登錄賬戶的時(shí)候,必須選擇以administrator安裝,不然后續(xù)會(huì)有很多執(zhí)行的權(quán)限問題。

如果點(diǎn)擊Test Credentials無法通過,可以在運(yùn)行輸入mmc打開策略編輯器,并在計(jì)算機(jī)配置-[windows設(shè)置]-[安全設(shè)置]-[本地策略]-[用戶權(quán)限分配]-[作為服務(wù)登錄],填寫administrator或者您的管理員賬號(hào)。

接著點(diǎn)擊下一步等待完成后,會(huì)彈出一個(gè)localhost:8080的頁(yè)面,根據(jù)他的指示初始化界面就可以了。輸入完管理員賬號(hào)后這個(gè)時(shí)候可以去修改workspace的地址,當(dāng)時(shí)我沒有修改地址的時(shí)候,因?yàn)槁窂接刑厥庾址麑?dǎo)致無論如何都無法用msbuild編譯通過。
打開C:\Windows\System32\config\systemprofile\AppData\Local\Jenkins.jenkins\config.xml,修改workspaceDir屬性的值為C:/jenkins_workspace/${ITEM_FULL_NAME},盡可能給一個(gè)簡(jiǎn)單純英文的路徑。
配置Jenkins
在主界面點(diǎn)擊【Manage Jenkins】-【Configure System】界面,定位到Shell,輸入您剛安裝的git路徑的sh.exe,C:\Program Files\Git\bin\sh.exe

同樣界面定位到SSH Servers點(diǎn)擊Add Server把剛剛安裝OpenSSL的服務(wù)器47.115.151.108填寫進(jìn)去,賬號(hào)密碼是47.115.151.108服務(wù)器管理員的賬號(hào)密碼。

在主界面點(diǎn)擊【Manage Jenkins】-【Global Tool Configuration】界面,定位到Git,輸入您剛安裝的git路徑的git.exe,C:\Program Files\Git\bin\git.exe

到這里Jenkins的配置基本上完成了。
自動(dòng)發(fā)布組件包到NuGet
新建Freestyle project,并在【源碼管理】、【構(gòu)建】填入您的構(gòu)建信息,構(gòu)建腳本我是保存在服務(wù)器上,因?yàn)楸4嬖诜?wù)器上更加可靠。

?
?
構(gòu)建腳本shell示例
#!/bin/bash
#腳本開始執(zhí)行
echo '腳本開始執(zhí)行'
base_path=C:/jenkins_workspace/Librariy
nuget_url=http://47.115.111.58:8008/nuget
nuget_api_key=B82D6DDB-C6F958E8C945
nuget restore $base_path
for project_name in $base_path/*
do
project_path=$project_name
package_path=$project_path/packages
rm -rf $package_path
nuget pack $project_path -Build -IncludeReferencedProjects -Properties Configuration=Release -OutputDirectory $package_path &&
nuget push -ApiKey $nuget_api_key -Source $nuget_url $package_path/*.nupkg
if [ $? -eq 0 ]; then
echo '發(fā)布成功:'$project_name''
else
echo '發(fā)布失敗:'$project_name''
fi
done
echo '腳本執(zhí)行結(jié)束'
以上發(fā)布組件包到私有NuGet的步驟就實(shí)施完畢了。
自動(dòng)發(fā)布Web應(yīng)用到IIS
新建Freestyle project,并在【源碼管理】、【構(gòu)建】填入您的構(gòu)建信息。[Publish Over SSH]插件跟OpenSSL能把編譯好的文件發(fā)送到相應(yīng)的服務(wù)器,并執(zhí)行對(duì)應(yīng)的集群分發(fā)腳本。
?

示例構(gòu)建shell腳本
#!/bin/bash
echo '腳本開始執(zhí)行'
base_path=C:/jenkins_workspace/API
project_path=$base_path/API.csproj
publish_path=$base_path/publish
rm -rf $publish_path
nuget restore $base_path &&
MSBuild.exe $project_path -t:"rebuild;publish;ResolveReferences;_CopyWebApplication" -p:"Configuration=Release;OutputPath=$publish_path"
if [ $? -eq 0 ]; then
echo '發(fā)布成功:'$project_name''
else
echo '發(fā)布失敗:'$project_name''
fi
echo '腳本執(zhí)行結(jié)束'
示例分發(fā)bat腳本
記得在局域網(wǎng)把相應(yīng)服務(wù)器的共享文件夾啟動(dòng)
net use \\192.168.1.2\app "password" /user:"administrator"
xcopy/a/s/h/y C:\app\ftp\SFNovelAPI \\192.168.1.2\app\API
net use \\192.168.1.3\app "password" /user:"administrator"
xcopy/a/s/h/y C:\app\ftp\SFNovelAPI \\192.168.1.3\app\APIxcopy/a/s/h/y C:\app\ftp\SFNovelAPI C:\app\SFNovelAPI
結(jié)束
以上記錄并分享了我在Windows實(shí)施自動(dòng)化的過程與步驟,如果大家有更好的建議與提議,可以在下方評(píng)論反饋給我。
【推薦】.NET Core開發(fā)實(shí)戰(zhàn)視頻課程?★★★
.NET Core實(shí)戰(zhàn)項(xiàng)目之CMS 第一章 入門篇-開篇及總體規(guī)劃
【.NET Core微服務(wù)實(shí)戰(zhàn)-統(tǒng)一身份認(rèn)證】開篇及目錄索引
Redis基本使用及百億數(shù)據(jù)量中的使用技巧分享(附視頻地址及觀看指南)
.NET Core中的一個(gè)接口多種實(shí)現(xiàn)的依賴注入與動(dòng)態(tài)選擇看這篇就夠了
10個(gè)小技巧助您寫出高性能的ASP.NET Core代碼
用abp vNext快速開發(fā)Quartz.NET定時(shí)任務(wù)管理界面
在ASP.NET Core中創(chuàng)建基于Quartz.NET托管服務(wù)輕松實(shí)現(xiàn)作業(yè)調(diào)度
現(xiàn)身說法:實(shí)際業(yè)務(wù)出發(fā)分析百億數(shù)據(jù)量下的多表查詢優(yōu)化
給我好看
您看此文用
?
?
·
?
秒,轉(zhuǎn)發(fā)只需1秒呦~

好看你就
點(diǎn)點(diǎn)
我

