🔜What is Jenkins?🔚
Jenkins is an open-source CI&CD software developed in Java, used for automating various tasks including building, testing, and deploying software. Jenkins offers multiple installation methods and provides over 1000 plugins to meet the needs of any project.
Features of Jenkins:
- An open-source continuous integration tool developed in Java, supporting continuous integration and continuous deployment.
- Easy to install, deploy, and configure: can be installed quickly via yum, or by downloading the war package and using docker containers, with convenient web interface configuration management.
- Notification and testing reports: integrates RSS/email to publish build results via RSS or notify via email when builds are completed, generating JUnit/TestNG test reports.
- Distributed builds: supports Jenkins to allow multiple computers to build/test together.
- File tracking: Jenkins can track which builds generated which jars, which builds used which version of jars, etc.
- Rich plugin support: supports extending plugins, allowing you to develop tools suitable for your team, such as git, svn, maven, docker, etc.
This article builds a CI/CD process using GitLab + Jenkins + Tomcat.
Host Planning#
Hostname | IP | Required Software | Purpose |
---|---|---|---|
121 | 192.168.1.121 | GitLab-12.4.2 | Code Hosting |
124 | 192.168.1.124 | Jenkins, JDK-21, Maven-3.9.9, Git, SonarQube | Jenkins Continuous Integration |
125 | 192.168.1.125 | JDK-1.8, Tomcat-8.5 | Release Testing |
The server operating system is CentOS 7.9.
Deployment Steps#
Deploy GitLab#
Install GitLab#
Install dependencies
yum -y install policycoreutils-python policycoreutils postfix
Download and install GitLab
# Download GitLab installation package
curl -O http://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-12.4.2-ce.0.el7.x86_64.rpm
# Install GitLab
rpm -i gitlab-ce-12.4.2-ce.0.el7.x86_64.rpm
Modify GitLab's default access port
vi /etc/gitlab/gitlab.rb
# Change the default port 80 to 82
external_url "http://192.168.1.121:82"
nginx['listen_port'] = 82
Reload configuration and start GitLab
gitlab-ctl reconfigure
gitlab-ctl restart
Configure firewall policy
firewall-cmd --add-port=82/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all
Enter http://192.168.1.121:82/ in the browser, change the root user password, and log in to GitLab with the root user.
Manage GitLab#
(1) Create a group
Use the administrator root to create a group, which can contain multiple project branches. Developers can be added to the group to set permissions. Different groups represent different development projects or service modules in the company, and adding different developers to different groups allows for permission management.
(2) Create a project
(3) Create a user
In the management center - Overview - Users, create a new user test1
, set a password, and add the user to the newly created project.
GitLab users have 5 different permissions within a group:
- Guest: Can create issues and comment, cannot read or write the repository.
- Reporter: Can clone code, cannot submit; QA and PM can grant this permission.
- Developer: Can clone code, develop, submit, and push; regular developers can grant this permission.
- Maintainer: Can create projects, add tags, protect branches, add project members, and edit projects; core developers can grant this permission.
- Owner: Can set project access permissions Visibility Level, delete projects, migrate projects, and manage group members; the group leader can grant this permission.
Upload Project Code#
Create a Java project using IDEA and upload it to the GitLab repository.
The Java project code used in this article comes from the Bilibili uploader, '' 涣沷 a 靑惷 '', with the original link: https://www.yuque.com/huanfqc/jenkins/jenkins.
The Java code address is: https://share.feijipan.com/s/qdEO7czl
Import the project into IDEA, configure GitLab-related settings, push the code, and refer to the original link mentioned above for specific steps.
Deploy Jenkins#
When installing jenkins-2.19*, the Chinese plugin cannot be installed properly. The JDK used in this article is jdk-21, and Jenkins is 2.492.3, both installed via rpm.
(1) Install JDK
yum install -y wget && wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.rpm
rpm -ivh jdk-21_linux-x64_bin.rpm
# Check version
java -version
(2) Install Jenkins
# Download Jenkins
curl -O https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat-stable/jenkins-2.492.3-1.1.noarch.rpm
# Install
rpm -ivh jenkins-2.492.3-1.1.noarch.rpm
(3) Modify Jenkins configuration file
vi /etc/sysconfig/jenkins
# Change the default user to root
JENKINS_USER="root"
# Change the default port to 8888
JENKINS_PORT=8888
(4) Configure firewall policy and start Jenkins
firewall-cmd --add-port=8888/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all
# Start Jenkins
systemctl daemon-reload
systemctl start jenkins
systemctl enable jenkins
(5) View Jenkins admin initialization password
cat /var/lib/jenkins/secrets/initialAdminPassword
(6) Enter http://192.168.1.124:8888/ in the browser, and enter the admin initialization password.
(7) Click Select plugins to install
, choose None
, and skip installing plugins to prepare for reconfiguring the domestic source for downloading plugins later.
(8) Follow the guide to complete the installation of Jenkins.
Configure Domestic Plugin Source#
(1) Select Jenkins - Manage Jenkins - Manage Plugins from the left sidebar, select Available, and wait for the plugin-related files to load.
(2) Enter the plugin directory and modify the address to the domestic source
cd /var/lib/jenkins/updates && ll
sed -i 's|http://updates.jenkins-ci.org/download|https://mirrors.tuna.tsinghua.edu.cn/jenkins|g' default.json
sed -i 's|http://www.google.com|https://www.baidu.com|g' default.json
(3) Access Jenkins, select Jenkins - Manage Jenkins - Manage Plugins from the left sidebar, select Advanced, change the Update Site to https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
(or https://mirrors.huaweicloud.com/jenkins/updates/update-center.json
), save, and enter http://192.168.1.124:8888/restart
in the browser to click and restart Jenkins.
Set Chinese Language#
Install the Chinese plugin, select Jenkins - Manage Jenkins - Manage Plugins from the left sidebar, select Advanced, search for chinese
, check the plugin, and click download and restart.
Manage User Permissions#
Install the Role-based Authorization Strategy
plugin to manage user permissions. After installation, (in the new version of Jenkins) select Manage Jenkins - Security, and choose Role-Based Strategy for the authorization strategy. Select Manage Jenkins - Manage and Assign Roles to create and assign roles.
Credential Management#
(1) Install the Credentials Binding
plugin for credential management.
Credential types:
- Username with password: Username and password
- SSH Username with private key: Using SSH user and key
- Secret file: A confidential text file, which Jenkins will copy to a temporary directory when used, and then set the file path to a variable. After the build ends, the copied Secret file will be deleted.
- Secret text: An encrypted text string to be saved, such as a DingTalk robot or GitHub API token.
- Certificate: By uploading the certificate file.
Common credential types are: Username with password and SSH Username with private key.
(2) Install the git
plugin and download git on the server.
yum -y install git
Password Credentials#
(1) Create a Jenkins project and password credentials. Select Manage Jenkins - Credentials, click Global
- Add Credentials
, and add the GitLab user test1's username and password to create credentials.
(2) Create a new task test01
, click configure, set the source code management to Git, fill in the GitLab project repository address (starting with http), select test1's credentials, and save.
(3) Enter test01, click Build Now, wait for the task to complete, and click console output to view detailed information.
SSH Key Credentials#
(1) Create an SSH key on the Jenkins server.
ssh-keygen -t rsa
# View public key content
cat ~/.ssh/id_rsa.pub
# Test SSH connection
ssh -T [email protected]
# Check if there is a GitLab host, ensure that the host exists; otherwise, an error will occur when using SSH credentials
cat ~/.ssh/known_hosts
(2) Log in to GitLab with the administrator account, select Settings
- SSH Keys
, paste the SSH public key content, and save.
(3) Use the command cat ~/.ssh/id_rsa
on the server to view the private key content. Create an SSH key credential in Jenkins, input the username root and SSH private key content, and save.
(4) Create a new task test02
, click configure, set the source code management to Git, fill in the GitLab project repository address (starting with git), select SSH credentials, and save.
(5) Enter test02, click Build Now, wait for the task to complete, and click console output to view detailed information.
Install Maven#
(1) Download and install Maven
curl -O https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.9.9/binaries/apache-maven-3.9.9-bin.tar.gz
# Create storage directory
mkdir -p /opt/maven
tar -vxzf apache-maven-3.9.9-bin.tar.gz -C /opt/maven/
# Configure environment variables to make them effective
echo "
export MAVEN_HOME=/opt/maven/apache-maven-3.9.9
export PATH=\$PATH:\$MAVEN_HOME/bin" >> /etc/profile
source /etc/profile
# Check Maven version
mvn -v
(2) Configure Jenkins to associate with Maven
In Manage Jenkins - Tools, configure JDK installation
and Maven installation
, setting their corresponding installation paths.
In Manage Jenkins - System - Global properties, add 3 Environment variables
.
(3) Modify Maven's local repository location
# Create local repository
mkdir -p /data/jenkins/repo
# Modify Maven's configuration file
vi /opt/maven/apache-maven-3.9.9/conf/settings.xml
# Change <localRepository>/path/to/local/repo</localRepository> to
<localRepository>/data/jenkins/repo</localRepository>
# Add Aliyun mirror source after the mirror with <id>maven-default-http-blocker</id>
# <mirror>
# <id>maven-default-http-blocker</id>
# <mirrorOf>external:http:*</mirrorOf>
# <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
# <url>http://0.0.0.0/</url>
# <blocked>true</blocked>
# </mirror>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
(4) Test Maven configuration
In Jenkins, select the task test02
, choose configure - Environment - Build Steps, select Execute shell, and enter the command mvn clean package
, save, click Build Now, wait for the task to complete, and click console output to view detailed information.
At this point, a target
directory will be added to the test02 task directory on the server.
[root@124 workspace]# ls
test01 test01@tmp test02 test02@tmp
[root@124 workspace]# cd test01
[root@124 test01]# ls
pom.xml src
[root@124 test01]# cd ..
[root@124 workspace]# ls
test01 test01@tmp test02 test02@tmp
[root@124 workspace]# cd test02
[root@124 test02]# ls
pom.xml src target
[root@124 test02]# pwd
/var/lib/jenkins/workspace/test02
[root@124 test02]#
Install Tomcat#
Download jdk-1.8 and tomcat-9
yum install -y java-1.8.0-openjdk*
curl -O https://mirrors.huaweicloud.com/apache/tomcat/tomcat-9/v9.0.104/bin/apache-tomcat-9.0.104.tar.gz
# Create storage directory
mkdir -p /opt/tomcat/
# Unzip
tar -zxvf apache-tomcat-9.0.104.tar.gz -C /opt/tomcat/
# Start Tomcat
/opt/tomcat/apache-tomcat-9.0.104/bin/startup.sh
Configure firewall policy
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload
firewall-cmd --list-all
Access http://192.168.1.125:8080/
in the browser.
Configure Tomcat user roles
vi /opt/tomcat/apache-tomcat-9.0.104/conf/tomcat-users.xml
<!-- Add the following content under the tomcat-users tag -->
<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"/>
Configure the range of remote access addresses for Tomcat
vi /opt/tomcat/apache-tomcat-9.0.104/webapps/manager/META-INF/context.xml
<!-- Comment out the following content -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
Restart Tomcat, enter the username and password to access.
# Stop running
/opt/tomcat/apache-tomcat-9.0.104/bin/shutdown.sh
# Start
/opt/tomcat/apache-tomcat-9.0.104/bin/startup.sh
Jenkins Build Project#
There are many types of automatic project builds in Jenkins, commonly including the following three:
- FreeStyle Project
- Maven Project
- Pipeline Project
The war package used in this article comes from the Bilibili uploader, '' 涣沷 a 靑惷 '', with the original link: https://www.yuque.com/huanfqc/jenkins/jenkins.
The war package project code address is: https://share.feijipan.com/s/BWEO9Jad, and the specific process of building the war package can be found in the original text.
Jenkins Build FreeStyle Project#
(1) Install the Deploy to container
plugin.
(2) Create a new project freestyle_demo
, configure and pull the test_war code from GitLab. This process, in addition to including the steps in the "Deploy Jenkins" section, also requires post-build actions, as shown in the following image.
(3) After saving the configuration, click Build Now, wait for the task to complete, and access Tomcat to see that the /websocketChat-1.0-SNAPSHOT
virtual directory has appeared.
Jenkins Build Maven Project#
(1) Install the Maven Integration
plugin.
(2) Create a new project maven-demo
, configure and pull the test_war code from GitLab. This process, in addition to including the steps in the "Jenkins Build FreeStyle Project" section, also requires modifications during the Build, as shown in the following image.
If an error occurs during the build, you can change the previously configured Aliyun mirror address to https.
(3) After saving the configuration, click Build Now, wait for the task to complete, and access Tomcat to see that the /websocketChat-1.0-SNAPSHOT
virtual directory has appeared.
Jenkins Build Pipeline Project#
Pipeline, simply put, is a workflow framework running on Jenkins that connects tasks that originally run independently on one or multiple nodes to achieve complex process orchestration and visualization that a single task is difficult to complete.
How to create a Jenkins Pipeline?
-
Pipeline scripts are implemented in Groovy language.
-
Pipeline supports two syntaxes: Declarative and Scripted Pipeline syntax.
-
There are also two ways to create a Pipeline: you can directly enter the script in Jenkins' Web UI; or you can create a Jenkinsfile script file and place it in the project source code repository (generally, we recommend directly loading the Jenkinsfile Pipeline from source control (SCM) in Jenkins).
Create a Pipeline script in Jenkins' Web UI to publish the project#
(1) Install the Pipeline plugin.
(2) Create a new task Pipeline-demo
, using declarative syntax, create a Pipeline script in Jenkins' Web UI; implement pulling code, compiling, building, and publishing the project.
In the configuration interface of Pipeline-demo, select Build Triggers - Pipeline, and choose a script template Hello World.
Click Pipeline Syntax
, select checkout: Check out from version control
in the snippet generator, and follow the guide to fill in the project address and credentials, generating the pipeline script. Paste the code pulling script into the modified template.
Select sh: Shell Script
in the snippet generator, fill in the compile command, and paste the script into the modified template.
Select deploy: Deploy war/ear to a container
in the snippet generator, follow the guide to fill in, and paste the script into the modified template.
pipeline {
agent any
stages {
stage('Pull Code') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/test_war_demo.git']])
}
}
stage('Compile Build') {
steps {
sh 'mvn clean package'
}
}
stage('Publish Project') {
steps {
deploy adapters: [tomcat9(credentialsId: '4d9b76aa-078c-462b-81f1-33fe1d9c971c', path: '', url: 'http://192.168.1.125:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
}
(3) After saving the configuration, click Build Now, wait for the task to complete, and access Tomcat to see that the /websocketChat-1.0-SNAPSHOT
virtual directory has appeared.
Use Jenkinsfile script to publish the project#
(1) In the project directory in IDEA, select New - File, create a Jenkinsfile file, and paste the Pipeline script content into it, publishing it together with the code to the project repository.
(2) In the configuration interface of the task Pipeline-demo
, select Build Triggers - Pipeline, define the content to select Pipeline script from SCM
- Git
, fill in the project address and credentials, and set the script path to Jenkinsfile
.
(3) After saving the configuration, click Build Now, wait for the task to complete, and access Tomcat to see that the /websocketChat-1.0-SNAPSHOT
virtual directory has appeared.
Common Build Triggers#
Jenkins has 4 built-in build triggers:
-
Trigger remote builds
-
Trigger after other projects build (Build after other projects are built)
-
Build periodically
The timing string from left to right represents: minute hour day month week
Examples of timing expressions:
Build once every 30 minutes: H represents a parameter
H/30 * * * *
Build once every 2 hours:
H H/2 * * *
Build 3 times a day at 8 AM, 12 PM, and 10 PM (multiple time points are separated by commas):
0 8,12,22 * * *
-
Poll SCM
Polling SCM is to specify a time to scan the local code repository for changes. If there are changes, it triggers the project build.
(1) Trigger remote builds
In the configuration interface of the task Pipeline-demo
, select Build Triggers
- Trigger remote builds (for example, using a script)
, set the custom authentication token to test
, and save the configuration. Access in the browser:
jenkins address/job/Pipeline-demo/build?token=
TOKEN_NAME
http://192.168.1.124:8888/job/Pipeline-demo/build?token=test, and check the task status to see that it has started building.
(2) Trigger after other projects build (Build after other projects are built)
When multiple tasks need to be executed sequentially, this can be used. For example, if you want to execute the freestyle_demo
task first, and then execute Pipeline-demo
, in the configuration interface of the task Pipeline-demo
, select Build Triggers
- Build after other projects are built
, enter freestyle_demo
, and select Trigger only when the build is stable
, and save the configuration. After the freestyle_demo
task is completed, Pipeline-demo
will start building.
(3) Build periodically
In the configuration interface of the task Pipeline-demo
, select Build Triggers
- Build periodically
, set */1 * * * *
(once a minute), save the configuration, and the freestyle_demo
task will build once a minute.
(4) Poll SCM
Polling SCM also requires setting a time period, but unlike building periodically, if there are no changes in the code repository during the time period, the task build will not proceed. For example, in the configuration interface of the task Pipeline-demo
, select Build Triggers
- Poll SCM
, set */1 * * * *
(once a minute), and save the configuration. If the code changes within the next minute, the Pipeline-demo
task will build; otherwise, it will wait until the next minute period after the code changes.
Git hook build trigger (common)#
When there is a code change in GitLab, a build request will be submitted to Jenkins, and Jenkins will trigger the build upon receiving the request.
(1) Install the GitLab plugin and GitLab Hook plugin (the new version comes with the GitLab Hook plugin).
(2) In the configuration interface of the task Pipeline-demo
in Jenkins, select Build Triggers
- Build when a change is pushed to GitLab. GitLab webhook URL: http://192.168.1.124:8888/project/Pipeline-demo
, and the following options will appear in the table, which can be left as default.
Event Type | Trigger Condition |
---|---|
Push Events | Code pushed to branches or tags, including new branch creation. |
Push on Branch Delete | Triggered when a branch is deleted. |
Opened Merge Request | Triggered when a new merge request is created. |
New Commits in MR | Triggered when new commits are pushed to an existing MR (updating MR). |
Accepted (Merged) MR | Triggered when a merge request is merged into the target branch (e.g., main ). |
Closed MR | Triggered when a merge request is closed (not merged). |
(3) In Jenkins, select Manage Jenkins - System - GitLab, uncheck Enable authentication for '/project' end-point
, and save the settings.
(4) In GitLab, select the management center - Settings - Network - Outbound Requests, check Allow requests to the local network from web hooks and services
, and save the configuration.
(5) In the GitLab project repository, select Settings - Integrations, enter the webhook URL, select the default configuration, and save. On the generated Webhook's right side, select Test - Push events, and if it shows Hook executed successfully: HTTP 200
, it is successful.
Parameterized Build#
(1) Create a branch v1 in the source code and modify the branch name in the Jenkinsfile script, then commit the code to GitLab.
Before modification: checkout scmGit(branches: [[name: '*/master']]
After modification: checkout scmGit(branches: [[name: '*/${branch}']]
(2) In the configuration interface of the task Pipeline-demo
in Jenkins, select This project is parameterized
- String Parameter
, with specific settings as shown in the following image.
(3) Save the settings, and in the task Pipeline-demo
interface, select Build with Parameters
, enter the branch name, click Build to perform the build.
Configure Email Server#
(1) Install the Email Extension TemplateVersion plugin.
(2) Select Manage Jenkins - Credentials, click Global
- Add Credentials
, create a password credential for the email server, with the account being the email address and the password being the obtained email authorization code.
(3) Select System
, in Jenkins Location
- System Administrator Email Address
, enter the registered email, and in Extended E-mail Notification
, enter the registered email and port, click Advanced
, select the password credential, check Use SSL
, enter the email suffix in Default user e-mail suffix
, select HTML (text/html)
for Default Content Type
, enter the registered email in Default Recipients
, and input the SMTP server and user default email suffix in the email notification section. Click advanced to complete the information, and check Test the configuration by sending a test email
to test the email server.
(4) Create an email server template
Create an email.html template in the project root directory
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"} - Build Log #${BUILD_NUMBER}</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0"
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
<td>(This email is automatically sent by the program, please do not reply!)</td>
</tr>
<tr>
<td><h2>
<font color="#0000FF">Build Result - ${BUILD_STATUS}</font>
</h2></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">Build Information</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>Project Name : ${PROJECT_NAME}</li>
<li>Build Number : Build #${BUILD_NUMBER}</li>
<li>Trigger Reason: ${CAUSE}</li>
<li>Build Log: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>Build Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>Workspace : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>Project Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
</td>
</tr>
<tr>
<td><b><font color="#0B610B">Changes Since Last
Successful Build:</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>Historical Change Record: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat=" %p"}
</td>
</tr>
<tr>
<td><b>Failed Test Results</b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td><pre
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
<br /></td>
</tr>
<tr>
<td><b><font color="#0B610B">Build Log (Last 100 Lines):</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td><textarea cols="80" rows="30" readonly="readonly"
style="font-family: Courier New">${BUILD_LOG, maxLines=100}</textarea>
</td>
</tr>
</table>
</body>
</html>
(5) Modify the Jenkinsfile file to add a post section at the same level as stages, adding email sending after the build.
pipeline {
agent any
stages {
stage('Pull Code') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/test_war_demo.git']])
}
}
stage('Compile Build') {
steps {
sh 'mvn clean package'
}
}
stage('Publish Project') {
steps {
deploy adapters: [tomcat9(credentialsId: '4d9b76aa-078c-462b-81f1-33fe1d9c971c', path: '', url: 'http://192.168.1.125:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
post {
always {
emailext(
subject: 'Build Notification: ${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}!',
body: '${FILE,path="email.html"}',
to: '[email protected],[email protected]'
)
}
}
}
Install SonarQube#
Integrate SonarQube with Jenkins for code review.
SonarQube 7.9 no longer supports MySQL; SonarQube 7.8 installation supports MySQL >=5.6 && <8.0.
(1) Before installing SonarQube, install MySQL database.
# Configure MySQL 5.7 yum source
vi /etc/yum.repos.d/mysql-community.repo
[mysql-connectors-community]
name=MySQL Connectors Community
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-connectors-community-el7-$basearch/
enabled=1
gpgcheck=1
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
[mysql-tools-community]
name=MySQL Tools Community
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-tools-community-el7-$basearch/
enabled=1
gpgcheck=1
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
[mysql-5.7-community]
name=MySQL 5.7 Community Server
baseurl=https://mirrors.tuna.tsinghua.edu.cn/mysql/yum/mysql-5.7-community-el7-$basearch/
enabled=1
gpgcheck=1
gpgkey=https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
# Install MySQL
yum -y install mysql-server
# Check version
mysql -V
systemctl start mysqld
systemctl enable mysqld
# View MySQL's initial password
grep "password" /var/log/mysqld.log
# MySQL security configuration
mysql_secure_installation
# After following the guide, log in and create a database
mysql -uroot -p
create database sonar;
# View databases
show databases;
(2) Install SonarQube
# Configure system-related parameters
echo "vm.max_map_count=524288
fs.file-max=131072" >> /etc/sysctl.conf
sysctl -p
# Download dependency tools
yum install -y unzip
wget https://binaries.sonarsource.com/Distribution/sonarqube/sonarqube-7.8.zip
mkdir -p /opt/sonar
unzip -q sonarqube-7.8.zip -d /opt/sonar
# Create user
useradd sonar
passwd sonar
# Change SonarQube file permissions
chown -R sonar:sonar /opt/sonar/sonarqube-7.8
(3) Modify the sonar.properties
configuration file in the conf
directory
sonar.jdbc.username=root
sonar.jdbc.password=database_password
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false
(4) Modify the wrapper.conf
in the conf
directory to set the path of jdk-1.8
wrapper.java.command=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412.b08-1.el7_9.x86_64/bin/java
(5) Enter the bin/linux-x86-64/
directory and start SonarQube using the sonar user
su sonar
./sonar.sh start
# View startup logs
tail ../../logs/sonar.log
Log in with the default account, both username and password are admin.
(6) After logging into SonarQube, select Administration
- Security
- Global Permissions
, check Administer System
, Administer
, Execute Analysis
, and Create
permissions for admin. Click the dropdown under the top right avatar, select My Account
- Security
, and fill in the token name to complete the creation of the Token.
Configure Jenkins and SonarQube Integration#
(1) Install the SonarQube Scanner
plugin on Jenkins. After installation, select Manage Jenkins
- Tools
- SonarQube Scanner Installation
, click Add SonarQube Scanner
, enter the name, select version SonarQube Scanner 4.2.0.1873
, and click save.
SonarQube 7.8 corresponds to Sonar-Scanner 4.2
SonarQube 8.9 LTS corresponds to Sonar-Scanner 4.6
(2) Configure SonarQube token credentials in Jenkins. Select the type as Secret text
, enter the token, and click create.
(3) In Jenkins, select System - SonarQube installations, click Add SonarQube
, enter the SonarQube address, select the created token credentials, and save to integrate SonarQube.
Add SonarQube Code Review to FreeStyle Tasks#
In the freestyle_demo
task, select configure - Build Steps, click to add a build step, select Execute SonarQube Scanner
, choose JDK, enter the analysis content, save the configuration, and click Build Now, waiting for the task to complete. Check the code analysis results in SonarQube.
sonar.projectKey=websocketChat
sonar.projectName=websocketChat
sonar.projectVersion=1.0
sonar.sources=.
sonar.java.binaries=./target/classes
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
sonar.sourceEncoding=UTF-8
Add SonarQube Code Review to Pipeline Tasks#
(1) In the project root directory, create a sonar-project.properties file and write the following content.
sonar.projectKey=Pipeline-demo
sonar.projectName=Pipeline-demo
sonar.projectVersion=1.0
sonar.sources=.
sonar.java.binaries=./target/classes
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
sonar.sourceEncoding=UTF-8
(2) In the Jenkinsfile, before the stages, introduce the SonarQube Scanner installed in Jenkins as a preset environment variable, then after the code pulling step, add the code review step.
pipeline {
agent any
environment {
// Introduce the SonarQube Scanner installed in Jenkins
scannerHome = tool 'sonar-scanner-jenkins'
}
stages {
stage('Pull Code') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/test_war_demo.git']])
}
}
stage('Code Review') {
steps {
// Introduce the SonarQube server settings configured in Jenkins
withSonarQubeEnv('SonarQube-jenkins') {
sh '${scannerHome}/bin/sonar-scanner'
}
}
}
stage('Compile Build') {
steps {
sh 'mvn clean package'
}
}
stage('Publish Project') {
steps {
deploy adapters: [tomcat9(credentialsId: '4d9b76aa-078c-462b-81f1-33fe1d9c971c', path: '', url: 'http://192.168.1.125:8080/')], contextPath: null, war: 'target/*.war'
}
}
}
post {
always {
emailext(
subject: 'Build Notification: ${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}!',
body: '${FILE,path="email.html"}',
to: '[email protected]'
)
}
}
}
(3) After completing the code changes, check the code analysis results in SonarQube after the pipeline task is executed.
Application Case#
This application case is referenced from the Bilibili uploader, '' 涣沷 a 靑惷 '', with the original link: https://www.yuque.com/huanfqc/jenkins/jenkins.
Using Jenkins + GitLab + Docker + SonarQube, deploy the front-end and back-end separation project of RuoYi's Spring Boot on 192.168.1.125.
Environment Preparation#
Set up passwordless login for the Jenkins server to 192.168.1.125
ssh-copy-id -i /root/.ssh/id_rsa.pub [email protected]
Install Docker#
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
# Modify image source and default configuration file path
vi /etc/docker/daemon.json
{
"data-root": "/data/dockerData",
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
]
}
# Start Docker
systemctl start docker
systemctl enable docker
Obtain and Modify Source Code Configuration#
(1) Clone the RuoYi project source code to the local machine, and place the ruoyi-ui directory alongside the RuoYi-Vue project.
git clone https://gitee.com/y_project/RuoYi-Vue.git
(2) Modify the vue.config.js
file in the ruoyi-ui
directory, changing localhost
to the IP of the deployment host, which is 192.168.1.125.
# Before modification
const baseUrl = 'http://localhost:8080' // Back-end interface
# After modification
const baseUrl = 'http://192.168.1.125:8080' // Back-end interface
(3) Modify the RuoYi-Vue\ruoyi-admin\src\main\resources\application.yml
file, changing the Redis configuration IP to 192.168.1.125.
# Redis configuration
redis:
# Address
host: 192.168.1.125
(4) Modify the RuoYi-Vue\ruoyi-admin\src\main\resources\application-druid.yml
file, changing the MySQL connection address to 192.168.1.125.
# Main database source
master:
url: jdbc:mysql://192.168.1.125:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
(5) In the ruoyi-ui
directory, create a sonar-project.properties file and write the following content to add SonarQube code review.
sonar.projectKey=ruoyi-ui
sonar.projectName=ruoyi-ui
sonar.projectVersion=1.0
sonar.sources=.
sonar.sourceEncoding=UTF-8
(6) In the ruoyi-ui
directory, create a Jenkinsfile file for the front-end project.
pipeline {
agent any
environment {
// Introduce the SonarQube Scanner installed in Jenkins
scannerHome = tool 'sonar-scanner-jenkins'
}
stages {
stage('Pull Code') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/ruoyi-ui.git']])
}
}
stage('Code Review') {
steps {
// Introduce the SonarQube server settings configured in Jenkins
withSonarQubeEnv('SonarQube-jenkins') {
sh '${scannerHome}/bin/sonar-scanner'
}
}
}
stage('Package and Deploy Website') {
steps {
script {
nodejs(nodeJSInstallationName: 'nodejs14') {
sh '''
npm install
# Build production environment
npm run build:prod
'''
}
// Deploy the build artifacts to the Nginx container mounted directory
sh '''
# Copy the entire dist directory to the mounted directory
scp -r dist 192.168.1.125:/data/ruoyi/nginx/html/
ssh 192.168.1.125 docker restart nginx
'''
}
}
}
}
}
(7) In the RuoYi-Vue
directory, create a sonar-project.properties file and write the following content to add SonarQube code review.
sonar.projectKey=ruoyi-api
sonar.projectName=ruoyi-api
sonar.projectVersion=1.0
sonar.sources=.
sonar.java.binaries=./ruoyi-admin/target/classes
sonar.exclusions=**/test/**,**/target/**
sonar.java.source=1.8
sonar.java.target=1.8
sonar.sourceEncoding=UTF-8
(8) In the RuoYi-Vue
directory, create a Jenkinsfile file for the back-end project.
pipeline {
agent any
environment {
// Introduce the SonarQube Scanner installed in Jenkins
scannerHome = tool 'sonar-scanner-jenkins'
}
stages {
stage('Pull Code') {
steps {
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'fbf87557-40b6-468a-91c5-2cfa1b2e33e8', url: 'http://192.168.1.121:82/test/ruoyi-api.git']])
}
}
stage('Compile Build') {
steps {
sh 'mvn clean package'
}
}
stage('Code Review') {
steps {
// Introduce the SonarQube server settings configured in Jenkins
withSonarQubeEnv('SonarQube-jenkins') {
sh '${scannerHome}/bin/sonar-scanner'
}
}
}
stage('Publish Project') {
steps {
script {
sh '''
ssh 192.168.1.125 "mkdir -p /data/ruoyi-api"
scp ruoyi-admin/target/*.jar 192.168.1.125:/data/ruoyi-api/ruoyi.jar
'''
// Create Dockerfile
sh '''
ssh 192.168.1.125 'cat > /data/ruoyi-api/Dockerfile <<-EOF
FROM openjdk:8
MAINTAINER xie
VOLUME /tmp
ADD ruoyi.jar ruoyi.jar
ENTRYPOINT ["java","-jar","/ruoyi.jar"]
EXPOSE 8080
EOF'
'''
// Build the image
sh '''
ssh 192.168.1.125 "docker build -t ruoyi:1.0 /data/ruoyi-api"
'''
// Stop and remove the existing container
sh '''
EXISTING_CONTAINER=$(ssh 192.168.1.125 "docker ps -a -q -f name=ruoyi")
if [ -n "$EXISTING_CONTAINER" ]; then
echo "Container 'ruoyi' already exists, stopping and removing the old container..."
ssh 192.168.1.125 "docker rm -f $EXISTING_CONTAINER"
fi
'''
// Run the new container
sh '''
ssh 192.168.1.125 "docker run -d --name ruoyi -p 8080:8080 ruoyi:1.0"
'''
}
}
}
}
}
Deploy Required Containers for the Project#
The project requires nginx, mysql, and redis containers, which need to be deployed in advance. The corresponding container versions are nginx:1.18.0, mysql:8.0.19, redis:6.0.8.
(1) Create the required directories
mkdir -p /data/ruoyi
mkdir -p /data/ruoyi/nginx/conf
mkdir -p /data/ruoyi/mysql/db
(2) Create a temporary nginx container and modify the configuration file
docker run --rm -v /data/ruoyi/nginx/conf:/backup nginx:1.18.0 \
sh -c "cp -r /etc/nginx/. /backup"
Modify the default.conf
file in /data/ruoyi/nginx/conf/conf.d
server {
listen 80;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
server_name localhost;
location / {
root /usr/share/nginx/html/dist;
index index.html index.htm;
try_files $uri /index.html;
}
location /prod-api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.1.125:8080/; # Note to change IP
}
if ($request_uri ~ "/actuator") {
return 403;
}
}
(3) Copy the SQL files from RuoYi-Vue\sql
to the /data/ruoyi/mysql/db
directory on the host 192.168.1.125.
(4) Write a yml file to orchestrate and deploy the containers using docker-compose.
# Write the yml file
vi ruoyi.yml
services:
nginx:
image: nginx:1.18.0
container_name: nginx
restart: always
volumes:
- /data/ruoyi/nginx/conf:/etc/nginx
- /data/ruoyi/nginx/logs:/var/log/nginx
- /data/ruoyi/nginx/html:/usr/share/nginx/html
environment:
TZ: "Asia/Shanghai"
ports:
- "80:80"
networks:
ruoyi:
ipv4_address: 172.20.112.11
mysql:
container_name: mysql
image: mysql:8.0.19
restart: always
environment:
MYSQL_ROOT_PASSWORD: "password"
MYSQL_ALLOW_EMPTY_PASSWORD: "no"
MYSQL_DATABASE: "ry-vue"
TZ: "Asia/Shanghai"
ports:
- "3306:3306"
volumes:
- /data/ruoyi/mysql/db:/var/lib/mysql
- /data/ruoyi/mysql/conf:/etc/my.cnf
- /data/ruoyi/mysql/init:/docker-entrypoint-initdb.d
command: --default-authentication-plugin=mysql_native_password
networks:
ruoyi:
ipv4_address: 172.20.112.12
redis:
container_name: redis
image: redis:6.0.8
restart: always
environment:
TZ: "Asia/Shanghai"
ports:
- "6379:6379"
volumes:
- /data/ruoyi/redis/conf:/etc/redis/redis.conf
- /data/ruoyi/redis/data:/data
command: redis-server /etc/redis/redis.conf
networks:
ruoyi:
ipv4_address: 172.20.112.13
networks:
ruoyi:
driver: bridge
ipam:
config:
- subnet: 172.20.112.0/24
(5) Execute the command to create the containers
docker compose -f ruoyi.yml up -d
# Check the container running status
docker ps
# Import the database
docker exec -it mysql bash
mysql -u root -ppassword ry-vue < /var/lib/mysql/ry_20250417.sql
mysql -u root -ppassword ry-vue < /var/lib/mysql/quartz.sql
Upload Code to GitLab#
(1) Create two repositories ruoyi-ui
and ruoyi-api
to store the front-end and back-end code respectively.
(2) In the ruoyi-ui
directory, open cmd and enter the command to upload the code.
git init
git remote add origin http://192.168.1.121:82/test/ruoyi-ui.git
# Add git permission configuration for this directory
git config user.name "test1"
git config user.email "test1@gitlab"
# Continue uploading
git add .
git commit -m "ruoyi-ui"
git push -u origin master
(3) In the RuoYi-Vue
directory, open cmd and enter the command to upload the code.
git init
git remote add origin http://192.168.1.121:82/test/ruoyi-api.git
# Add git permission configuration for this directory
git config user.name "test1"
git config user.email "test1@gitlab"
# Continue uploading
git add .
git commit -m "ruoyi-api"
git push -u origin master
Configure Jenkins Pipeline#
(1) Install Node.js and NodeJS plugin.
Install Node.js on the Jenkins server.
wget https://nodejs.org/dist/latest-fermium/node-v14.21.3-linux-x64.tar.gz
tar -vxzf node-v14.21.3-linux-x64.tar.gz -C /opt
mv /opt/node-v14.21.3-linux-x64 /opt/nodejs
# Configure environment variables
echo "
export NODE_HOME=/opt/nodejs
export PATH=$NODE_HOME/bin:$PATH" >> /etc/profile
# Make variables effective
source /etc/profile
# Check version
node -v
npm -v
# Configure mirror source
npm config set registry https://registry.npmmirror.com
npm config set sass_binary_site=https://npm.taobao.org/mirrors/node-sass
(2) Configure NodeJS settings.
In Manage Jenkins
- Tools
- NodeJS installation, click Add NodeJS
, fill in the name of nodejs as nodejs14
, and enter the installed nodejs path on the server as /opt/nodejs
, then save.
(3) Create a ruoyi-ui
pipeline task, in the pipeline - definition, select Pipeline script from SCM
, SCM select Git
, fill in the ruoyi-ui git repository address and login credentials, keep other options default, and save.
(4) Click Build Now
, wait for the task to complete. Access http://192.168.1.125/
in the browser to check the front-end deployment status.
(5) Create a ruoyi-api
pipeline task, in the pipeline - definition, select Pipeline script from SCM
, SCM select Git
, fill in the ruoyi-api git repository address and login credentials, keep other options default, and save.
(6) Click Build Now
, wait for the task to complete. Access http://192.168.1.125/
in the browser, and you can log in normally, indicating success.
(7) Access SonarQube to view the specific quality review status of the front-end and back-end code.
This knowledge comes from the Bilibili video BV1pF411Y7tq.