Appearance
待办
概述
CI概述
CI(Continuous Integration)
集成软件的过程不是新问题。在一个人开发的项目中,依赖外部系统又比较少的话,软件集成不会成为太大的问题,但是随着项目复杂度的增加(即使只增加一个人), 就会对集成和确保软件组件能够一起工作提出更多的要求一一要早集成,常集成。等到项目快结束时才来集成会导致各种各样的软件品质问题,解决这些问题代价很大,常常会导致项目延期。 CI以较小增量的方式迅速地解决这些风险。
在Martin Fowler热门的文章《Continuous Integration》(持续集成)中,他将CI描述为:
一种软件开发实践,即因队的成员经常集成他们的工作,通常每个成员每天至少集成一次一一这导致每天发生多次集成。每次集成都通过自动化的构建(包括测试)来验证,从而尽快地检测出集成错误。许多团队发现这个过程会大大减少集成问题,让团队能够更快地开发内聚的软件。
https://www.martinfowler.com/articles/continuousIntegration.html
根据我的经验,这意味着:
- 所有开发者都先要在他们自己的工作站上执行私有构建,然后再将他们的代码提交到版本控制库中,从而确保他们的变更不会导致集成构建失败。
- 开发者每天至少向版本控制库提交一次代码。
- 集成构建每天在一台独立的计算机上进行多次。
- 每次构建都必须100%通过测试。
- 生成可以进行功能测试的产品(如WAR、配件、可执行程序等)。
- 修复失败的构建是优先级最高的事情。
- 某些开发者复查构建生成的报告,如编码标准报告和依赖分析报告,寻找可以改进的地方。
CD概述
CD(Continuous Delivery)
至少对开发团队来说,该方法的基础是持续集成(CI)。CI使整个开发团队保持同步,消除了集成问题引起的延期。在几年前,Paul Duvall写了一本关于CI的书。但CI只是第一步。软件即使被成功地集成到了代码主干上,也仍旧是没有在生产环境中发挥作用的软件。David和Jez的书对从CI至"最后一公里"的问题进行了阐述,描述了如何构建部署流水线,才能将已集成的代码转变为已经部署到生产环境中的软件。
这种交付思想长期以来一直是软件开发中被人遗忘的角落,是开发人员和运维团队之间的一个黑洞。因此毫无疑问的是,本书中的技术都依赖于这些团队的凝聚,而这也就是悄然兴起的DevOps运动的前兆。这个过程也包括测试人员,因为测试工作也是确保无差错发布的关键因素。贯穿一切的是高度自动化,让事情能够很快完成而且没有差错。
Jenkins概述
Jenkins是一款流行的开源持续集成(Continuous Integration)与持续部署(Continuous Delivery)工具,广泛用于项目开发,具有自动化构建、测试和部署等功能。
Jenkins的特征:
- 开源的Java语言开发持续集成工具,支持持续集成,持续部署。
- 易于安装部署配置:可通过yum安装,或下载war包以及通过docker容器等快速实现安装部署,可方便web界面配置管理。
- 消息通知及测试报告:集成RSS/E-mail通过RSS发布构建结果或当构建完成时通过e-mail通知,生成JUnit/TestNG测试报告。
- 分布式构建:支持Jenkins能够让多台计算机一起构建/测试。
- 文件识别:Jenkins能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等。
- 丰富的插件支持:支持扩展插件,你可以开发适合自己团队使用的工具,如git,svn,maven,docker等。
Jenkins入门
Jenkins安装
docker-compose.yml
ymlversion: '3.9' services: jenkins: restart: always image: jenkins/jenkins:2.346.1-lts container_name: jenkins hostname: jenkins environment: TZ: 'Asia/Shanghai' # ports: # - '8080:8080' # - '50000:50000' volumes: - './jenkins_home:/var/jenkins_home' networks: default: external: true name: global
log
texjenkins | Running from: /usr/share/jenkins/jenkins.war jenkins | webroot: EnvVars.masterEnvVars.get("JENKINS_HOME") jenkins | 2021-06-15 03:49:00.234+0000 [id=1] INFO org.eclipse.jetty.util.log.Log#initialized: Logging initialized @568ms to org.eclipse.jetty.util.log.JavaUtilLog jenkins | 2021-06-15 03:49:00.452+0000 [id=1] INFO winstone.Logger#logInternal: Beginning extraction from war file jenkins | 2021-06-15 03:49:23.373+0000 [id=1] WARNING o.e.j.s.handler.ContextHandler#setContextPath: Empty contextPath jenkins | 2021-06-15 03:49:23.523+0000 [id=1] INFO org.eclipse.jetty.server.Server#doStart: jetty-9.4.38.v20210224; built: 2021-02-24T20:25:07.675Z; git: 288f3cc74549e8a913bf363250b0744f2695b8e6; jvm 1.8.0_282-b08 jenkins | 2021-06-15 03:49:24.731+0000 [id=1] INFO o.e.j.w.StandardDescriptorProcessor#visitServlet: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet jenkins | 2021-06-15 03:49:24.961+0000 [id=1] INFO o.e.j.s.s.DefaultSessionIdManager#doStart: DefaultSessionIdManager workerName=node0 jenkins | 2021-06-15 03:49:24.961+0000 [id=1] INFO o.e.j.s.s.DefaultSessionIdManager#doStart: No SessionScavenger set, using defaults jenkins | 2021-06-15 03:49:24.964+0000 [id=1] INFO o.e.j.server.session.HouseKeeper#startScavenging: node0 Scavenging every 600000ms jenkins | 2021-06-15 03:49:27.405+0000 [id=1] INFO hudson.WebAppMain#contextInitialized: Jenkins home directory: /var/jenkins_home found at: EnvVars.masterEnvVars.get("JENKINS_HOME") jenkins | 2021-06-15 03:49:28.154+0000 [id=1] INFO o.e.j.s.handler.ContextHandler#doStart: Started w.@600b0b7{Jenkins v2.277.1,/,file:///var/jenkins_home/war/,AVAILABLE}{/var/jenkins_home/war} jenkins | 2021-06-15 03:49:28.271+0000 [id=1] INFO o.e.j.server.AbstractConnector#doStart: Started ServerConnector@58e1d9d{HTTP/1.1, (http/1.1)}{0.0.0.0:8080} jenkins | 2021-06-15 03:49:28.271+0000 [id=1] INFO org.eclipse.jetty.server.Server#doStart: Started @28641ms jenkins | 2021-06-15 03:49:28.273+0000 [id=21] INFO winstone.Logger#logInternal: Winstone Servlet Engine running: controlPort=disabled jenkins | 2021-06-15 03:49:30.726+0000 [id=28] INFO jenkins.InitReactorRunner$1#onAttained: Started initialization jenkins | 2021-06-15 03:49:30.879+0000 [id=26] INFO jenkins.InitReactorRunner$1#onAttained: Listed all plugins jenkins | 2021-06-15 03:49:35.480+0000 [id=26] INFO jenkins.InitReactorRunner$1#onAttained: Prepared all plugins jenkins | 2021-06-15 03:49:35.515+0000 [id=29] INFO jenkins.InitReactorRunner$1#onAttained: Started all plugins jenkins | 2021-06-15 03:49:35.541+0000 [id=29] INFO jenkins.InitReactorRunner$1#onAttained: Augmented all extensions jenkins | 2021-06-15 03:49:37.175+0000 [id=29] INFO jenkins.InitReactorRunner$1#onAttained: System config loaded jenkins | 2021-06-15 03:49:37.176+0000 [id=27] INFO jenkins.InitReactorRunner$1#onAttained: System config adapted jenkins | 2021-06-15 03:49:37.177+0000 [id=27] INFO jenkins.InitReactorRunner$1#onAttained: Loaded all jobs jenkins | 2021-06-15 03:49:37.179+0000 [id=27] INFO jenkins.InitReactorRunner$1#onAttained: Configuration for all jobs updated jenkins | 2021-06-15 03:49:37.234+0000 [id=42] INFO hudson.model.AsyncPeriodicWork#lambda$doRun$0: Started Download metadata jenkins | 2021-06-15 03:49:37.371+0000 [id=42] INFO hudson.util.Retrier#start: Attempt #1 to do the action check updates server jenkins | 2021-06-15 03:49:39.844+0000 [id=26] INFO jenkins.install.SetupWizard#init: jenkins | jenkins | ************************************************************* jenkins | ************************************************************* jenkins | ************************************************************* jenkins | jenkins | Jenkins initial setup is required. An admin user has been created and a password generated. jenkins | Please use the following password to proceed to installation: jenkins | jenkins | 10d16e7151dd4c1eb9f0786a4163544f jenkins | jenkins | This may also be found at: /var/jenkins_home/secrets/initialAdminPassword jenkins | jenkins | ************************************************************* jenkins | ************************************************************* jenkins | ************************************************************* jenkins | jenkins | 2021-06-15 03:50:35.018+0000 [id=27] INFO jenkins.InitReactorRunner$1#onAttained: Completed initialization jenkins | 2021-06-15 03:50:35.085+0000 [id=20] INFO hudson.WebAppMain$3#run: Jenkins is fully up and running
改密码
插件管理
修改Jenkins插件下载地址
jenkins
->Manage Jenkins
->Manage Plugins
->Avaiable
这样做的目的,是为了把Jenkins官方的插件列表下载到本地,接着修改地址文件,替换为国内插件地址
主机
->编辑
->jenkins_home/updates/default.json
bashsed 's~https://updates.jenkins.io/download~https://mirrors.tuna.tsinghua.edu.cn/jenkins~g' /var/jenkins_home/updates/default.json -i sed 's~http://www.google.com/~https://www.baidu.com~g' /var/jenkins_home/updates/default.json -i
jenkins
->Manage Jenkins
->Manage Plugins
->Advanced
->Update Site
texhttps://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
jenkins
->地址栏
texhttp://localhost:18080/restart
安装插件
搜索插件
jenkins
->Manage Jenkins
->Manage Plugins
->Available
- 搜索勾选
Role-based Authorization Strategy
- 搜索勾选
Build Authorization Token Root Plugin
- 搜索勾选
Credentials Binding
- 搜索勾选
Localization: Chinese (Simplified)
搜索勾选Deploy to container
搜索勾选Maven Integration
搜索勾选Pipeline
搜索勾选Gitlab Hook
搜索勾选Email Extension Template
搜索勾选SonarQube Scanner
搜索勾选Publish Over SSH
搜索勾选NodeJS
搜索勾选Extended Choice Parameter
- 搜索勾选
安装插件
Install without restart
授权管理
Jenkins
->Manage Jenkins
->Security
->Configure Global Security
->Authorization
选择
Role-Based Strategy
配置角色
Jenkins
->Manage Jenkins
->Security
->Manage and Assign Roles
- Global roles
- 创建base角色,指定
overall-read
权限
管理员等高级用户可以创建基于全局的角色 Project roles(项目角色)
针对某个或者某些项目的角色 Slave roles(奴隶角色):节点相关的权限
- Item roles
- 创建
api
角色,指定模式api-.*
,指定权限全部勾选 - 创建
common
角色,指定模式common-.*
,指定权限全部勾选
配置用户
Jenkins
->Manage Jenkins
->Security
->Manage Users
->Create User
- 创建jack用户
- 创建eric用户
分配角色
Jenkins
->Manage Jenkins
->Security
->Manage and Assign Roles
- Global roles
- 添加jack用户,指定
base
角色 - 添加eric用户,指定
base
角色
- Item roles
- 为jack分配api权限
- 为eric分配common权限
创建项目
Jenkins
->New Item
- 创建
api-future-weaver
项目,指定Freestyle project
类型 - 创建
common-future-weaver
项目,指定Freestyle project
类型
- 创建
测试角色
登录jack用户,查看权限
登录eric用户,查看权限
创建 admin api token
凭据管理
添加凭据
Jenkins
->Manage Jenkins
->Manage Credentials
->global
->添加凭据
可以添加的凭证有5种
Username with password
用户名和密码
SSH Username with private key
使用SSH用户和密钥
Secret file
需要保密的文本文件,使用时Jenkins会将文件复制到一个临时目录中,再将文件路径 设置到一个变量中,等构建结束后,所复制的Secret file就会被删除。
Secret text
需要保存的一个加密的文本串,如钉钉机器人或Github的api token
Certificate
通过上传证书文件的方式
配置 Jenkins 项目使用凭据
Jenkins
->New Item
- 创建
gitlab-test
项目,指定Freestyle project
类型
Source Code Management
->填写git地址
->选择凭据
- 创建
构建项目
Build Now
,查看输出结果
Maven整合
Jenkins 全局工具配置
Jenkins
->Manage Jenkins
->System Configure
->Global Tool Configuration
->Maven
->Add Maven
Name
apache-maven-3.8.1
MAVEN_HOME
/usr/local/apache-maven-3.8.1
Jenkins 系统环境变量配置
Jenkins
->Manage Jenkins
->System Configure
->Configure System
->Global properties
->environment variables
->Add
- 添加
M2_HOME
环境变量
Name
M2_HOME
Value
/usr/local/apache-maven-3.8.1
- 添加
PATH+EXTRA
环境变量
Name
PATH+EXTRA
Value
$M2_HOME/bin
- 添加
配置 Jenkins 项目整合 maven
Jenkins
->New Item
- 创建
maven-test
项目,指定Freestyle project
类型
Build
->Add build step
->Execute shell
shellmvn -version
- 创建
构建项目
Build Now
,查看输出结果
Tomcat整合
Tomcat配置
$CATALINA_HOME/conf/tomcat-users.xml
xml<tomcat-users> <role rolename="tomcat"/> <role rolename="role1"/> <role rolename="manager-script"/> <role rolename="manager-gui"/> <role rolename="manager-status"/> <role rolename="admin-gui"/> <role rolename="admin-script"/> <user username="tomcat" password="tomcat" roles="manager-gui,manager-script,tomcat,admin-gui,admin-script"/> </tomcat-users
$CATALINA_HOME/webapps/manager/META-INF/context.xml
注释掉以下配置
xml<!-- <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" /> -->
重启 Tomcat
bashshutdown.sh startup.sh
测试用户权限
登录
http://localhost:8080/manager/html
自动化部署
Jenkins 建立 Pipeline 项目
groovypipeline { agent any stages { stage('拉取代码') { steps { checkout([ $class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[ credentialsId: 'gitlab-rainbow-weaver-auth-passsword', url:'git@192.168.66.100:future-weaver_group/web_demo.git' ]] ]) } } stage('编译构建') { steps { sh label: '', script: 'mvn clean package' } } stage('项目部署') { steps { deploy adapters: [ tomcat8( credentialsId: '', path: 'tomcat-auth-password', url: 'http://tomcat:8080' ) ], contextPath: null, war: 'target/*.war' } } } }
Jenkins深入
Jenkins作业
Jenkins触发器
为jenkins容器安装expect命令
shell
docker exec -it -u root jenkins bash
apt-get clean
apt-get update
apt-get install expect
Build Triggers配置
勾选
Trigger builds remotely
选项
Authentication Token
填写admin api token
Build配置
选择Execute Shell
shell
expect -c '
spawn ssh root@centos8
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" {send "root\r" }
}
expect "#" { send "date >> /date.log\r" }
expect "#" { send "exit\r" }
expect eof'
测试远程触发构建
http://localhost:18080/buildByToken/build?job=api-future-weaver&token=11154ee0d840e41dc9e10841cae2395ff4