CICD 实现
基于容器化构建和打包
主机 | 服务 | 描述 |
---|---|---|
jenkins | jenkins、java、docker | |
nexus | nexus、docker部署、制品库 | |
sonarqube | 代码扫描、docker部署 |
jenkins 主机
1、容器部署
# 一键安装docker脚本
curl -L https://gitea.beyourself.org.cn/newrain001/shell-project/raw/branch/master/os/get-docker-latest.sh | sh
2、jenkins部署
所需安装插件
blue ocean
maven
nexus 主机
1、容器部署
# 一键安装docker脚本
curl -L https://gitea.beyourself.org.cn/newrain001/shell-project/raw/branch/master/os/get-docker-latest.sh | sh
2、nexus 配置
[root@10 opt]# mkdir /opt/nexus
[root@10 opt]# cd /opt/nexus/
[root@10 opt]# vim docker-compose.yml
services:
nexus:
image: sonatype/nexus3
container_name: nexus
ports:
- "8081:8081"
environment:
INSTALL4J_ADD_VM_PARAMS: "-Xms512m -Xmx512m -XX:MaxDirectMemorySize=512m"
volumes:
- nexus-data:/nexus-data
- ./nexus-data:/nexus-data
restart: always
nginx_proxy:
image: nginx
container_name: nexus_proxy
ports:
- "80:80"
volumes:
- ./nexus-proxy/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- nexus
restart: always
#volumes:
# nexus-data:
# driver: local
[root@10 nexus]# mkdir nexus-proxy
[root@10 nexus]# vim nexus-proxy/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
server {
listen 80;
client_max_body_size 2G;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_buffering on;
proxy_read_timeout 120s;
proxy_send_timeout 30s;
proxy_connect_timeout 90s;
location / {
proxy_pass http://10.36.176.138:8081; # 本机外部地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
[root@10 nexus]# chmod -R 777 .
[root@10 nexus]# docker compose up
sonarqube 主机
1、容器部署
# 一键安装docker脚本
curl -L https://gitea.beyourself.org.cn/newrain001/shell-project/raw/branch/master/os/get-docker-latest.sh | sh
2、sonarqube配置
[root@10 ~]# mkdir /opt/sonarqube/
[root@10 ~]# cd /opt/sonarqube/
[root@10 sonarqube]# vim /etc/security/limits.conf
* soft nofile 131072
* hard nofile 131072
* soft nproc 10240
* hard nproc 10240
[root@10 sonarqube]# vim /etc/sysctl.conf
net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward=1
vm.max_map_count=524288
fs.file-max=131072
[root@10 sonarqube]# docker compose up
jenkinsfile
pipeline {
agent any
parameters {
string(name: 'PROJECT_VERSION', defaultValue: '3.8.0', description: '构建版本')
string(name: 'SONARQUBE_URL', defaultValue: 'http://10.36.176.138:19000', description: '代码扫描服务器地址')
string(name: 'SONARQUBE_CREDENTIALS', defaultValue: 'sqa_7377e33cbcd69873afab1316314169c8471dde04', description: '代码扫描私钥')
string(name: 'PROJECT_KEY', defaultValue: 'ruoyi', description: '项目唯一标识')
string(name: 'NEXUS_URL', defaultValue: 'maven', description: '制品仓库')
}
environment {
NEXUS_CREDENTIALS_ID = '123456'
GROUP_ID = 'com.ruoyi'
ARTIFACT_ID = 'ruoyi'
}
stages {
stage('后端打包') {
steps {
withCredentials([usernamePassword(credentialsId: "123456", usernameVariable: 'NEXUS_USERNAME', passwordVariable: 'NEXUS_PASSWORD')]) {
withDockerContainer(args: '-v /root/.m2:/root/.m2', image: 'maven:3.8.8-sapmachine-11') {
sh """
mvn package
mvn deploy:deploy-file \
-DgroupId=com.ruoyi \
-DartifactId=ruoyi \
-Dversion=${params.PROJECT_VERSION} \
-Dpackaging=jar \
-Dfile=ruoyi-admin/target/ruoyi-admin.jar \
-DrepositoryId=nexus \
-Durl=http://${NEXUS_USERNAME}:${NEXUS_PASSWORD}@10.36.176.138/repository/${params.NEXUS_URL}/
"""
}
}
}
}
stage('前端打包') {
steps {
withDockerContainer(args: '-v /opt/node_modules:/root/.jenkins/workspace/pipeline/node_modules', image: 'node:18.20.3-alpine3.20') {
sh """
cd ruoyi-ui
npm install --registry http://registry.npmmirror.com
npm run build:prod
"""
}
}
}
stage('代码扫描') {
steps {
withDockerContainer(image: 'sonarsource/sonar-scanner-cli') {
sh """
sonar-scanner \
-Dsonar.projectKey=${params.PROJECT_KEY} \
-Dsonar.projectName=${params.PROJECT_KEY} \
-Dsonar.projectVersion=${params.PROJECT_VERSION} \
-Dsonar.sources=. \
-Dsonar.host.url=${params.SONARQUBE_URL} \
-Dsonar.login=${params.SONARQUBE_CREDENTIALS} \
-Dsonar.java.binaries=.
"""
}
}
}
}
post {
always {
emailext (
subject: '项目 【$PROJECT_NAME】 第【$BUILD_NUMBER】次构建 - $BUILD_STATUS!',
body: '''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${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">
<h3>本邮件由系统自动发出,请勿回复!</h3>
<tr>
<br/>
各位同事,大家好,以下为${PROJECT_NAME }项目构建信息</br>
<td><font color="#CC0000">构建结果 - ${BUILD_STATUS}</font></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>项目名称 : ${PROJECT_NAME}</li>
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
<li>触发原因: ${CAUSE}</li>
<li>构建状态: ${BUILD_STATUS}</li>
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
<h4><font color="#0B610B">最近提交</font></h4>
<ul>
<hr size="2" width="100%" />
${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
</ul>
详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/>
</td>
</tr>
</table>
</body>
</html>
''',
to: '1161733918@qq.com',
attachLog: true
)
}
}
}
详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/>
</td>
</tr>
</table>
''', to: '1161733918@qq.com', attachLog: true ) } } } ```