0.Jenkins构建产物的几种方式
1.使用Pipeline脚本去构建
这种方式的好处就是可以使用Groovy脚本去写,自由度很高,使用多少节点,使用什么容器,使用什么规则,只要是Groovy支持的基本都能写,这也是Jenkins2.0的主要构建方式。这种方式适用于插件用的多,构建Node多,构建环境复杂,构建流程复杂的团队。推荐使用~
2.使用FreeStyle方式去构建
这种方式的好处的自由,想怎么写怎么写,想用什么打包就用什么打包,想写什么脚本就写什么脚本。这种方式的对于Shell和NodeJs写的好的人来说简直就是神器,但是使用插件就没得Pipeline那么舒心了。适合插件用的少的,Shell写的牛逼的团队、初学者、项目构建不复杂的团队。但是项目不复杂用Pipeline会更加的顺滑。
接下来我全部使用Pipeline作为例子来进行讲解,其中会将构建产物上传至Jforg,有兴趣的小伙伴可以移步
安装并配置Jfrog-Artifactory
1.使用Jenkins构建Dotnet包
stage('Init Environment'){
script {
env.p_ns = 'namespace' // 命名空间
env.p_fullname = 'Data' // 项目名称
env.p_name = 'data' // 项目名称
env.c_type = '7z' // 压缩方式
env.artifactory = 'http://jfrog.xxx.top/artifactory' // 产物仓库地址
env.git_branch = 'devlop' // 所用分支
env.git_addr = 'http://git.xxx.com/project.git' // Git地址
if (!env.app_version) {
env.app_version = "auto_version_${env.BUILD_NUMBER}"
}
echo "${env.p_name}"
echo "${env.p_ns}"
}
}
node('k8s-agent-dotnet'){
stage('Clone'){
checkout([$class: 'GitSCM', branches: [[name: "origin/${env.git_branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: 'git-user-id', url: "${env.git_addr}"]]])
}
dir("01.src/services/${env.p_name}/Eimp.${env.p_fullname}.HttpApi.Host"){
stage('Build Project Test'){
container('dotnet5'){
sh 'dotnet --info'
// jnlp镜像的用户是Jenkins,dotnet镜像的用户是root,所以有下面的这一句
// 没有777的权限,jenkins用户就没办法操作这个root用户新建的文件夹
sh 'rm -rf ./publish && mkdir publish && chmod -R 777 publish'
// sh "dotnet restore ./Eimp.${env.p_fullname}.HttpApi.Host.csproj --configfile ./Scripts/Nuget/nuget.config"
sh "dotnet publish ./Eimp.${env.p_fullname}.HttpApi.Host.csproj -c Release -o ./publish --configfile ./Scripts/Nuget/nuget.config"
sh 'cp -r ./Scripts/Docker/Dockerfile ./publish/'
}
dir('publish'){
sh "7z a -t${env.c_type} ${env.p_name}.${env.c_type} ./"
}
}
stage('Upload PKG'){
withCredentials([usernamePassword(credentialsId: 'jfrog_robot', passwordVariable: 'password', usernameVariable: 'username')]) {
sh "curl -u ${username}:${password} -T ./publish/${env.p_name}.${env.c_type} ${env.artifactory}/${env.p_ns}/${env.app_version}/${env.p_name}_${env.app_version}.${env.c_type}"
}
}
}
}
node('docker-agent'){
stage('Clear Workspace'){
sh 'rm -rf ./*'
}
// 将产物下载到Docker构建专用Node上
stage('Download PKG'){
withCredentials([usernamePassword(credentialsId: 'jfrog_robot', passwordVariable: 'password', usernameVariable: 'username')]) {
sh "curl -u ${username}:${password} ${env.artifactory}/${env.p_ns}/${env.app_version}/${env.p_name}_${env.app_version}.${env.c_type} -o ./${env.p_name}.${env.c_type}"
}
sh "7za x ./${env.p_name}.${env.c_type} -r -o./"
sh "rm -rf ./${env.p_name}.${env.c_type}"
}
// 构建镜像
stage('Build And Push Docker Image'){
docker.withRegistry('https://docker-factory.xxx.top', 'harbor_push_robot') {
def docker_img = docker.build("${env.p_ns}/${env.p_name}:${env.app_version}");
docker_img.push()
}
}
// 执行一段NodeJs通知Rancher平台更新最新的Images
stage('Update Project In Rancher'){
script{
if(env.need_startup){
nodejs('NodeJs 15.5.0') {
withCredentials([usernamePassword(credentialsId: 'rancher', passwordVariable: 'password', usernameVariable: 'username')]) {
sh "node /home/jenkins/tools/rancher/publish.js /project/c-gwjgg:p-h485k/workloads/deployment:xxxx:${env.p_name} ${env.app_version} ${password} ${username}"
}
}
}
else{
echo "No startup required"
}
}
}
// 利用sshPublisher插件发布到服务器,这里不能拿来就用啊,这里是我从别的项目复制过来的
// 需要修改一下才能正常使用的
stage('Publish To Server') {
script {
def servers = env.pub_servers.tokenize(',')
if(servers.size() > 0){
def server_params = []
for(server in servers) {
server_params.add(
sshPublisherDesc(
configName: server,
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: "sh ./scripts/update_service_v2.sh ${env.p_name} ${env.c_type}",
execTimeout: 120000,
flatten: false,
makeEmptyDirs: true,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: 'pkgs',
remoteDirectorySDF: false,
removePrefix: 'publish',
sourceFiles: "publish/${env.p_name}.${env.c_type}"
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: true
)
)
}
sshPublisher(publishers: server_params)
}
else{
echo 'Not Choose Server'
}
}
}
}
2.使用Jenkins构建Node/Web包
stage('Init Environment'){
script {
env.p_ns = 'namespace' // 命名空间
env.p_name = 'web-client' // 项目名称
env.c_type = '7z' // 压缩方式
env.artifactory = 'http://jfrog.xxxx.top/artifactory'
env.git_branch = 'devlop' // 所用分支
env.git_addr = 'http://git.xxx.com/project.git' // Git地址
if (!env.app_version) {
env.app_version = "auto_version_${env.BUILD_NUMBER}"
}
echo "${env.p_name}"
echo "${env.p_ns}"
}
}
// 为了复用节点,这里随意选择带有jnlp的节点就行了,因为大部分操作都只基于NodeJs这个插件
node('k8s-agent || k8s-agent-dotnet'){
stage('Clone'){
checkout([$class: 'GitSCM', branches: [[name: "origin/${env.git_branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: 'dbadff90-a2c7-4d03-8e48-808118abcaf5', url: "${env.git_addr}"]]])
}
stage('Build Project'){
sh 'rm -rf ./build'
nodejs('NodeJs 15.5.0') {
sh 'yarn'
sh "yarn build"
}
sh 'cp -r ./nginx ./build/'
sh 'cp -r ./Dockerfile ./build/'
dir('build'){
sh "7z a -t${env.c_type} ${env.p_name}.${env.c_type} ./"
}
}
stage('Upload PKG'){
withCredentials([usernamePassword(credentialsId: 'jfrog_robot', passwordVariable: 'password', usernameVariable: 'username')]) {
sh "curl -u ${username}:${password} -T ./build/${env.p_name}.${env.c_type} ${env.artifactory}/${env.p_ns}/${env.app_version}/${env.p_name}_${env.app_version}.${env.c_type}"
}
}
}
node('docker-agent'){
stage('Clear Workspace'){
sh 'rm -rf ./*'
}
stage('Download PKG'){
withCredentials([usernamePassword(credentialsId: 'jfrog_robot', passwordVariable: 'password', usernameVariable: 'username')]) {
sh "curl -u ${username}:${password} ${env.artifactory}/${env.p_ns}/${env.app_version}/${env.p_name}_${env.app_version}.${env.c_type} -o ./${env.p_name}.${env.c_type}"
}
sh "7za x ./${env.p_name}.${env.c_type} -r -o./build"
sh 'mv ./build/nginx ./'
sh 'mv ./build/Dockerfile ./'
}
stage('Build And Push Docker Image'){
docker.withRegistry('https://docker-factory.xxx.top', 'harbor_push_robot') {
def docker_img = docker.build("${env.p_ns}/${env.p_name}:${env.app_version}");
docker_img.push()
}
}
stage('Update Project In Rancher'){
script{
if(env.need_startup){
nodejs('NodeJs 15.5.0') {
withCredentials([usernamePassword(credentialsId: 'rancher', passwordVariable: 'password', usernameVariable: 'username')]) {
sh "node /home/jenkins/tools/rancher/publish.js /project/c-gwjgg:p-h485k/workloads/deployment:xxxx:${env.p_name} ${env.app_version} ${password} ${username}"
}
}
}
else{
echo "No startup required"
}
}
}
// 利用sshPublisher插件发布到服务器,这里不能拿来就用啊,这里是我从别的项目复制过来的
// 需要修改一下才能正常使用的
stage('Publish To Server') {
script {
def servers = env.pub_servers.tokenize(',')
if(servers.size() > 0){
def server_params = []
for(server in servers) {
server_params.add(
sshPublisherDesc(
configName: server,
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: "sh ./scripts/update_service_v2.sh ${env.p_name} ${env.c_type}",
execTimeout: 120000,
flatten: false,
makeEmptyDirs: true,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: 'pkgs',
remoteDirectorySDF: false,
removePrefix: 'publish',
sourceFiles: "publish/${env.p_name}.${env.c_type}"
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: true
)
)
}
sshPublisher(publishers: server_params)
}
else{
echo 'Not Choose Server'
}
}
}
}
3. 注意
所有需要用到环境变量的地方都要用双引号""
,不然就会被当做字符串使用
sshPublisher
插件的execCommand
参数值只能执行服务器~/
这个路径下面的脚本
4. 贴一下update_service_v2.sh 的脚本
#!/bin/bash
m_p="/apps" # 主路径
service=$1 # 服务名称
pkg_type=$2 # 压缩包类型
if [ ! -n "$pkg_type" ]; then
pkg_type='zip';
fi
update_services() {
# 进入执行主目录
cd "${m_p}"
if [ ! -f "./pkgs/${service}.${pkg_type}" ]; then
echo "压缩包不存在,请确认压缩包存在后再试"
exit 1
fi
# 检测运行目录是否存在
if [ ! -d "./apps/${service}" ]; then
mkdir "./apps/${service}"
else
if [ ${service} != "web_client" ] && [ ${service} != "app_client" ]; then # 前端比较特殊无需用supervisor守护
# supervisorctl status "$service" | awk '{print $2}'
# echo $?
if [ $(supervisorctl status "$service" | awk '{print $2}') = "RUNNING" ]; then # 当处于运行状态下的情况下才进行停止操作
supervisorctl stop "$service"; #--rt2
fi
fi
rm -rf "./apps/${service}/*"
fi
if [ ${pkg_type} == "zip" ]; then
unzip -oq "./pkgs/${service}.${pkg_type}" -d "./apps/${service}"
else
7za x -y t${pkg_type} "./pkgs/${service}.${pkg_type}" -r -o./apps/${service}
fi
if [ -d "./configs/${service}" ]; then
for c_name in $(ls ./configs/${service}/); do
rm -rf "./apps/${service}/$c_name"
cp -r "./configs/${service}/$c_name" "./apps/${service}"
done
fi
if [ ${service} != "web_client" ] && [ ${service} != "app_client" ]; then # 前端比较特殊无需用supervisor守护
# 检测日志存储目录是否存在
if [ ! -d "./app_logs/${service}" ]; then
mkdir "./app_logs/${service}"
fi
supervisorctl start "$service"
fi
}
update_services
我要的是实现思路吗?我要的是Ctrl+C,Ctrl+V就能用的脚本
拿来吧你~
网友评论