🔜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:
- Open-source continuous integration tool developed in Java, supporting continuous integration and continuous deployment.
- Easy installation and configuration: can be installed via yum, or by downloading the war package and quickly deploying through 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 versions 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 the default access port for GitLab
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 the 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 the 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, push; regular developers can grant this permission.
- Maintainer: Can create projects, add tags, protect branches, add project members, edit projects; core developers can grant this permission.
- Owner: Can set project access permissions (Visibility Level), delete projects, migrate projects, manage group members; group leaders can grant this permission.
Upload Project Code#
Use IDEA to create a Java project and upload it to the GitLab repository.
The Java project code used in this article comes from 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 the plugin installation to prepare for reconfiguring the download plugin's domestic source.
(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, choose Available, and wait for the plugin-related files to load.
(2) Enter the plugin directory and change 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, choose 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, choose 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, (new version of Jenkins) select Manage Jenkins - Security, and choose Role-Based Strategy for authorization policy. 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: Use SSH user and key
- Secret file: A text file that needs to be kept confidential; when used, Jenkins will copy the file to a temporary directory and set the file path to a variable. After the build ends, the copied Secret file will be deleted.
- Secret text: An encrypted text string that needs to be saved, such as a DingTalk robot or GitHub API token.
- Certificate: By uploading a certificate file.
Common credential types include: Username with password (user password) and SSH Username with private key (SSH 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 in 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 this 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
in the server to view the private key content. Create an SSH key credential in Jenkins, input 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 where <id>maven-default-http-blocker</id> is located
# <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 input 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 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, for the specific process of building the war package, refer to 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 figure below.
(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 figure below.
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 is difficult to complete with a single task.
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 the Jenkins Web UI; or you can create a Jenkinsfile script file and place it in the project source code repository (generally, we recommend loading the Jenkinsfile Pipeline directly from source code control (SCM) in Jenkins).
Create Pipeline Script in Jenkins Web UI to Publish Project#
(1) Install the Pipeline plugin.
(2) Create a new task Pipeline-demo
, using declarative syntax, create a Pipeline script in the Jenkins Web UI; implement pulling code, compiling and building, to publishing the project.
In the configuration interface of Pipeline-demo
, select Build Trigger - Pipeline, choose a script template Hello World.
Click Pipeline Syntax
, in the snippet generator, select checkout: Check out from version control
, follow the guide to fill in the project address and credentials, generate the pipeline script, and paste the code pulling script into the modified template.
In the snippet generator, select sh: Shell Script
, fill in the compile command, generate the pipeline script, and paste the script into the modified template.
In the snippet generator, select deploy: Deploy war/ear to a container
, follow the guide to fill in, generate the pipeline script, 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 Project#
(1) In the project directory in IDEA, select New - File, create a Jenkinsfile, 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 Trigger - Pipeline, define the content to choose 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 are built (Build after other projects are built)
-
Scheduled builds (Build periodically)
The scheduled string from left to right represents: minute hour day month week
Examples of scheduled 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 separated by commas):
0 8,12,22 * * *
-
Poll SCM (Poll SCM)
Polling SCM specifies 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 scripts)
, 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, return to check the task status has started building.
(2) Trigger after other projects are built (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, 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, freestyle_demo will start building.
(3) Scheduled builds (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 every minute.
(4) Poll SCM (Poll SCM)
Polling SCM also needs to set a time period, but unlike scheduled builds, 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 (Commonly Used)#
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, with the default selection being fine.
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 (updates 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 - integration, input the webhook URL, select the default configuration, and save. In the generated Webhook, select Test - Push events, and display Hook executed successfully: HTTP 200
, indicating success.
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 figure below.
(3) Save the settings, in the task Pipeline-demo
interface, select Build with Parameters
, input 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 email server password credentials, 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
, input the registered email, in Extended E-mail Notification
, input the registered email and port, click Advanced
, select password credentials, check Use SSL
, in Default user e-mail suffix
, input the email suffix, Default Content Type
select HTML (text/html)
, Default Recipients
input the registered email, and in the email notification section, input the SMTP server and user default email suffix, click advanced to complete the information, and check Test configuration by sending a test email
to test the email server.
(4) Create 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 Log: <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 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 the 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
# Configure MySQL security
mysql_secure_installation
# After completing the guided configuration, 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 avatar in the upper right corner, select My Account
- Security
, and fill in the token name arbitrarily 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
, input 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 type as Secret text
, input the token, and click create.
(3) In Jenkins, select System - SonarQube installations, click Add SonarQube
, input 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 build steps, select Execute SonarQube Scanner
, select JDK, input 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 a step for code review.
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 execution.
Application Case#
This application case is referenced from 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 separated project of Ruoyi on 192.168.1.125.
Environment Preparation#
Set up Jenkins server for passwordless login 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' // Backend interface
# After modification
const baseUrl = 'http://192.168.1.125:8080' // Backend interface
(3) Modify the application.yml
file in RuoYi-Vue\ruoyi-admin\src\main\resources
to change the Redis configuration IP to 192.168.1.125.
# Redis configuration
redis:
# Address
host: 192.168.1.125
(4) Modify the application-druid.yml
file in RuoYi-Vue\ruoyi-admin\src\main\resources
to change the MySQL connection address to 192.168.1.125.
# Main database data 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 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 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 image
sh '''
ssh 192.168.1.125 "docker build -t ruoyi:1.0 /data/ruoyi-api"
'''
// Stop and remove existing containers
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 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#
This 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 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 192.168.1.125
host's /data/ruoyi/mysql/db
directory.
(4) Write a yml file to orchestrate and deploy containers using docker compose.
# Write 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 containers
docker compose -f ruoyi.yml up -d
# Check container running status
docker ps
# Import 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 input the command to upload 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 to upload
git add .
git commit -m "ruoyi-ui"
git push -u origin master
(3) In the RuoYi-Vue
directory, open cmd and input the command to upload 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 to upload
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
, set the name of Node.js to nodejs14
, input the installed Node.js path /opt/nodejs
, and save the application.
(3) Create a ruoyi-ui
pipeline task, in 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 the application.
(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 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 the application.
(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 Bilibili video BV1pF411Y7tq