Jenkins服务

一、Jenkins基础

Jenkins官方网站

1. 概述

Jenkins是一款基于Java开发的CI(持续集成)和CD(持续部署)平台。

Jenkins无需数据库支持,服务的存储是基于xml文件的方式。

2. Jenkins主要文件

  • /etc/init.d/jenkins - 服务启动/停止脚本
  • /etc/logrotate.d/jenkins - 服务日志切割脚本
  • /etc/sysconfig/jenkins - 服务主配置文件
  • /usr/lib/jenkins/jenkins.war - 替换相应war包,升级Jenkins版本
  • /usr/sbin/rcjenkins - 服务重启脚本(为/etc/init.d/jenkins文件的软连接)
  • /var/cache/jenkins - 服务缓存目录
  • /var/lib/jenkins - 服务工作目录
  • /var/log/jenkins - 服务日志目录
[root@jenkins ~]# rpm -ql jenkins
/etc/init.d/jenkins
/etc/logrotate.d/jenkins
/etc/sysconfig/jenkins
/usr/lib/jenkins
/usr/lib/jenkins/jenkins.war
/usr/sbin/rcjenkins
/var/cache/jenkins
/var/lib/jenkins
/var/log/jenkins

3. Jenkins安装

离线安装包
提取码:17tu

安装方式

  • YUM安装
  • war安装
  • 容器安装(docker)

使用Tomcat 8.0及以上直接运行war包时,请注意修改 /安装目录/bin/catalina.sh 文件中的 UMASK ;
if [ -z "$UMASK" ]; then
    UMASK="0022"
fi

step 01 安装Java

yum install -y java
[root@jenkins ~]# yum install java -y
Loaded plugins: fastestmirror
Determining fastest mirrors
......
  xorg-x11-font-utils.x86_64 1:7.5-21.el7 
  xorg-x11-fonts-Type1.noarch 0:7.5-9.el7

Complete!

step 02 安装Jenkins

yum localinstall -y jenkins-*.rpm
[root@jenkins ~]# cd /tmp/
[root@jenkins /tmp]# rz -E
rz waiting to receive.
[root@jenkins /tmp]# ls
jenkins-2.176.1-1.1.noarch.rpm  jenkins_plugins_new.tar.gz
[root@jenkins /tmp]# yum localinstall jenkins-2.176.1-1.1.noarch.rpm -y
Loaded plugins: fastestmirror
Examining jenkins-2.176.1-1.1.noarch.rpm: jenkins-2.176.1-1.1.noarch
Marking jenkins-2.176.1-1.1.noarch.rpm to be installed
......
Installed:
  jenkins.noarch 0:2.176.1-1.1
Complete!

step 03 修改配置文件

# /etc/sysconfig/jenkins
JENKINS_HOME="工作目录" #指定Jenkins服务的工作目录
JENKINS_USER="用户名" #指定Jenkins服务进程的运行用户
JENKINS_JAVA_OPTIONS=" - Djava.awt.headless=true" #Jenkins服务的Java启动参数(保持默认)
JENKINS_PORT="端口" #指定Jenkins运行端口(默认8080)
JENKINS_LISTEN_ADDRESS="" #指定Jenkins监听地址(默认监听0.0.0.0)
[root@jenkins ~]# grep -Ev '^$|^#' /etc/sysconfig/jenkins 
JENKINS_HOME="/var/lib/jenkins"
JENKINS_JAVA_CMD=""
JENKINS_USER="jenkins"
JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true"
JENKINS_PORT="8080"
JENKINS_LISTEN_ADDRESS=""
JENKINS_HTTPS_PORT=""
JENKINS_HTTPS_KEYSTORE=""
JENKINS_HTTPS_KEYSTORE_PASSWORD=""
JENKINS_HTTPS_LISTEN_ADDRESS=""
JENKINS_DEBUG_LEVEL="5"
JENKINS_ENABLE_ACCESS_LOG="no"
JENKINS_HANDLER_MAX="100"
JENKINS_HANDLER_IDLE="20"
JENKINS_ARGS=""

step 04 启动Jenkins

systemctl start jenkins
systemctl enable jenkins
[root@jenkins ~]# systemctl enable jenkins 
jenkins.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig jenkins on
[root@jenkins ~]# systemctl start  jenkins 

step 05 访问Jenkins

netstat -lntup
[root@jenkins ~]# netstat -lntup| grep 8080
tcp6       0      0 :::8080                 :::*                    LISTEN      8301/java 

step 06 解锁Jenkins

cat /var/lib/jenkins/secrets/initialAdminPassword
[root@jenkins ~]# cat /var/lib/jenkins/secrets/initialAdminPassword
c59cf575b9354c639aa5d5ba89ff9f81

step 07 配置Jenkins

step 08 修改管理员密码

在未配置admin账户的情况下,请使用初始(解锁)密码,登录admin账户。

4. Jenkins插件安装

Jenkins插件网站

插件安装方式:
1. 在线安装 - 加速安装插件(替换安装源)
jenkins插件下载加速最终方案[转自vasks博客]
2. 本地安装 - 上传一个插件(支持.hpi文件)
3. 导入插件 - 将其他服务器jenkins服务的插件包导入到指定插件目录
在Jenkins服务中,新安装的插件可直接使用,但是已安装的插件升级,需要重启Jenkins服务。

本文以方式3为例,安装插件

step 01 停止jenkins服务

systemctl stop jenkins
[root@jenkins ~]# systemctl stop jenkins.service 

step 02 解压导入插件

Jenkins插件目录: /var/lib/jenkins/plugins/
tar xf jenkins_*_plugins.tar.gz
\cp -rp plugins/* /var/lib/jenkins/plugins/
[root@jenkins ~]# cd /tmp/
[root@jenkins /tmp]# tar xf jenkins_plugins_new.tar.gz 
[root@jenkins /tmp]# ls -d plugins/
plugins/
[root@jenkins /tmp]# \cp -rp plugins/* /var/lib/jenkins/plugins/
[root@jenkins /tmp]# ll /var/lib/jenkins/plugins/ | head -3 
total 134684
drwxr-xr-x 7 jenkins jenkins      124 Aug 19  2019 ace-editor
-rw-r--r-- 1 jenkins jenkins  4279042 Aug 19  2019 ace-editor.jpi

step 03 授权插件文件

因为Jenkins服务是由Jenkins用户运行起来的;
chown -R jenkins.jenkins /var/lib/jenkins/plugins/
[root@jenkins /tmp]# chown -R jenkins.jenkins /var/lib/jenkins/plugins/

step 04 启动jenkins服务

systemctl start jenkins
[root@jenkins /tmp]# systemctl start jenkins
[root@jenkins /tmp]# tail -f /var/log/jenkins/jenkins.log 
......
INFO: Obtained the updated data file for hudson.tools.JDKInstaller
Feb 22, 2021 3:57:56 PM hudson.model.AsyncPeriodicWork$1 run
INFO: Finished Download metadata. 7,438 ms

step 05 隐藏Jenkins警告

step 06 Jenkins汉化

Jenkins服务默认不支持中文,需要借助插件实现汉化;

step 07 更改jenkins运行用户(建议学习期间以root运行)

[root@jenkins ~]# ps aux | grep [j]enkins
jenkins    7451  0.4 27.6 2732732 560492 ?      Ssl  08:49   1:45 /etc/alternatives/java -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true -DJENKINS_HOME=/var/lib/jenkins -jar /usr/lib/jenkins/jenkins.war --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war --daemon --httpPort=8080 --debug=5 --handlerCountMax=100 --handlerCountMaxIdle=20
[root@jenkins ~]# grep JENKINS_USER /etc/sysconfig/jenkins 
JENKINS_USER="root"
[root@jenkins ~]# systemctl restart jenkins
[root@jenkins ~]# ps aux | grep [j]enkins
root       9145 94.5 14.5 2637048 294552 ?      Ssl  15:39   0:17 /etc/alternatives/java -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true -DJENKINS_HOME=/var/lib/jenkins -jar /usr/lib/jenkins/jenkins.war --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war --daemon --httpPort=8080 --debug=5 --handlerCountMax=100 --handlerCountMaxIdle=20

二、Jenkins与Gitlab集成

1. Jenkins部署HTML

step 00 准备web集群环境

Web集群搭建步骤详见基于Nginx的Web服务章节

# load balance
[root@lb01 ~]# cat /etc/nginx/conf.d/jenkins_test_proxy.conf 
upstream aspen {
    server 172.16.1.17:80;
    server 172.16.1.18:80;
}
server {
    listen 80;
    server_name html.aspen.com;
    location / {
        proxy_pass http://aspen;
        proxy_set_header Host $http_host;
    }
}
[root@lb01 ~]# systemctl restart nginx
# web 01
[root@web01 ~]# cat /etc/nginx/conf.d/jenkins_test_html.conf 
server {
       listen 80;
       server_name html.aspen.com;
       location / {
                root /html;
                index index.html;
       }
}
[root@web01 /html]# systemctl restart nginx
[root@web01 ~]# echo "Web01 based on nginx" > /html/index.html
# web 02
root@web02 ~]# cat /etc/nginx/conf.d/jenkins_test_html.conf 
server {
       listen 80;
       server_name html.aspen.com;
       location / {
            root /html;
            index index.html;
       }
}
[root@web02 /tmp]# systemctl restart nginx
[root@web02 ~]# echo "Web02 based on nginx" > /html/index.html
# test
[root@jenkins ~]# curl http://html.aspen.com
Web02 based on nginx
[root@jenkins ~]# curl http://html.aspen.com
Web01 based on nginx

step 01 上传代码至Gitlab

Git相关操作请参照版本控制章节

示例代码
提取码:t905
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git remote -v
origin  https://gitee.com/kangjie1209/monitor.git (fetch)
origin  https://gitee.com/kangjie1209/monitor.git (push)
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git remote remove origin
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git remote -v

step 02 配置免密环境(代码拉取免密)

[root@jenkins ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
......
[root@jenkins ~]# cat ./.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsww7jcptgQg5YMOb65UtFPVlKQM1oUgOe5hMSymhNvmDnp4fPHaOafHDl5a8qJFhNLGu6vxqwA9YY7lOm0i4zGHdiliOhAENNg64rrAxYOZSheHzw7zuLF/oFXpQ7kSkpISr3sQ4XeSYb/TtJEk77AQt7X+y+dzoVT8q+p7wx5Xd3ui8oz9x5Y//7i1Nn06fOjFcpxjvl+GllwUXCGBRuekTs+oHRya4u9f6S9VqaJc53VCbYVL6JmjX9pg230RkXux+c/+N3gIU+XOixuCIoSaIlNghgc3bYXRRwgrx9tQYBul3kA4vpIeSXVHBowifJnGPzHVzYpfEwrnb12SdL root@jenkins

step 03 手动上线代码

# 提交代码至Gitlab
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git remote add origin http://gitlab.aspen.com/dev/monitor.git
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git add .

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git commit -m "Initial commit"
On branch master
nothing to commit, working tree clean

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git push -u origin master
libpng warning: iCCP: cHRM chunk does not match sRGB
Enumerating objects: 435, done.
Counting objects: 100% (435/435), done.
Delta compression using up to 12 threads
Compressing objects: 100% (372/372), done.
Writing objects: 100% (435/435), 8.78 MiB | 12.88 MiB/s, done.
Total 435 (delta 53), reused 435 (delta 53)
remote: Resolving deltas: 100% (53/53), done.
To http://gitlab.aspen.com/dev/monitor.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
# 运维部署代码
[root@jenkins ~]# git clone git@gitlab.aspen.com:dev/monitor.git
Cloning into 'monitor'...
remote: Enumerating objects: 438, done.
remote: Counting objects: 100% (438/438), done.
remote: Compressing objects: 100% (375/375), done.
remote: Total 438 (delta 55), reused 434 (delta 53)
Receiving objects: 100% (438/438), 8.78 MiB | 0 bytes/s, done.
Resolving deltas: 100% (55/55), done.
[root@jenkins ~]# ls
anaconda-ks.cfg  monitor
[root@jenkins ~]# scp -rp ./monitor/* root@10.0.0.17:/html/
The authenticity of host '10.0.0.17 (10.0.0.17)' can't be established.
ECDSA key fingerprint is SHA256:4O+/HRUt2Qwcz4xXk3y+Y5It07gqAUNy//ju/dZH2Vc.
ECDSA key fingerprint is MD5:5b:e2:99:8c:b6:d6:88:85:2c:4a:84:65:4a:74:78:75.
......
[root@jenkins ~]# scp -rp ./monitor/* root@10.0.0.18:/html/
The authenticity of host '10.0.0.18 (10.0.0.18)' can't be established.
ECDSA key fingerprint is SHA256:4O+/HRUt2Qwcz4xXk3y+Y5It07gqAUNy//ju/dZH2Vc.
ECDSA key fingerprint is MD5:5b:e2:99:8c:b6:d6:88:85:2c:4a:84:65:4a:74:78:75.
......

step 04 创建Job(Jenkins)

# 准备工作
[root@jenkins ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.17
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
......
[root@jenkins ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.18
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
......

[root@jenkins ~]# cat ./.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA7MMO43KbYEIOWDDm+uVLRT1ZSkDNaFIDnuYTEspoTb5g56eH
......
-----END RSA PRIVATE KEY-----

step 05 编写自动构建脚本

[root@jenkins ~]# mkdir /scripts
[root@jenkins ~]# vim /scripts/jenkins_deploy_html.sh
#!/usr/bin/bash
for host in {10.0.0.17,10.0.0.18}
do
   scp -rp $WORKSPACE/* root@$host:/html
done
[root@jenkins ~]# chmod +x /scripts/jenkins_deploy_html.sh 
[root@jenkins ~]# ll /scripts/jenkins_deploy_html.sh
-rwxr-xr-x 1 root root 100 Mar  1 14:37 /scripts/jenkins_deploy_html.sh

step 06 优化job

#!/usr/bin/bash
Date=$(date +%F-%H-%M)
Web_Host="10.0.0.17 10.0.0.18"
Project_Name="HTML-monitor-$Date"
Sdir=/opt
Ddir=/Code
WorkDir=/Web

function_tar() {
    cd $WORKSPACE
    tar czf $Sdir/${Project_Name}.tar.gz ./*
}

function_scp() {
    for host in ${Web_Host}
    do
        scp -rp $Sdir/${Project_Name}.tar.gz root@$host:/opt
        ssh root@$host "mkdir -p ${Ddir}${WorkDir}/${Project_Name} && \
        tar xf /opt/${Project_Name}.tar.gz -C ${Ddir}${WorkDir}/${Project_Name} && \
        rm -f /opt/${Project_Name}.tar.gz && \
        rm -rf /html && \
        ln -s ${Ddir}${WorkDir}/${Project_Name} /html"
    done
}
function_deploy() {
    function_tar
    function_scp
}
function_deploy

step 07 模拟更新代码

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ vim index.html
...
            <a class="logo pull-left" href="index.html" style="width: 233px">Monitor Plat v1.0</a>
...
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git add .
warning: LF will be replaced by CRLF in index.html.
The file will have its original line endings in your working directory

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git commit -m "Monitor Plat v1.0"
[master e9b7d61] Monitor Plat v1.0
 1 file changed, 1 insertion(+), 1 deletion(-)

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git push -u origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 334 bytes | 334.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/monitor.git
   a371858..e9b7d61  master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

step 08 基于参数化构建优化

#!/usr/bin/bash
Date=$(date +%F-%H-%M)
Web_Host="10.0.0.17 10.0.0.18"
Project_Name="HTML-monitor-$Date-${git_version}"
Sdir=/opt
Ddir=/Code
WorkDir=/Web

function_tar() {
    cd $WORKSPACE
    tar czf $Sdir/${Project_Name}.tar.gz ./*
}

function_scp() {
    for host in ${Web_Host}
    do
        scp -rp $Sdir/${Project_Name}.tar.gz root@$host:/opt
        ssh root@$host "mkdir -p ${Ddir}${WorkDir}/${Project_Name} && \
        tar xf /opt/${Project_Name}.tar.gz -C ${Ddir}${WorkDir}/${Project_Name} && \
        rm -f /opt/${Project_Name}.tar.gz && \
        rm -rf /html && \
        ln -s ${Ddir}${WorkDir}/${Project_Name} /html"
    done
}
function_deploy() {
    function_tar
    function_scp
}
function_deploy

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ vim index.html
......
            <a class="logo pull-left" href="index.html" style="width: 233px">Monitor Plat v1.3</a>
......
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git add .
gwarning: LF will be replaced by CRLF in index.html.
The file will have its original line endings in your working directory

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git commit -m "ver 1.3"
[master 7096ce8] ver 1.3
 1 file changed, 1 insertion(+), 1 deletion(-)

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 311 bytes | 311.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/monitor.git
   eac358d..7096ce8  master -> master
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git tag -a "v1.3" -m "tag ver 1.3"

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/monitor (master)
$ git push --tags
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 157 bytes | 157.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/monitor.git
 * [new tag]         v1.3 -> v1.3

step 09 基于git paremeter插件构建优化

step 10 实现代码回退

#!/bin/bash
Web_Host="10.0.0.17 10.0.0.18"
Backup_File=$(ssh root@10.0.0.18 "find /Code/Web  -iname *-${git_version} -type d")
function_rollback() {
    for i in ${Web_Host}
    do
       ssh root@$i "rm -rf /html && \
       ln -s ${Backup_File} /html"
    done
}

function_rollback

2. Jenkins部署Java

step 00 准备环境(Nginx+Tomcat)

Tomcat操作详见Tomcat章节

[root@lb01 ~]# cat /etc/nginx/conf.d/jenkins_test_proxy.conf 
upstream aspen {
    server 172.16.1.17:8080;
    server 172.16.1.18:8080;
}
server {
    listen 80;
    server_name html.aspen.com;
    location / {
        proxy_pass http://aspen;
        proxy_set_header Host $http_host;
    }
}
[root@lb01 ~]# systemctl restart nginx
[root@web01 ~]# netstat -lntp | grep 8080
tcp6       0      0 :::8080                 :::*                    LISTEN      8190/java     
[root@web02 ~]# netstat -lntp | grep 8080
tcp6       0      0 :::8080                 :::*                    LISTEN      7961/java 

step 01 上传代码至Gitlab

示例代码
提取码:t905
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git remote remove origin

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git remote -v

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git remote add origin http://gitlab.aspen.com/dev/java.git

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git add .

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git commit -m "first commit"
On branch master
nothing to commit, working tree clean

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git push -u origin master
......
Branch 'master' set up to track remote branch 'master' from 'origin'.

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git tag -a v1.0 -m "java_code 1.0"

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git push --tags
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 160 bytes | 160.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/java.git
 * [new tag]         v1.0 -> v1.0

step 02 手动拉取代码

[root@jenkins ~]# git clone git@gitlab.aspen.com:dev/java.git
Cloning into 'java'...
remote: Enumerating objects: 20, done.
remote: Counting objects: 100% (20/20), done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 20 (delta 2), reused 0 (delta 0)
Receiving objects: 100% (20/20), done.
Resolving deltas: 100% (2/2), done.
[root@jenkins ~]# cd java/
[root@jenkins ~/java]# tree .
.
├── dist
│   └── hello-world.war
├── pom.xml
├── README.md
└── src
    └── main
        └── webapp
            ├── index.jsp
            └── WEB-INF
                └── web.xml

5 directories, 5 files

step 03 安装编译插件

maven插件依赖于Java程序运行。
yum install -y maven
[root@jenkins ~/java]# yum install -y maven
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
......
Installed:
  maven.noarch 0:3.0.5-17.el7                  
......
Complete!
[root@jenkins ~/java]# java -version
openjdk version "1.8.0_282"
OpenJDK Runtime Environment (build 1.8.0_282-b08)
OpenJDK 64-Bit Server VM (build 25.282-b08, mixed mode)
[root@jenkins ~/java]# mvn -version
Apache Maven 3.0.5 (Red Hat 3.0.5-17)
Maven home: /usr/share/maven
Java version: 1.8.0_282, vendor: Red Hat, Inc.
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.282.b08-1.el7_9.x86_64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-957.el7.x86_64", arch: "amd64", family: "unix"

step 04 配置maven国内源

可以使用Nexus服务搭建本地的Maven仓库。
# /etc/maven/settings.xml
< mirrors >
< mirror >

< id >alimaven< /id >
< mirrorOf >central< /mirrorOf >
< name >aliyun maven< /name >
< url >http://maven.aliyun.com/nexus/content/repositories/central< /url >

< /mirror >
< /mirrors >

[root@jenkins ~/java]# awk '/<mirrors>/,/<\/mirrors>/' /etc/maven/settings.xml 
  <mirrors>
    <!-- mirror
     | Specifies a repository mirror site to use instead of a given repository. The repository that
     | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
     | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
     |
    <mirror>
      <id>mirrorId</id>
      <mirrorOf>repositoryId</mirrorOf>
      <name>Human Readable Name for this Mirror.</name>
      <url>http://my.repository.com/repo/path</url>
    </mirror>
     -->
    <mirror>
      <id>alimaven</id>
      <mirrorOf>central</mirrorOf>
      <name>aliyun maven.</name>
      <url>http://maven.aliyun.com/nexus/content/repositories/central</url>
    </mirror>
  </mirrors>

step 05 编译

执行编译时,需进入项目目录。
mvn clean package
[root@jenkins ~/java]# mvn clean package
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Hello World Web Application Repository 1.0.0
[INFO] ------------------------------------------------------------------------
Downloading: http://maven.aliyun.com/nexus/content/repositories/central/org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.pom
......
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 31.407s
[INFO] Finished at: Fri Mar 05 15:29:55 CST 2021
[INFO] Final Memory: 10M/31M
[INFO] ------------------------------------------------------------------------
[root@jenkins ~/java]# ls
dist  pom.xml  README.md  src  target
[root@jenkins ~/java]# tree target/
target/
├── hello-world-war-1.0.0
│   ├── index.jsp
│   ├── META-INF
│   └── WEB-INF
│       ├── classes
│       └── web.xml
├── hello-world-war-1.0.0.war
├── maven-archiver
│   └── pom.properties
└── surefire

6 directories, 4 files

编译缓存jar包存放目录

缓存编译的jar包存放在当前用户下.m2目录下。
[root@jenkins ~]# du -sh ./.m2/
4.0M    ./.m2/
[root@jenkins ~]# find ./.m2 -iname *.jar | head -4
./.m2/repository/org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.jar
./.m2/repository/org/apache/maven/plugins/maven-resources-plugin/2.5/maven-resources-plugin-2.5.jar
./.m2/repository/org/apache/maven/plugins/maven-compiler-plugin/2.3.2/maven-compiler-plugin-2.3.2.jar
./.m2/repository/org/apache/maven/plugins/maven-surefire-plugin/2.10/maven-surefire-plugin-2.10.jar

step 06 手动上线代码

[root@jenkins ~/java]# ssh root@10.0.0.17 'rm -rf /application/tomcat/webapps/*'
[root@jenkins ~/java]# ssh root@10.0.0.18 'rm -rf /application/tomcat/webapps/*'
[root@jenkins ~/java]# scp target/hello-world-war-1.0.0.war root@10.0.0.17:/application/tomcat/webapps/ROOT.war
hello-world-war-1.0.0.war                                              100% 2403     1.1MB/s   00:00    
[root@jenkins ~/java]# scp target/hello-world-war-1.0.0.war root@10.0.0.18:/application/tomcat/webapps/ROOT.war
hello-world-war-1.0.0.war
[root@jenkins ~/java]# ssh root@10.0.0.18 'ls /application/tomcat/webapps/'
ROOT
ROOT.war
[root@jenkins ~/java]# ssh root@10.0.0.17 'ls /application/tomcat/webapps/'
ROOT
ROOT.war

step 07 重启Tomcat服务

[root@jenkins ~/java]# ssh root@10.0.0.17 'pkill java && /application/tomcat/bin/startup.sh'
Tomcat started.
[root@jenkins ~/java]# ssh root@10.0.0.18 'pkill java && /application/tomcat/bin/startup.sh'
Tomcat started.

step 08 创建Job(Jenkins)

[root@jenkins ~/java]# mvn -version
Apache Maven 3.0.5 (Red Hat 3.0.5-17)
Maven home: /usr/share/maven
Java version: 1.8.0_282, vendor: Red Hat, Inc.
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.282.b08-1.el7_9.x86_64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-957.el7.x86_64", arch: "amd64", family: "unix"

step 09 编写自动构建脚本

[root@jenkins ~]# cat /scripts/jenkins_deploy_java.sh 
#!/usr/bin/bash
Date=$(date +%F-%H-%M)
Web_Host="10.0.0.17 10.0.0.18"
Project_Name="Java-ROOT-$Date-${git_version}"
Sdir=/opt/Java_Project
Ddir=/Code/Java
Tomcat_Path=/application/tomcat/webapps
function_deploy() {
    for host in ${Web_Host}
    do
        ssh root@$host "mkdir -p ${Sdir}"
        scp -rp  ${WORKSPACE}/target/*.war  root@$host:${Sdir}/${Project_Name}.war
        ssh root@$host "mkdir -p ${Ddir} && \
        cd ${Sdir} && \
        unzip  ${Project_Name}.war -d ${Ddir}/${Project_Name} && \
        rm -f  ${Sdir}/${Project_Name}.war && \
        rm -rf ${Tomcat_Path}/ROOT && \
        ln -s  ${Ddir}/${Project_Name}  ${Tomcat_Path}/ROOT && \
        pkill java; \
        /application/tomcat/bin/startup.sh "
    done
}
function_deploy

step 10 模拟更新代码

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ sed -i 's#Aspen_Han v1.2#Yong_Han v1.3#g' src/main/webapp/index.jsp

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ sed -n 6p src/main/webapp/index.jsp
        <h1>Hello World! Yong_Han v1.3</h1>

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git add .
warning: LF will be replaced by CRLF in src/main/webapp/index.jsp.
The file will have its original line endings in your working directory

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git commit -m "new version"
[master 45e6601] new version
 1 file changed, 1 insertion(+), 1 deletion(-)

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git push origin master
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 12 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 460 bytes | 230.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/java.git
   8a43fb4..45e6601  master -> master

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git tag -a "v1.3" -m "Young_Han"

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git push origin --tags
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 160 bytes | 160.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/java.git
 * [new tag]         v1.3 -> v1.3

三、扩展

1. 钉钉通知

该功能依赖Jenkins的DingDing插件实现。

step 1 添加群组机器人

step 2 Jenkins集成钉钉

step 3 测试

2. 邮件通知

内容转自老_张博客

未完待续...

3. Gitlab自动触发Jenkins

该功能基于Gitlab的Webhook实现,常用于企业测试环境的代码部署,不建议使用在生产环境中。

step 1 改造jenkins项目

step 2 gitlab允许访问本地Web钩子

step 3 gitlab增加Webhook

step 4 模拟提交代码

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ sed 's#Yong_Han v1.3#Aspen_Han WEB_HOOK Test#g' src/main/webapp/index.jsp -i
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ sed -n 6p src/main/webapp/index.jsp
        <h1>Hello World! Aspen_Han WEB_HOOK Test</h1>
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git add .
warning: LF will be replaced by CRLF in src/main/webapp/index.jsp.
The file will have its original line endings in your working directory
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git commit -m "WEB_Hook"
[master b5cfefd] WEB_Hook
 1 file changed, 1 insertion(+), 1 deletion(-)
Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git push origin
Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 12 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 471 bytes | 235.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/java.git

step 5 验证

4. 分布式构建

Slave节点插件应与Master节点插件一致,并需要与各个关联节点实现免密。

step1 增加Slave节点

系统管理 -> 节点管理 -> 新建节点

step2 启用Slave节点

系统管理 -> 节点管理 -> 指定节点 -> 启动代理

step3 测试主从关系

注意各种工具插件配置文件的同步以及各种部署脚本的同步

step 4 将指定任务分配至指点节点

pipeline {
    // agent any
    agent { label 'Branch01' } //分配指定节点执行任务
    parameters {
        string(name: 'git_version', defaultValue: 'v1.0', description: 'Gitlab项目Tag')
    }
    ......
}

四、Pipeline

Pipeline是运行在Jenkins上的工作框架,通过“代码的方式”将多个任务链接起来。

1. 优势

  • 直观展示每个阶段的任务
  • 直观展示每个阶段的执行时间
  • 快速定位任务出现错误的位置

2. 作用

传统的Jenkins任务部署流程,需在图形界面下进行点击(交互式操作),使用pipeline能够实现每一步自动化,不需要人为干预。

3. 基础语法

Pipeline是一种固定格式,必须遵行。
pipeline { #所有代码包含在pipeline{}内

agent any #agent{}定义任务在哪台主机上运行,可以是any,none等
environment { #environment{}用于定义环境变量
变量名='变量值'
}
stages { #stages{}类似一个大项目的集合,主要用于包含所有stage子任务
stage('任务名1'){ #stage{}类似单个子任务,主要用来包含steps子层
steps { #steps{} 用来实现具体执行的操作
执行命令
}
}
stage('任务名2'){
steps {
执行命令
}
}
}
post { #satges所有任务执行后,出发post任务
failure { #构建失败钉钉通知
dingTalk accessToken: '令牌',imageUrl: '',jenkinsUrl: 'jenkins服务地址',message: '消息', notifyPeople: ''
}
success { #构建成功钉钉通知
dingTalk accessToken: '令牌',imageUrl: '',jenkinsUrl: 'jenkins服务地址',message: '消息', notifyPeople: ''
}
}

}

4. pipeline项目改造

以Java项目为示例

step 1 创建pipeline项目

step 2 语法查询

step 3 编写pipeline 脚本

pipeline {
    agent any
    parameters {
        string(name: 'git_version', defaultValue: 'v1.0', description: 'Gitlab项目Tag')
    }
    stages {
        stage('获取代码'){
            steps {
              checkout([$class: 'GitSCM', branches: [[name: '${git_version}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '0776c87e-9d98-4023-a9ac-df5384d499ee', url: 'git@gitlab.aspen.com:dev/java.git']]])  
            }
        }
        stage('质量检测'){
            steps {
                sh '/usr/local/sonar-scanner/bin/sonar-scanner -Dsonar.projectKey=${JOB_NAME} -Dsonar.sources=. -Dsonar.java.binaries=target/sonar'
            }
        }
        stage('代码编译'){
            steps {
                sh 'mvn clean package'
            }
        }
        stage('代码部署'){
            steps {
                sh 'sh -x /scripts/jenkins_deploy_java.sh'
            }
        }
    }
    post {
        failure {
            dingTalk accessToken: '620c7530a39fe8be70ba2c55d4e4b4adbd2806502bf61f13f6def25debeba229', imageUrl: '', jenkinsUrl: 'http://jenkins.aspen.com:8080/', message: '代码构建失败', notifyPeople: ''
        }
        success {
            dingTalk accessToken: '620c7530a39fe8be70ba2c55d4e4b4adbd2806502bf61f13f6def25debeba229', imageUrl: '', jenkinsUrl: 'http://jenkins.aspen.com:8080/', message: '代码构建成功', notifyPeople: ''
        }
    }
}
  • git拉取代码

  • 钉钉通知

step 4 测试pipeline

  • 常规视图

  • Blue Ocean

5.pipeline scripts from SCM

step 1 项目改造

step 2 编写脚本

pipeline {
    agent any
    parameters {
        string(name: 'git_version', defaultValue: 'v1.0', description: 'Gitlab项目Tag')
    }
    stages {
        stage('获取代码'){
            steps {
              checkout([$class: 'GitSCM', branches: [[name: '${git_version}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '0776c87e-9d98-4023-a9ac-df5384d499ee', url: 'git@gitlab.aspen.com:dev/java.git']]])  
            }
        }
        stage('质量检测'){
            steps {
                sh '/usr/local/sonar-scanner/bin/sonar-scanner -Dsonar.projectKey=${JOB_NAME} -Dsonar.sources=. -Dsonar.java.binaries=target/sonar'
            }
        }
        stage('代码编译'){
            steps {
                sh 'mvn clean package'
            }
        }
        stage('代码部署'){
            steps {
                sh 'sh -x /scripts/jenkins_deploy_java.sh'
            }
        }
    }
    post {
        failure {
            dingTalk accessToken: '620c7530a39fe8be70ba2c55d4e4b4adbd2806502bf61f13f6def25debeba229', imageUrl: '', jenkinsUrl: 'http://jenkins.aspen.com:8080/', message: '代码构建失败', notifyPeople: ''
        }
        success {
            dingTalk accessToken: '620c7530a39fe8be70ba2c55d4e4b4adbd2806502bf61f13f6def25debeba229', imageUrl: '', jenkinsUrl: 'http://jenkins.aspen.com:8080/', message: '代码构建成功', notifyPeople: ''
        }
    }
}

step 3 提交项目

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ vim Jenkinsfile

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git add .
warning: LF will be replaced by CRLF in Jenkinsfile.
The file will have its original line endings in your working directory

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git commit -m "SCM mode for pipeline"
[master 824ad6d] SCM mode for pipeline
 1 file changed, 36 insertions(+)
 create mode 100644 Jenkinsfile

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git push origin master
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 946 bytes | 946.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/java.git
   b5cfefd..824ad6d  master -> master

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git tag -a "v1.4" -m "tag ver 1.4 add SCM"

Aspen_Han@DESKTOP-QQSLJ85 MINGW64 /f/code/java (master)
$ git push --tags
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 164 bytes | 164.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To http://gitlab.aspen.com/dev/java.git
 * [new tag]         v1.4 -> v1.4