技术思绪摘录旅行笔记
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台。这是一个免费的源代码,可以处理任何类型的构建或持续集成。集成Jenkins可以用于一些测试和部署技术。

1、打开Jenkins,选择新建Item

image.png

2、填写项目名称,选择自由风格,点击确定

image.png

3、勾选This project is parameterized,开始设置参数

image.png

image.png

先看下这几种参数类型:常用的就几种,本文中用到的就

Choice Parameter:选择型参数

String Parameter:字符串参数

4、我们开始添加参数

image.png

这样以此类推,下面把参数都列举一下

分支名称-选择参数:

BRANCH_NAME

master

分支名称

编译方式-选择参数:

COMPILE_MODE

Debug
Release

编译方式

启动项目所在文件夹-字符串参数:

PROJECT_START_PATH

src/JwtDemoApi

启动项目文件夹

主版本号-字符串参数:

MAJOR_NO

1

主版本号

次版本号-字符串参数:

BUILD_NO

1

次版本号

IIS站点名称-字符串参数:

SITE_NAME

JwtDemoApi

IIS站点名称

 IIS站点端口号-字符串参数:

SITE_PORT

809

IIS站点端口号

IIS发布站点绝对路径-字符串参数:

SITE_PUBLISH_PATH

E:\WebSite\WebSite_JwtDemoApi

IIS发布站点绝对路径(结尾不带斜杠,vs发布的路径/临时发布文件夹)

IIS运行地址绝对路径-字符串参数:

SITE_RUN_PATH

E:\Feature\Host

IIS运行站点绝对路径(结尾不带斜杠,IIS运行的就是这个目录下的文件,需要手动加一个Config文件夹,启用这个文件下的配置文件)

IIS绑定的域名-字符串参数:

SITE_HOST

baidu.com

IIS站点绑定的域名


5、配置源码管理-git

image.png

Repository URL:填你的git仓库地址

Credentials:添加一个能拉取操作你git仓库的账号

指定分支:${BRANCH_NAME},这里填写的变量

6、构建-增加构建步骤,选择Execute Windows Batch Command(执行windows bat命令)

image.png

脚本V1-简单暴力版本,直接重新发布,删除iis站点,重新创建

chcp 65001 > nul 

echo "进入目录"
cd %PROJECT_START_PATH%

echo "还原项目包"
dotnet restore
rem dotnet restore -s "https://api.nuget.org/v3/index.json" -s "https://jhrs.com/lib/nuget"

echo "编译代码"
dotnet build -c "%COMPILE_MODE%"

echo "停止IIS站点"
C:\Windows\System32\inetsrv\appcmd.exe stop site "%SITE_NAME%"
C:\Windows\System32\inetsrv\appcmd.exe stop appPool /appPool.name:"%SITE_NAME%"

echo "删除现有文件,重新发布"
del /f /s /q %SITE_PUBLISH_PATH%\*.*

echo "发布项目"
dotnet publish -c %COMPILE_MODE%  -r win-x64 --self-contained true   -o "%SITE_PUBLISH_PATH%"

echo "新建版本号"
md "%SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID%"

echo "拷贝项目到当前版本"
xcopy %SITE_PUBLISH_PATH% %SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID% /s/e/y

echo "拷贝指定文件夹的配置文件"
xcopy %SITE_RUN_PATH%\Config %SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID% /s/e/y

echo "删除站点"
C:\Windows\System32\inetsrv\appcmd.exe delete site "%SITE_NAME%"
C:\Windows\System32\inetsrv\appcmd.exe delete apppool "%SITE_NAME%"

echo "新建站点"
C:\Windows\System32\inetsrv\appcmd.exe add site /name:"%SITE_NAME%" /bindings:http://*:%SITE_PORT% /physicalpath:"%SITE_RUN_PATH%\%MAJOR_NO%.%BUILD_NO%.%BUILD_ID%"
C:\Windows\System32\inetsrv\appcmd.exe add AppPool /name:"%SITE_NAME%"
C:\Windows\System32\inetsrv\appcmd.exe Set app "%SITE_NAME%/" /applicationpool:"%SITE_NAME%"
C:\Windows\System32\inetsrv\appcmd.exe set apppool /apppool.name:"%SITE_NAME%" /managedRuntimeVersion:""

echo "启动项目"
C:\Windows\System32\inetsrv\appcmd.exe start site "%SITE_NAME%"
C:\Windows\System32\inetsrv\appcmd.exe start appPool /appPool.name:"%SITE_NAME%"
C:\Windows\System32\inetsrv\appcmd.exe recycle appPool /appPool.name:"%SITE_NAME%"

脚本V2-支持绑定域名和iis证书

@echo off
setlocal EnableExtensions DisableDelayedExpansion

if defined DEPLOY_UTF8_READY goto :main
chcp 65001 >nul
set "DEPLOY_UTF8_READY=1"
call "%~f0" %*
exit /b %errorlevel%

:main
for %%V in (PROJECT_START_PATH COMPILE_MODE SITE_NAME SITE_PORT SITE_PUBLISH_PATH SITE_RUN_PATH MAJOR_NO BUILD_NO THR_NO) do (
    if not defined %%V (
        echo [错误] 缺少环境变量:%%V
        exit /b 1
    )
)

set "APPCMD=%windir%\System32\inetsrv\appcmd.exe"
set "VERSION=%MAJOR_NO%.%BUILD_NO%.%THR_NO%"
set "VERSION_PATH=%SITE_RUN_PATH%\%VERSION%"
if not defined SITE_HOST set "SITE_HOST=这是你的域名"
set "SITE_HTTP_PORT=80"
set "SITE_HTTPS_PORT=443"
set "BUILD_ARTIFACTS_PATH=%SITE_PUBLISH_PATH%"
set "FINDSTR=%SystemRoot%\System32\findstr.exe"

if "%SITE_PORT%"=="%SITE_HTTP_PORT%" (
    echo [错误] SITE_PORT 是额外监听端口,不能与域名 HTTP 端口 %SITE_HTTP_PORT% 相同
    exit /b 1
)
if "%SITE_PORT%"=="%SITE_HTTPS_PORT%" (
    echo [错误] SITE_PORT 是额外监听端口,不能与域名 HTTPS 端口 %SITE_HTTPS_PORT% 相同
    exit /b 1
)

if not exist "%APPCMD%" (
    echo [错误] 未找到 AppCmd:%APPCMD%
    exit /b 1
)

echo ============================================================
echo [开始] %date% %time%
echo [信息] 站点名称:%SITE_NAME%
echo [信息] 发布版本:%VERSION%
echo [信息] 域名 HTTP 端口:%SITE_HTTP_PORT%
echo [信息] 域名 HTTPS 端口:%SITE_HTTPS_PORT%
echo [信息] 额外 HTTP 监听端口:%SITE_PORT%(不绑定域名)
echo ============================================================

echo [1/10] 还原程序
echo [信息] 项目目录:%PROJECT_START_PATH%
echo [信息] 编译模式:%COMPILE_MODE%
echo [信息] 目标运行时:win-x64
cd /d "%PROJECT_START_PATH%" || goto :fail
set "MSBUILDDISABLENODEREUSE=1"
dotnet restore --runtime win-x64 || goto :fail
echo [完成] 程序还原成功

echo [2/10] 停止 IIS 站点和应用程序池
echo [信息] IIS 站点:%SITE_NAME%
"%APPCMD%" list site /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
    echo [信息] 站点已存在,正在停止
    call :StopSiteAndWait "%SITE_NAME%" 5 2
    if errorlevel 1 (
        echo [错误] 停止站点超时或失败
        goto :fail
    )
) else (
    echo [跳过] IIS 站点不存在
)
"%APPCMD%" list apppool /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
    echo [信息] 应用程序池已存在,正在停止
    call :StopAppPoolAndWait "%SITE_NAME%" 5 2
    if errorlevel 1 (
        echo [错误] 停止应用程序池超时或失败
        goto :fail
    )
) else (
    echo [跳过] IIS 应用程序池不存在
)
echo [完成] IIS 停止检查完成

echo [3/10] 删除现有文件
echo [信息] 临时发布目录:%SITE_PUBLISH_PATH%
if exist "%SITE_PUBLISH_PATH%\." (
    echo [信息] 正在删除临时发布目录
    rmdir /s /q "%SITE_PUBLISH_PATH%" || goto :fail
) else (
    echo [跳过] 临时发布目录不存在
)
echo [信息] 版本运行目录:%VERSION_PATH%
if exist "%VERSION_PATH%\." (
    echo [信息] 正在删除现有版本目录
    rmdir /s /q "%VERSION_PATH%" || goto :fail
) else (
    echo [跳过] 现有版本目录不存在
)
echo [信息] 正在创建临时发布目录
md "%SITE_PUBLISH_PATH%" || goto :fail
echo [完成] 现有文件清理完成

echo [4/10] 发布项目到指定目录
echo [信息] 发布目标:%SITE_PUBLISH_PATH%
echo [信息] 自包含发布:true
dotnet publish -c "%COMPILE_MODE%" --runtime win-x64 --self-contained true --no-restore -o "%SITE_PUBLISH_PATH%" || goto :fail
echo [完成] 项目发布成功

echo [5/10] 拷贝项目文件到运行目录
echo [信息] 来源:%SITE_PUBLISH_PATH%
echo [信息] 目标:%VERSION_PATH%
md "%VERSION_PATH%" || goto :fail
set "VERSION_DIR_CREATED=1"
xcopy "%SITE_PUBLISH_PATH%\*" "%VERSION_PATH%\" /s /e /y /i
if errorlevel 1 goto :fail
echo [完成] 项目文件拷贝成功

echo [6/10] 拷贝配置文件到运行目录
echo [信息] 配置来源:%SITE_RUN_PATH%\Config
echo [信息] 配置目标:%VERSION_PATH%
if exist "%SITE_RUN_PATH%\Config\." (
    echo [信息] 正在覆盖运行目录中的配置
    xcopy "%SITE_RUN_PATH%\Config\*" "%VERSION_PATH%\" /s /e /y /i
    if errorlevel 1 goto :fail
) else (
    echo [跳过] 配置目录不存在
)
echo [完成] 配置文件处理完成

echo [7/10] 删除 IIS 站点和应用程序池
"%APPCMD%" list site /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
    echo [信息] 正在删除 IIS 站点:%SITE_NAME%
    "%APPCMD%" delete site "%SITE_NAME%" || goto :fail
) else (
    echo [跳过] IIS 站点不存在
)
"%APPCMD%" list apppool /name:"%SITE_NAME%" /text:name 2>nul | "%FINDSTR%" /x "%SITE_NAME%" >nul
if not errorlevel 1 (
    echo [信息] 正在删除 IIS 应用程序池:%SITE_NAME%
    "%APPCMD%" delete apppool "%SITE_NAME%" || goto :fail
) else (
    echo [跳过] IIS 应用程序池不存在
)
echo [完成] IIS 站点和应用程序池删除完成

echo [8/10] 创建 IIS 应用程序池和站点
echo [信息] 正在创建应用程序池:%SITE_NAME%
"%APPCMD%" add apppool /name:"%SITE_NAME%" || goto :fail
"%APPCMD%" set apppool /apppool.name:"%SITE_NAME%" /managedRuntimeVersion:"" || goto :fail
echo [信息] 正在创建站点:%SITE_NAME%
echo [信息] 站点物理路径:%VERSION_PATH%
echo [信息] 初始监听:http://*:%SITE_PORT%
"%APPCMD%" add site /name:"%SITE_NAME%" /bindings:"http/*:%SITE_PORT%:" /physicalPath:"%VERSION_PATH%" || goto :fail
"%APPCMD%" set app "%SITE_NAME%/" /applicationPool:"%SITE_NAME%" || goto :fail
echo [完成] IIS 应用程序池和站点创建成功

echo [9/10] 绑定 HTTP、HTTPS 域名和证书
echo [信息] HTTP 域名绑定:http://%SITE_HOST%:%SITE_HTTP_PORT%
echo [信息] HTTPS 绑定:https://%SITE_HOST%:%SITE_HTTPS_PORT%
echo [信息] 正在添加 HTTP 域名绑定
"%APPCMD%" set site /site.name:"%SITE_NAME%" /+bindings.[protocol='http',bindingInformation='*:%SITE_HTTP_PORT%:%SITE_HOST%'] || goto :fail
echo [信息] 正在添加 HTTPS SNI 绑定
"%APPCMD%" set site /site.name:"%SITE_NAME%" /+bindings.[protocol='https',bindingInformation='*:%SITE_HTTPS_PORT%:%SITE_HOST%',sslFlags='1'] || goto :fail
echo [信息] 正在从 Cert:\LocalMachine\My 和 Cert:\LocalMachine\WebHosting 检索并绑定证书
call :BindHttpsCertificate "%SITE_HOST%" "%SITE_HTTPS_PORT%"
if errorlevel 1 goto :fail
echo [完成] HTTP、HTTPS 域名和证书绑定成功

echo [10/10] 启动 IIS 应用程序池和站点
echo [信息] 正在启动应用程序池:%SITE_NAME%
"%APPCMD%" start apppool /apppool.name:"%SITE_NAME%" || goto :fail
echo [信息] 正在启动站点:%SITE_NAME%
"%APPCMD%" start site /site.name:"%SITE_NAME%" || goto :fail
echo [完成] IIS 应用程序池和站点启动成功

echo [成功] 发布完成
echo [结束] %date% %time%
echo [信息] 版本:%VERSION%
echo [信息] 运行目录:%VERSION_PATH%
echo [信息] HTTP 地址:http://%SITE_HOST%:%SITE_HTTP_PORT%
echo [信息] 访问地址:https://%SITE_HOST%:%SITE_HTTPS_PORT%
echo [信息] 额外监听:http://服务器IP:%SITE_PORT%
exit /b 0

:fail
set "FAIL_CODE=%errorlevel%"
if "%FAIL_CODE%"=="0" set "FAIL_CODE=1"
echo [失败时间] %date% %time%
echo [错误] 发布失败,退出码:%FAIL_CODE%
if defined BUILD_ARTIFACTS_PATH if exist "%BUILD_ARTIFACTS_PATH%\." (
    echo [清理] 删除临时发布目录:%BUILD_ARTIFACTS_PATH%
    rmdir /s /q "%BUILD_ARTIFACTS_PATH%"
)
if defined VERSION_DIR_CREATED if exist "%VERSION_PATH%\." (
    echo [清理] 删除未完成的版本目录:%VERSION_PATH%
    rmdir /s /q "%VERSION_PATH%"
)
echo [错误] 发布流程已终止
exit /b 1

rem ========== 子过程:按域名检索 LocalMachine\My/WebHosting 证书并绑定到 SNI 端点 ==========
:BindHttpsCertificate
setlocal
set "HTTPS_HOST=%~1"
set "HTTPS_PORT=%~2"
powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "$ErrorActionPreference='Stop'; $hostName=$env:HTTPS_HOST; $port=$env:HTTPS_PORT; $now=Get-Date; function Test-DnsName([string]$pattern,[string]$name) { if ($pattern -ieq $name) { return $true }; if ($pattern.StartsWith('*.')) { $suffix=$pattern.Substring(1); if ($name.EndsWith($suffix,[StringComparison]::OrdinalIgnoreCase)) { $prefix=$name.Substring(0,$name.Length-$suffix.Length); return $prefix.Length -gt 0 -and $prefix.IndexOf('.') -lt 0 } }; return $false }; $certPaths=@('Cert:\LocalMachine\My','Cert:\LocalMachine\WebHosting'); $certMatches=@(Get-ChildItem -Path $certPaths -ErrorAction SilentlyContinue | Where-Object { $candidate=$_; if (-not $candidate.HasPrivateKey -or $candidate.NotBefore -gt $now -or $candidate.NotAfter -le $now) { return $false }; $names=@($candidate.DnsNameList | ForEach-Object { $_.Unicode }); if ($names.Count -eq 0 -and $candidate.Subject -match '(?:^|,\s*)CN=([^,]+)') { $names=@($Matches[1].Trim()) }; foreach ($name in $names) { if (Test-DnsName $name $hostName) { return $true } }; return $false } | Sort-Object NotAfter -Descending); if ($certMatches.Count -eq 0) { throw ('在 Cert:\LocalMachine\My 和 Cert:\LocalMachine\WebHosting 中未找到域名 {0} 的有效且带私钥证书' -f $hostName) }; $cert=$certMatches[0]; $certStoreName=if ($cert.PSParentPath -match '\\WebHosting$') { 'WebHosting' } else { 'MY' }; $endpoint=('{0}:{1}' -f $hostName,$port); $appId='{4dc3e181-e14b-4a21-b022-59fc669b0914}'; & netsh.exe http show sslcert ('hostnameport={0}' -f $endpoint) *> $null; if ($LASTEXITCODE -eq 0) { & netsh.exe http update sslcert ('hostnameport={0}' -f $endpoint) ('certhash={0}' -f $cert.Thumbprint) ('appid={0}' -f $appId) ('certstorename={0}' -f $certStoreName) | Out-Host } else { & netsh.exe http add sslcert ('hostnameport={0}' -f $endpoint) ('certhash={0}' -f $cert.Thumbprint) ('appid={0}' -f $appId) ('certstorename={0}' -f $certStoreName) | Out-Host }; if ($LASTEXITCODE -ne 0) { throw ('HTTPS 证书绑定失败,netsh 退出码:{0}' -f $LASTEXITCODE) }; Write-Host ('已绑定证书:{0},证书存储:LocalMachine\{1},有效期至:{2:yyyy-MM-dd HH:mm:ss}' -f $cert.Subject,$certStoreName,$cert.NotAfter)"
if errorlevel 1 (
    echo [错误] HTTPS 证书检索或绑定失败
    exit /b 1
)
exit /b 0

rem ========== 子过程:停止站点并等待完全停止 ==========
:StopSiteAndWait
setlocal
set "SITE_NAME=%~1"
set "MAX_RETRIES=%~2"
set "SLEEP_SEC=%~3"
if "%MAX_RETRIES%"=="" set "MAX_RETRIES=5"
if "%SLEEP_SEC%"=="" set "SLEEP_SEC=2"

rem 先检查当前状态,如果已经是 Stopped 则直接返回成功
"%APPCMD%" list site /name:"%SITE_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
    echo 站点 %SITE_NAME% 已处于停止状态
    exit /b 0
)

rem 尝试停止(忽略错误,因为可能正在停止或已停)
"%APPCMD%" stop site /site.name:"%SITE_NAME%" >nul 2>&1

set /a retry=0
:stop_site_loop
set /a display_retry=retry+1
echo [等待] 站点停止状态检查 %display_retry%/%MAX_RETRIES%,%SLEEP_SEC% 秒后重试
timeout /t %SLEEP_SEC% /nobreak >nul
"%APPCMD%" list site /name:"%SITE_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
    echo 站点 %SITE_NAME% 已成功停止
    exit /b 0
)
set /a retry+=1
if %retry% lss %MAX_RETRIES% goto :stop_site_loop

echo 警告:停止站点 %SITE_NAME% 超时,当前状态:
"%APPCMD%" list site /name:"%SITE_NAME%" /text:state
exit /b 1

rem ========== 子过程:停止应用程序池并等待完全停止 ==========
:StopAppPoolAndWait
setlocal
set "APPPOOL_NAME=%~1"
set "MAX_RETRIES=%~2"
set "SLEEP_SEC=%~3"
if "%MAX_RETRIES%"=="" set "MAX_RETRIES=5"
if "%SLEEP_SEC%"=="" set "SLEEP_SEC=2"

"%APPCMD%" list apppool /name:"%APPPOOL_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
    echo 应用程序池 %APPPOOL_NAME% 已处于停止状态
    exit /b 0
)

"%APPCMD%" stop apppool /apppool.name:"%APPPOOL_NAME%" >nul 2>&1

set /a retry=0
:stop_apppool_loop
set /a display_retry=retry+1
echo [等待] 应用程序池停止状态检查 %display_retry%/%MAX_RETRIES%,%SLEEP_SEC% 秒后重试
timeout /t %SLEEP_SEC% /nobreak >nul
"%APPCMD%" list apppool /name:"%APPPOOL_NAME%" /text:state 2>nul | "%FINDSTR%" /i "Stopped" >nul
if not errorlevel 1 (
    echo 应用程序池 %APPPOOL_NAME% 已成功停止
    exit /b 0
)
set /a retry+=1
if %retry% lss %MAX_RETRIES% goto :stop_apppool_loop

echo 警告:停止应用程序池 %APPPOOL_NAME% 超时,当前状态:
"%APPCMD%" list apppool /name:"%APPPOOL_NAME%" /text:state
exit /b 1

7、编译如果提示nuget 不存在则在工作目录新建 nuget.config文件,因为你的项目中,可能引用的dll来自你私有nuget

image.png

8、自动构建,根据仓库的变化,自动构建。

image.png

Poll SCM:设置定时检查代码仓库是否有变更,有变更则构建

定时构建语法

* * * * *

第一个*表示分钟,取值0~59

第二个*表示小时,取值0~23

第三个*表示一个月的第几天,取值1~31

第四个*表示第几月,取值1~12

第五个*表示一周中的第几天,取值0~7,其中0和7代表的都是周日

H开头是定时构建,不带H的定时检查,有变化才构建

每隔5分钟构建一次

H/5 * * * *

每两小时构建一次

H H/2 * * *

每天中午下班前定时构建一次

0 12 * * *

每天下午下班前定时构建一次

0 18 * * *

每15分钟构建一次:H/15 * * * * 或*/5 * * * *

每天8点构建一次:0 8 * * *

每天8点~17点,两小时构建一次:0 8-17/2 * * *

周一到周五,8点~17点,两小时构建一次:0 8-17/2 * * 1-5

每月1号、15号各构建一次,除12月:H H 1,15 1-11 *

*/5 * * * * (每5分钟检查一次源码变化)
0 2 * * * (每天2:00 必须build一次源码)

9、手动触发

image.png


CarsonIT 微信扫码关注公众号 策略、创意、技术

留下您的脚步

 

最近评论

查看更多>>

站点统计

总文章数:285 总分类数:18 总评论数:93 总浏览数:256.85万

精选推荐

阅读排行

友情打赏

请打开您的微信,扫一扫