通知与报告
通知
电子邮件
基本电子邮件
在系统配置中配置,Jenkins Location,配置url和管理员邮箱;E-mail Notification
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# 脚本式 node('node1'){ try{ ... currentBuild.result='SUCCESS' } catch(err){ currentBuild.result='FAILURE' } finally{ mail to:'xxx@xxx.com', subject:"Status of pipeline:${currentBuild.fullDisplayName}", body:"${env.BUILD_URL} has result ${currentBuild.result}" } } # 声明式 pipeline{ agent any stages{ ... } post{ always{ mail to:'xxx@xxx.com', subject:"Status of pipeline:${currentBuild.fullDisplayName}", body:"${env.BUILD_URL} has result ${currentBuild.result}" } } } |
扩展电子邮件
电子邮件扩展插件 Extension Email plugin , email-ext
增加了对内容/收件人/触发器(注触发器现在不适用于流水线)的支持
全局配置:Extended E-mail Notification
Emergency reroute,所有jenkins邮件都会发给指定的收件人
${currentBuild.result?:'SUCCESS'} 检查result是否为NULL,若是,则赋值为SUCCESS;在jenkins中,构建结果的NULL值表示成功
协作服务
Slack通知
Slack通知插件 Slack Notification plugin
HipChat通知
HipChat通知插件 HipChat Notification plugin
报告
报告通常有代码分析、代码覆盖率、单元测试报告等
HTML报告
HTML发布者插件 HTML Publisher plugin 允许在流水线中添加一个步骤来指向HTML报告(通常出现在左边栏中),并提供长时间保存报告等功能
# Gradle执行完单元测试后会创建一个名为index.html的报告 位于 <component>/build/reports/test 中
# 若需要添加此index.html报告,则可以:
1 2 3 4 5 6 7 8 |
publishHTML(target:[ allowMissing: false, alwaysLinkToLastBuild, false, keepAll: true, reportDir: 'api/build/reports/test', reportFiles: 'index.html', reportName: 'API Unit Testing Results' ]) |
allowMissing,当为false时,报告缺失会导致构建失败
alwaysLinkToLastBuild,当为true时,若当前构建失败,会显示上次成功构建时的报告链接
keepAll,为true时,会将成功构建的报告归档,否则只归档最近成功构建的报告
reportName,在任务界面界面上看到的链接名称
访问与安全
安全加固jenkins
jenkins2默认启用安全性
Manage Jenkins > Configure Global Security
Enable security开启后,可在身份验证和授权两个维度配置安全性
Security Realm 安全域
1、servlet容器代理,jetty或tomcat,通过容器支持的任何机制来进行身份验证
2、jenkins专有用户数据库,jenkins自己的帐号系统,若开启注册功能,可接受新注册的用户
3、LDAP,可以添加一个以上的ldap服务器,每个服务器都可以有不同的配置
4、UNIX用户/组数据库,需要额外的配置,如把jenins设置成shadow组的成员,以便操作系统可以访问和使用它
访问控制,授权
1、Legacy mode ,只区分管理员和只读用户
2、安全矩阵,权限/用户(组)的二维矩阵
3、项目矩阵授权策略,为每个项目的配置页添加一个安全矩阵(Enable project-based security)
其他全局安全配置
Markup Formatter,Safe HTML
Agents,JNLP进程启动代理可以绑定一个固定的端口
Plugin Manager,应该不勾选Use browser for metadata download
Hidden security warnings,与从已安装组件的更新站点获取安全警告有关,可以选择显示哪些警告,仅展示被勾选的警告
授权项目插件 Authorize Project plugin,允许使用指定的权限运行构建,会在每个任务中添加一个授权项,Authorization(左边栏)
Jenkins中的凭证
凭证插件 Credentials plugin 包含在jenkins安装中,提供对凭证的创建和管理机制,同时也为其他插件提供存储和访问凭证的api
凭证:用户名和密码、Docker凭证目录、Docker主机凭证验证、SSH用户名和私钥、机密zip文件、机密文件、机密文本等
凭证存储在 JENKINS_HOME/secrets 是加密的
凭证的范围
表示如何才能被暴露的方式,分为系统、全局、用户
系统即jenkins系统本身,只暴露给系统和后台任务,一般用于连接到节点的认证
全局,jenkins中的任务能够使用的凭证
用户,只有当jenkins中的线程作为该用户进行身份验证时,凭证才可以使用
凭证域
一个域名和一个规范,只有满足该规范才能访问到这个域
默认有全局域
凭证提供者
存储和获取凭证的地方,如内部凭证存储
系统凭证提供者:在根上下文中暴露凭证,可用于系统和全局 jenkins -> credentials
管理凭证
提供者Providers -> 类型Types ->限制Restrictions
授权项目插件 Authorize Project plugin,对于构建任务,可以限制使用哪些凭证,防止高级别的凭证被恶意使用
创建和管理凭证
Credentials表格:T 类型,P 提供者,Store 存储,Domain 域,ID,Name
置灰的凭证表示该凭证来自于父上下文
下一个表格列出当前上下文中可用的凭证存储
表的底部列出了在父上下文中可用的凭证存储
创建规范specification后,当选择凭证并输入一个与模式匹配的相关值时,来自该域的凭证会作为选项进行呈现
若不提供规范,该域等效于全局域
创建凭证时,指定一个有意义的ID非常有必要,否则会使用随机ID;而描述在选择凭证时,会非常有用
基于角色的访问权限
基于角色的授权策略插件 Role-based Authorization Strategy plugin
插件允许定义三种角色:全局角色、项目角色、从节点角色
在全局安全设置中选择:Role-Based Strategy ,然后在管理页面会新出现一个选项:Manage and Assign Roles 管理和分配角色,这是该插件的功能入口
三个选项:管理角色、分配角色、角色策略宏
管理角色 Manage Roles
创建和管理角色并分配权限
角色模式是一种正则表达式,Daily-* 是区分大小写的 (?!)Daily-* 不区分大小写
分配角色 Assign Roles
横线,表示这个用户/组不存在或者不合法
身份验证组,对任何可以登录的人,是一个内置组
角色策略宏 Role Strategy Macros
根据项目的某些特性定义访问权限的宏,如 BuildableJob,授予该角色的用户将只能访问可构建的任务(任务被禁用)
角色策略宏是区分全局、项目、从节点的,使用时,需要在角色中添加,添加时加 @前缀
在流水线中使用凭证
需要安装有 凭证绑定插件 Credential Binding plugin
用户名密码
withCredentials([usernamePassword(withCredentialsId:'<ID>',
passwordVariable:'<var to hold password>',
usernameVariable:'<var to hold username>')])
SSH密钥
withCredentials([sshUserPrivateKey(withCredentialsId:'ID',
keyFileVariable:'MYFILE',
passphraseVariable:'PASSPHRASE',
usernameVariable:'USERNAME')]){
// 代码块
}
也可以使用sshagent代码块 需SSH代理插件 SSH agent plugin
sshagent([ID]){
// 代码块
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
node{ def sshRepodef="git@xxx.xxx/xxx.git" stage('Get Source'){ git url:sshRepodef } stage('Add Tag'){ sh "git config user.name xxx" sh "git config user.email xxx@xxx" sshagent(['xxxxxx']){ sh "git tag -a ${env.BUILD_TAG} -m 'demostrate push of tags'" sh "git push ${sshRepodef} --tags" } } } |
令牌凭证
1 2 3 4 5 6 7 8 9 10 |
node{ withCredentials([string(withCredentialsId:'<token>',variable:'TOKEN')]) { sh ''' set +x curl -H "Token: $TOKEN" https://xxx/ ''' } } # 脚本调试 set -x是开启 set +x是关闭 |
控制脚本安全性
脚本安全性由 脚本安全插件 Script Security plugin 提供
两种机制:脚本批准和Groovy沙箱
脚本检查
管理员创建或配置的脚本会自动添加到已批准列表中,被批准的脚本可由任何人运行
非管理员运行一个未在已批准列表中的脚本,它将禁止运行直到获得批准
脚本批准
位于 In-process Script Approval
Groovy沙箱
Jenkins维护一个白名单方法集,这些方法被认为在任何脚本中都是安全的
若脚本只使用了白名单中的方法,则允许脚本在未经批准的情况下运行
jenkins凭证与Vault配合使用
Vault是管理密钥的工具,可以作为jenkins身份验证的外部凭证存储
身份验证使用的方式是 AppRole
略
扩展流水线
共享流水线库,由存储在代码仓库中的代码组成,该代码库由jenkins自动下载并可供流水线使用
可信库和不可信库
根级别的库是全局的可信的,用于特定任务集(如文件夹)的库是不可信的
内部库,jenkins2包含一个内部git仓库,可用于存储内部库,放置于该库的脚本被认为是可信的
workflowLibs.git
内部库的访问方法:
1、SSH
在全局安全中启用SSH Server 并指定一个较大的端口
在http://<jenkins>/user/<userid>/configure添加ssh公钥
git clone ssh://<userid>@<system-name>:<port>/workflowLibs.git
2、HTTP
git clone http://<system-name>:<port>/workflowLibs.git
#git clone http://<system-name>:<port>/jenkins/workflowLibs.git
若使用http方式时遇到403等问题,需要保证处于登录状态,并且临时关闭CRSF
默认克隆下来的仓库是空的,若要使用,需要新建一个新的主分支
cd workflowLibs
git chechout -b master
外部库
在 configuration -> Global Pipeline Libraries 中添加
Default Version 可以是分支或标签
Load implicitly 隐式加载,允许用户自动加载外部库
Allow default version to be overridden 覆盖默认版本,使用注解的方式,如 @Library('libname@version')_
加载库到脚本中
如果有内容,workflowLibs的全局内部库将会被自动加载
使用隐式加载复选项可以指定用于流水线的外部库自动加载
导入方法集合
import static org.demo.Utilities.*
若不使用自动加载,则需要显式加载外部库
1、@Library 注解
@Library('<libname>[@<version>)]')_ [<import statement>]
其中,版本需以@开头,可以是标签、分支名或其他规范
可以在注解的末尾或下一行包含 import 语句,以导入特定的方法了集
不指定 import 则导入全部方法,但必须在注解末尾添加下划线 _
可在同一注解中指定多个库名称,以逗号分隔
注意:注解需要放在脚本开头,脚本式的node行上方,声明式的pipeline行上方(声明式使用注解不是一个很好的方式)
# 加载默认版本
@Library('myLib')_
# 加载指定版本
@Library('myLib@2.0')_
# 加载多个库
@Library(['myLib','oneLib@master'])_
# 带导入语句
@Library('myLib@1.0') import static org.demo.Utilities.*
2、库步骤
library "<libname>[@<version>]"
可放在流水线的任何位置
可使用变量替换参数,如 library "<libname>@${BRANCH_NAME}"
3、库指令
仅可用于声明式流水线,使用libraries指令
1 2 3 4 5 6 7 8 9 10 |
pipeline{ agent any libraries{ lib("myLib@master") lib("alib") } stages{ ... } } |
jenkins项目中的库范围
除了全局共享库,还有文件夹、多分支流水线等级别的库,即本地作用域共享库
本地作用域共享库被认为是不可信的需要在groovy沙箱中运行
1 2 3 4 5 6 7 8 9 10 11 12 |
# 样本例程 timestamps{ gradle <tasks> } def commandOutput timestamps{ commandOutput=sh(script:"${<command-to-run>}, returnStdout:true).trim() } echo commandOutput # trim() 可以使输出更清晰 |
库结构
共享库代码结构:
-src
-vars
-resources
src
使用标准java目录结构的groovy文件,当执行流水线时,将被添加到类路径中,eg src/org/foo/bar.groovy
任何groovy代码均可在此使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# 示例: // org.demo.buildUtils package org.demo def timedGradldBuild(tasks){ timestamps{ sh "${tool 'gradle3.2'}/bin/gradle ${tasks}" } } # 在流水线中可这样调用: def myUtils=new org.demo.buildUtils() git "<url>" myUtils.timedGradldBuild("clean build") # 示例: # 创建一个封闭类,然后在类的构建函数或方法中通过将steps对象传递给一个方法来获取访问所有DSL步骤的权限 // org.demo.buildUtils package org.demo class buildUtils implements Serializable{ def steps buildUtils(steps){ this.steps=steps} def timedGradldBuild(tasks){ def gradleHome=steps.tool 'gradle3.2' steps.timestamps{ steps.sh "$gradleHome}/bin/gradle ${tasks} } } } # 在流水线中调用: @Library('bldtools') import org.conf.buildUtils.* def bldtools=new buildUtils(steps) node{ git "url" bldtools.timedGradldBuild 'clean build' } |
vars
此区域用于托管脚本,这些脚本定义了变量并关联了想要在流水线中使用的方法
xxx.groovy xxx.txt(若有,为xxx.groovy的说明文档,支持markdown和html语法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# 示例: // vars/timedCommand.groovy def setCommand(commandToRun){ cmd=commandToRun } def getCommand(){ cmd } def runCommand(){ timestamps{ cmdOut=sh(script:"${cmd}",returnStdout:true).trim() } } def getOutput(){ cmdOut } # 在流水线中使用: node{ timedCommand.cmd='ls -la' echo timedCommand.cmd timedCommand.runCommand echo timedCommand.getOutput } |
可以像使用步骤一样使用全局变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// vars/timedCommand2 def call(String cmd,String logFilePath){ timestamps{ cmdOut=echo sh (script:"${cmd},returnStdout:true).trim() } echo cmdOut writeFile file:"${logFilePath}",text:"${cmdOutput}" } # 在流水线中调用: timedCommand2 'ls -la','listing.log' // vars/timedCommand3 def call(Closure commands){ timestamps{ commands() } } # 在流水线中调用: timedCommand3{ def content=readFile file:'<path to huge datafile>' sh "<some processing on content>" writeFile file:'path to file',text:content echo "Done" } |
resources
非groovy文件可存储在此目录,可通过外部库中的libraryResource步骤加载
def datafile=libraryResource 'org/conf/data/lib/datafile.ext'
加载sh脚本
def myExternalScript=libraryResource 'myexternal.sh'
sh myLatestScript
使用第三方库
共享库可以通过@Grab注解使用第三方库
直接加载代码
可以通过load直接加载代码,这将直接从磁盘位置读取,而不依赖于源码仓库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 示例: def call(String cmd,String logFilePath){ timestamps{ cmdOut=echo sh (script:"${cmd},returnStdout:true).trim() } echo cmdOut writeFile file:"${logFilePath}",text:"${cmdOutput}" } return this; # 在流水线中使用: node{ def myProc=load '/home/xxx/xxx.groovy' myProc 'ls -la','command.log' } |
从外部SCM加载代码
需要 流水线远程加载器插件 Pipeline Remote Loader plugin (Global Variable Reference)
该插件提供fileLoader DSL函数,用于从git/github/svn中加载代码
1 2 3 4 |
# 示例: def timestampProc=fileLoader.fromGit('jenkins/pipeline/timedCommand', 'https://github.com/xxxx/xxx.git','master',null,'') timestampProc.timedCommand("ls -la","command.log") |
可以使用回放功能调试通过load或fileLoader加载的库
转载请注明:轻风博客 » Jenkins2权威指南2-通知/报告/安全/共享流水线库