CICD持续部署 Jenkins 部署

2024-08-30 654 0

Docker 部署

加速源

sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    -i.bak  /etc/yum.repos.d/rocky-*.repo
dnf makecache
setenforce 0
sed -i 's#^SELINUX=.*#SELINUX=disabled#' /etc/sysconfig/selinux
systemctl stop firewalld

部署Docker

curl -o /etc/yum.repos.d/docker-ce.repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
dnf install docker-ce

Gitlab 部署

部署GitLab

# cat docker-compose.yaml 
version: '3.6'
services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab
    restart: always
    hostname: 'gitlab'
    environment:
      TZ: 'Asia/Shanghai'
      GITLAB_OMNIBUS_CONFIG: |
        # Add any other gitlab.rb configuration here, each on its own line
        external_url 'http://git.sundayhk.com'
        gitlab_rails['gitlab_shell_ssh_port'] = 8022
        #nginx['listen_port'] = 80
        nginx['client_max_body_size'] = '2048m'
        gitlab_rails['smtp_enable'] = true
        gitlab_rails['smtp_address'] = "smtp.qq.com"
        gitlab_rails['smtp_port'] = 465
        gitlab_rails['smtp_user_name'] = "sundayle@qq.com"
        gitlab_rails['smtp_password'] = "bdoowbhvqywydaeh"
        gitlab_rails['smtp_domain'] = "smtp.qq.com"
        gitlab_rails['smtp_authentication'] = "login"
        gitlab_rails['smtp_enable_starttls_auto'] = false
        gitlab_rails['smtp_tls'] = true
        gitlab_rails['gitlab_email_enabled'] = true
        gitlab_rails['gitlab_email_from'] = 'sundayle@qq.com'
        #gitlab_rails['openssl_verify_mode'] = false
        #gitlab_rails['smtp_openssl_verify_mode'] = 'none'
    ports:
      - '80:80'
      - '8443:443'
      - '8022:22' # SSH端口宿主机已占用,这里映射其他端口
    volumes:
      - '/data/app_data/gitlab/config:/etc/gitlab'
      - '/data/app_data/gitlab/logs:/var/log/gitlab'
      - '/data/app_data/gitlab/data:/var/opt/gitlab'
    shm_size: '256m'
[root@gitlab ~]# docker compose up -d

获取gitlab root默认密码

[root@gitlab ~]# docker exec gitlab cat /etc/gitlab/initial_root_password | grep ^Password
Password: UCc6hQKMurkvNllkBamAkS+7DCDGxxxxxxxxx=

访问 http://git.sundayhk.com/
使用root和密码登陆

关闭注册 (帐号通过管理员添加)

image-20240727174406722

禁用 Gravatar

image-20240727174031413

邮件配置及测试

上面通过docker-compose.yaml 配置ENV Gitlab邮件相关变量,已经实现邮件配置。

这里也可以直接编辑容器内的gitlab.rb文件实现

[root@gitlab ~]# docker exec -it gitlab bash
root@gitlab:/# vi /etc/gitlab/gitlab.rb

gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "sundayhk@qq.com"
gitlab_rails['smtp_password'] = "bdoowbxxxxxxxxxxxxxx" # 授权码
gitlab_rails['smtp_domain'] = "smtp.qq.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = false
gitlab_rails['smtp_tls'] = true
# gitlab_rails['smtp_pool'] = false

gitlab_rails['gitlab_email_enabled'] = true
gitlab_rails['gitlab_email_from'] = 'sundayhk@qq.com'

每次修改都要重新生成配置文件及重启服务

# gitlab-rake gitlab:check
gitlab-ctl reconfigure
gitlab-ctl restart

邮件测试

root@gitlab:/# gitlab-rails console
--------------------------------------------------------------------------------
 Ruby:         ruby 3.1.5p253 (2024-04-023 revision 1945f8dc0e) [x86_64-linux]
 GitLab:       17.2.1 (b30193cc04c) FOSS
 GitLab Shell: 14.37.0
 PostgreSQL:   14.11
------------------------------------------------------------[ booted in 59.20s ]
=> #<Mail::Message:513100, Multipart: false, Headers: <Date: Sat, 27 Jul 2024 13:45:40 +0000>, <From: GitLab <sundayle@qq.com>>, <Reply-To: GitLab <noreply@git.sundayhk.com>>, <To: shaopenghk@qq.com>, <Message-ID: <66a4fa04941de_11ef2ff8446b4@gitlab.mail>>, <Subject: test>, <Mime-Version: 1.0>, <Content-Type: text/html; charset=US-ASCII>, <Content-Transfer-Encoding: 7bit>, <Auto-Submitted: auto-generated>, <X-Auto-Response-Suppress: All>>
irb(main):012:0> 

配置邮件后 添加新用户 则会发邮件 通过链接设置用户密码
image-20240727220754262

Gitlab备份

手动备份

[root@gitlab ~]# docker exec gitlab gitlab-rake gitlab:backup:create

[root@gitlab ~]# docker exec gitlab ls /var/opt/gitlab/backups/
1722090118_2024_07_27_17.2.1_gitlab_backup.tar

宿主机定时备份任务

[root@gitlab ~]# crontab -e

# m h  dom mon dow   command
# gitlab backup 
00 02 * * * /data/shell/gitlab_backup.sh > /dev/null 2>&1

备份脚本

[root@gitlab ~]#  vim /data/shell/gitlab_backup.sh

#!/bin/bash
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

docker exec gitlab gitlab-rake gitlab:backup:create

Gitlab恢复

[root@gitlab ~]# docker exec -it gitlab bash

# 停止相关数据连接服务
root@gitlab:/# gitlab-ctl stop unicorn
root@gitlab:/# gitlab-ctl stop sidekiq
root@gitlab:/# cd /var/opt/gitlab/backups
root@gitlab:/var/opt/gitlab/backups# ls -l
total 1000
-rw-------. 1 git git 512000 Jul 27 22:22 1722090118_2024_07_27_17.2.1_gitlab_backup.tar

root@gitlab:/var/opt/gitlab/backups# gitlab-rake gitlab:backup:restore
BACKUP=1722090118_2024_07_27_17.2.1

# 启动Gitlab
root@gitlab:/var/opt/gitlab/backups# gitlab-ctl start

SonarQube Docker部署

宿主机参数配置

配置内核参数

 echo vm.max_map_count=524288 >> /etc/sysctl.conf
 echo fs.file-max=131072  >> /etc/sysctl.conf
 sysctl -p

配置安全限制 (重新登陆终端生效)

echo "* soft nofile 131072" >>  /etc/security/limits.conf 
echo "* hard nofile 131072 " >>  /etc/security/limits.conf 
[root@jenkins ~]# mkdir -p /data/docker_yaml/sonarqube/
# cat /data/docker_yaml/sonarqube/docker-compose.yaml

version: "3"
services:
  postgres:
    image: postgres
    container_name: postgres
    restart: unless-stopped
    ports:
      - 5432:5432
    networks:
      - sonarnet
    environment:
      POSTGRES_DB: sonar
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
    volumes:
      - ./data/postgresql:/var/lib/postgresql

  sonarqube:
    image: sonarqube:9.9.6-community
    container_name: sonarqube
    restart: unless-stopped
    ports:
      - "9000:9000"
    depends_on:
      - db
    networks:
      - sonarnet
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    volumes:
      - ./data/sonarqube/data:/opt/sonarqube/data
      - ./data/sonarqube/extensions:/opt/sonarqube/extensions
      - ./data/sonarqube/logs:/opt/sonarqube/logs

networks:
  sonarnet:
    driver: bridge

挂载因权限问题需要修改用户权限再重新启动

[root@jenkins sonarqube]# docker compose up -d
[root@jenkins sonarqube]# chown -R 999:999 ./data/postgresql/
[root@jenkins sonarqube]# chown -R 1000:1000 ./data/sonarqube/
[root@jenkins sonarqube]# docker compose down
[root@jenkins sonarqube]# docker compose up -d

启动容器后观察日志是否正常启动

[root@jenkins sonarqube]# docker compose logs -f
# 看到如下内容代表启动成功
2024.08.26 07:03:33 INFO  ce[][o.s.p.ProcessEntryPoint] Starting Compute Engine
2024.08.26 07:03:33 INFO  ce[][o.s.ce.app.CeServer] Compute Engine starting up...
2024.08.26 07:03:34 INFO  ce[][o.sonar.db.Database] Create JDBC data source for jdbc:postgresql://db:5432/sonar
2024.08.26 07:03:34 INFO  ce[][c.z.h.HikariDataSource] HikariPool-1 - Starting...
2024.08.26 07:03:35 INFO  ce[][c.z.h.p.HikariPool] HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@62138e8d
2024.08.26 07:03:35 INFO  ce[][c.z.h.HikariDataSource] HikariPool-1 - Start completed.
2024.08.26 07:03:37 INFO  ce[][o.s.s.p.ServerFileSystemImpl] SonarQube home: /opt/sonarqube
2024.08.26 07:03:37 INFO  ce[][o.s.c.c.CePluginRepository] Load plugins
2024.08.26 07:03:41 INFO  ce[][o.s.c.c.ComputeEngineContainerImpl] Running Community edition
2024.08.26 07:03:41 INFO  ce[][o.s.ce.app.CeServer] Compute Engine is started
2024.08.26 07:03:42 INFO  app[][o.s.a.SchedulerImpl] Process[ce] is up
2024.08.26 07:03:42 INFO  app[][o.s.a.SchedulerImpl] SonarQube is operational

正常启动后在浏览器打开http://ip:9090, 用户名密码默认admin
这里启动有点慢,耐心等待

image.png

image.png

安装中文
image.png

重启SonarQube 生效
image.png

注意:SonarQube根据浏览器的header选择显示的语言,如果安装中文插件重启后还是显示英文,一般是因为浏览器选择了英文。需将中文置顶。

image.png

image.png

Maven安装

测试使用 选择性安装

安装 JDK 17

该版本兼容Maven和SonarQube
https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html

[root@jenkins ~]# wget https://download.oracle.com/java/17/archive/jdk-17.0.7_linux-x64_bin.tar.gz
[root@jenkins ~]# tar xf jdk-17.0.7_linux-x64_bin.tar.gz
[root@jenkins ~]# jdk-17.0.11 /usr/local/jdk

配置JDK环境变量

[root@jenkins ~]# cat > /etc/profile.d/jdk.sh << \EOF
# set oracle jdk environment
export JAVA_HOME=/usr/local/jdk
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
EOF

[root@jenkins ~]# source /etc/profile.d/jdk.sh

查看JDK版本

[root@jenkins ~]# java -version
java version "17.0.11" 2024-04-16 LTS
Java(TM) SE Runtime Environment (build 17.0.11+7-LTS-207)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.11+7-LTS-207, mixed mode, sharing)

安装Maven

[root@jenkins ~]# wget https://dlcdn.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz
[root@jenkins ~]# tar xf apache-maven-3.8.8-bin.tar.gz 
[root@jenkins ~]# mv apache-maven-3.8.8 /usr/local/maven

配置Maven环境变量

[root@jenkins ~]# cat > /etc/profile.d/maven.sh << \EOF
export JAVA_HOME=/usr/local/jdk
export MAVEN_HOME=/usr/local/maven
export PATH=${MAVEN_HOME}/bin:${JAVA_HOME}/bin:$PATH
EOF

查看Maven版本信息

[root@jenkins ~]# source /etc/profile.d/maven.sh
[root@jenkins ~]# mvn -v
Apache Maven 3.8.8 (4c87b05d9aedce574290d1acc98575ed5eb6cd39)
Maven home: /usr/local/maven
Java version: 17.0.11, vendor: Oracle Corporation, runtime: /usr/local/jdk
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "5.14.0-362.8.1.el9_3.x86_64", arch: "amd64", family: "unix"

配置Maven镜像加速

[root@jenkins ~]# vim /usr/local/maven/conf/settings.xml

  <mirrors>
    <mirror>
      <id>alimaven</id>
       <name>aliyun maven</name>
       <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
       <mirrorOf>central</mirrorOf>
    </mirror>

  </mirrors>

  <profiles>

    <profile>
        <id>jdk-1.8</id>
        <activation>
            <activeByDefault>true</activeByDefault>
            <jdk>1.8</jdk>
        </activation>
        <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
        </properties>    
    </profile>

  </profiles>

SonarQube 使用

SonarQube的使用方式很多,Maven可以整合,也可以采用sonar-scanner的方式,再查看Sonar Qube的检测效果

Maven实现代码检测

maven/conf/settings.xml 配置sonarqube

<profile>
    <id>sonar</id>
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
        <sonar.login>admin</sonar.login>
        <sonar.password>123456789</sonar.password>
        <sonar.host.url>http://192.168.77.17:9000</sonar.host.url>
    </properties>
</profile>

项目代码

git clone https://github.com/sundayhk/spring-boot-hello-world.git
cd spring-boot-hello-word

项目代码 pod.xml 添加插件 (这里已经添加了)

<plugin>
    <groupId>org.sonarsource.scanner.maven</groupId>
    <artifactId>sonar-maven-plugin</artifactId>
</plugin>

在项目代码位置执行命令:

mvn package
mvn sonar:sonar

image.png

image.png

SonarScanner使用

SonarQube配置令牌

image.png
复制生成的令牌 squ_cc848f66bf8b0da638e7e87cef3e53777775d85d

sonar-scanner安装

https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/#running-from-zip-file

[root@jenkins ~]# wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.1.0.4477-linux-x64.zip
[root@jenkins ~]# unzip sonar-scanner-cli-6.1.0.4477-linux-x64.zip
[root@jenkins ~]# mv sonar-scanner-cli-6.1.0.4477-linux-x64 /usr/local/sonar-scanner

sonar-scanner配置文件

[root@jenkins ~]# vim /usr/local/sonar-scanner/conf/sonar-scanner.properties 
# Configure here general information about the environment, such as the server connection details for example
# No information about specific project should appear here

#----- SonarQube server URL (default to SonarCloud)
sonar.host.url=http://192.168.77.16:9000

#sonar.scanner.proxyHost=myproxy.mycompany.com
#sonar.scanner.proxyPort=8002
sonar.sourceEncoding=UTF-8

sonar-scanner代码检测

[root@jenkins ~]# git clone https://github.com/sundayhk/spring-boot-hello-world.git
[root@jenkins ~]# cd spring-boot-hello-world
[root@jenkins spring-boot-hello-world]# ls
docker-compose.yaml  Dockerfile  pom.xml  README.md  src  target
[root@jenkins spring-boot-hello-world]# mvn package
[root@jenkins spring-boot-hello-world]# /usr/local/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=spring-boot-hello-world -Dsonar.projectKey=java -Dsonar.java.binaries=target/ -Dsonar.login=squ_cc848f66bf8b0da638e7e87cef3e53777775d85d
...
01:35:18.458 INFO  ANALYSIS SUCCESSFUL, you can find the results at: http://192.168.77.16:9000/dashboard?id=spring-boot-hello-world
01:35:18.458 INFO  Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
01:35:18.460 INFO  More about the report processing at http://192.168.77.16:9000/api/ce/task?id=AZG2YVeR2fyEPGXMqRUB
01:35:18.482 INFO  Analysis total time: 10.707 s
01:35:18.485 INFO  EXECUTION SUCCESS
01:35:18.486 INFO  Total time: 13.401s

image.png

Jenkins 自由风格部署

Jenkins配置

代码拉取到Jenkins本地后,需要在Jenkins中对代码进行构建,这里需要Maven的环境,而Maven需要Java的环境,接下来需要在Jenkins中安装JDK和Maven,并且配置到Jenkins服务。

[root@jenkins ~]# docker pull jenkins/jenkins:lts
[root@jenkins ~]# mkdir -p /data/docker_yaml/jenkins
[root@jenkins jenkins]# cd /data/docker_yaml/jenkins

Jenkins容器内JDK版本为17 (/opt/java/openjdk),若需要指定版本则需安装或挂载
这里使用JDK11

[root@jenkins jenkins]# wget https://aka.ms/download-jdk/microsoft-jdk-11.0.24-linux-x64.tar.gz
[root@jenkins jenkins]# tar xf microsoft-jdk-11.0.24-linux-x64.tar.gz

Jenkins容器内Maven准备,JAVA项目构建使用

[root@jenkins jenkins]# wget https://dlcdn.apache.org/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz
[root@jenkins jenkins]# tar xf apache-maven-3.8.8-bin.tar.gz

中央仓库加速

[root@jenkins jenkins]# vim ./apache-maven-3.8.8/conf/settings.xml 

<mirrors>
    <!-- 阿里云加速--!>
    <mirror>
      <id>alimaven</id>
       <name>aliyun maven</name>
       <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
       <mirrorOf>central</mirrorOf>
    </mirror>

  </mirrors>

复制前面配置的sonar-scanner目录

[root@jenkins jenkins]# cp -r /usr/local/sonar-scanner .
# vim /data/docker_yaml/jenkins/docker-compose.yaml

version: "3"
services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    restart: on-failure
    environment:
      TZ: Asia/Shanghai
    ports:
      - 8080:8080
      - 50000:50000
    volumes:
      - ./data/jenkins_home:/var/jenkins_home
      - ./apache-maven-3.8.8:/usr/local/maven
      - ./jdk-11.0.24+8:/usr/local/jdk
      - ./sonar-scanner:/usr/local/sonar-scanner
[root@jenkins jenkins]# mkdir -p ./data/jenkins_home
[root@jenkins jenkins]# chown 1000:1000 ./data/jenkins_home
[root@jenkins jenkins]# docker compose up -d

查看jenkins密钥

[root@jenkins jenkins]# docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword
# 或查看日志
[root@jenkins jenkins]# docker compose logs
...
jenkins  | 
jenkins  | e531c57c3e6e47f4a8b055ee608ad51c
jenkins  | 
jenkins  | This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

修改jenkins更新源

Jenkins安装过程需要下载插件,但是默认下载地址下载速度较慢,需要更新下载地址为国内镜像站
如华为云源加速
https://www.jenkins-zh.cn/tutorial/management/mirror/

直接在物理机修改数据卷文件

[root@jenkins jenkins]# vim /data/app_data/jenkins_home/hudson.model.UpdateCenter.xml 

<?xml version='1.1' encoding='UTF-8'?>
<sites>
  <site>
    <id>default</id>
    <url>https://mirrors.huaweicloud.com/jenkins/updates/update-center.json</url>
  </site>
</sites>

修改后 重启下Jenkins容器

[root@jenkins jenkins]# docker compose restart

访问:http:///IP:8080
输入密钥

image.png

选择第二个
image.png

默认
image.png

image.png

image.png

安装插件

中文插件 新版翻译不全,但够用 安装过locale插件 zh_cn设置无效,zh_tw则正常

  • Localization: Chinese(Simplified)

image.png

需要重启才生效
浏览器访问: http://192.168.77.16:8080/restart
注:若Docker部署没指定重启策略(默认no), 不会自动拉起容器,此时执行 浏览器重启jenkins,则容器状态是退出状态,需手动启动容器或指定重启策略为 always、on-failure、unless-stopped,容器内重启jenkins才会自动重启容器

  • Git Parameter
  • Publish Over SSH

image.png

  • Gitlab SSH 密钥

生成SSH密钥对

[root@jenkins ~]# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:pT7dOlOcFLxGQbwovGzKxQ2X+UxfFy3vee12ng999vI root@jenkins
The key's randomart image is:
...
[root@jenkins ~]# ls -l .ssh/
total 12
-rw-------. 1 root root 2602 Aug 31 03:23 id_rsa
-rw-r--r--. 1 root root  566 Aug 31 03:23 id_rsa.pub
-rw-r--r--. 1 root root   92 Aug 28 01:48 known_hosts

Gitlab 添加SSH密钥 粘贴 id_rsa.pub 内容

image.png

Jenkins 全局凭据 添加 Gitlab SSH密钥

image.png

Gitlab 创建 Access Token (到期时间限制最长为一年)
image.png

系统管理-系统配置 找到Gitlab
image.png

image.png

添加后 选中 保存
image.png

系统管理-全局工具配置

JDK配置
image.png

Maven配置
image.png

image.png

项目部署

这里先构建自由风格的软件项目,方便入门,后续主要使用流水线,其实都挺简单。

java项目:https://github.com/sundayhk/spring-boot-hello-world
image.png

image.png

前面已经配置了Gitlab SSH 密钥

image-20240831221136287

增加构建步骤
image.png
image.png

构建测试

配置好了 点击 立即构建

查看最近一次构建
image.png

查看控制台输出 拉到最底部 查看构建结果
image.png

构建Success
image.png

进入Jenkins目录 可以看到targetr下打包好的 spring-boo-hello-world-1.0.2.jar

[root@jenkins ~]# docker exec -it jenkins bash
jenkins@e95cee752a96:/$ ls -l /var/jenkins_home/workspace/spring-boot-hello-world/target/
total 17408
drwxr-xr-x. 3 jenkins jenkins       47 Sep  1 11:39 classes
drwxr-xr-x. 3 jenkins jenkins       25 Sep  1 11:39 generated-sources
drwxr-xr-x. 3 jenkins jenkins       30 Sep  1 11:39 generated-test-sources
drwxr-xr-x. 2 jenkins jenkins       28 Sep  1 11:40 maven-archiver
drwxr-xr-x. 3 jenkins jenkins       35 Sep  1 11:39 maven-status
-rw-r--r--. 1 jenkins jenkins 17813960 Sep  1 11:41 spring-boot-hello-world-1.0.2.jar
-rw-r--r--. 1 jenkins jenkins     3589 Sep  1 11:40 spring-boot-hello-world-1.0.2.jar.original
drwxr-xr-x. 2 jenkins jenkins     4096 Sep  1 11:40 surefire-reports
drwxr-xr-x. 3 jenkins jenkins       17 Sep  1 11:39 test-classes

持续集成Publish Over SSH

插件:Publish Over SSH

Jenkins拉取GitLab的SpringBoot代码进行构建发布到测试环境实现持续集成

配置Publish Over SSH,将构建好的JAR包,传输到测试或生产服务器,进行Docker自动部署运行

系统管理-系统配置-Publish over SSH
配置测试服务器 强烈建议使用密钥
image.png

Docker文件

# cat Dockerfile 

FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
# docker-compose.yaml
version: "3.8"
services:
  spring-boot-hello-world:
    build: 
      context: ./
      #dockerfile: Dockerfile
      #args:
      #  - JAR_FILE=target/*.jar
    image: spring-boot-hello-world:v1.0.0
    container_name: spring-boot-hello-world
    ports:
      - 8888:8080

Jenkins构建后操作脚本命令

image.png

持续集成SonarQube

插件:SonarQube Scanner

Sonar Qube 开启权限验证
image.png

Sonar Qube 配置令牌

image.png

Jenkins 全局凭据 配置SonarQube Token
image.png

SonarQube Token 凭据需提前创建
image.png

Jenkins 配置sonar-scanner
image.png

配置项目工程
image.png

Analysis properties

sonar.projectname=${JOB_NAME}
sonar.projectKey=${JOB_NAME}
sonar.source=./
sonar.java.binaries=target/

点击构建

控制台输出结果

[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  8.187 s
[INFO] Finished at: 2024-09-03T14:11:11+08:00
[INFO] ------------------------------------------------------------------------
SSH: Connecting from host [5d78ad8df758]
SSH: Connecting with configuration [TestServer] ...
SSH: EXEC: completed after 19,418 ms
SSH: Disconnecting configuration [TestServer] ...
SSH: Transferred 4 file(s)
Finished: SUCCESS

image.png

持续交付Git Parameter

插件:Git Parameter

基于Git Parameter 选取指定的发行版本构建任务,交付发布到目标服务器

配置工程
添加Git参数

image.png

构建步骤

删除之前配置的调用顶层Maven目标,添加执行Shell

image.png

image.png

cd ${WORKSPACE}
git checkout $release
rm -rf target/*
/usr/local/maven/bin/mvn package -DskipTests

修改代码 打下tag

[root@jenkins spring-boot-hello-world]# vim src/main/java/com/example/helloworld/controller/HelloWorldController.java

package com.example.helloworld.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {

    @GetMapping("/")
    public String sendGreetings() {
        return "Hello World! V1.0.0"; // 修改
    }
}

修改内容并打标签

[root@jenkins spring-boot-hello-world]#  git commit -m 'update release to v1.0.0'

[root@jenkins spring-boot-hello-world]# git tag v1.0.0
[root@jenkins spring-boot-hello-world]# git push origin v1.0.0
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
To ssh://git.sundayhk.com:8022/zsp/spring-boot-hello-world.git
 * [new tag]         v1.0.0 -> v1.0.0

image.png

构建任务成功 查看

[root@jenkins spring-boot-hello-world]# curl 192.168.77.16:8888
Hello World! V1.0.0

推送镜像仓库

Jenkins容器使用宿主机Docker

构建镜像和发布镜像到harbor都需要使用到docker命令。而在Jenkins容器内部安装Docker官方推荐直接采用宿主机带的Docker即可。

若宿主机Docker是用root启动的,而 Jenkins容器 默认用户是 jenkins,id 和 group 都是 1000(官方容器默认的值),这种情况在容器中就无法正常写入文件到宿主机,会报Permission denied

设置宿主机docker.sock权限:

chown 1000:1000 /var/run/docker.sock
# 或
chmod 666 /var/run/docker.sock

添加数据卷

# cat docker-compose.yaml
version: "3"
services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    restart: on-failure
    environment:
      TZ: Asia/Shanghai
    ports:
      - 8080:8080
      - 50000:50000
    volumes:
      - ./data/jenkins_home:/var/jenkins_home
      - ./apache-maven-3.8.8:/usr/local/maven
      - ./jdk-11.0.24+8:/usr/local/jdk
      - ./sonar-scanner:/usr/local/sonar-scanner
docker compose up -d

添加构建步骤

image.png

docker build -t harbor.sundayhk.com/java_project/${JOB_NAME}:$tag ./
docker login -u admin -p password harbor.sundayhk.com
docker push harbor.sundayhk.com/java_project/${JOB_NAME}:$tag
[root@jenkins ~]# docker images | grep harbor.sundayhk.com/java_project/spring-boot-hello-world
harbor.sundayhk.com/java_project/spring-boot-hello-world   v1.0.0            18449e7172b1   1 minute ago   672MB

编写部署脚本

部署项目需要通过Publish Over SSH插件,让目标服务器执行命令。为了方便一次性实现拉取镜像和启动的命令,推荐采用脚本文件的方式。

添加脚本文件到目标服务器,再通过Publish Over SSH插件让目标服务器执行脚本即可。

系统管理 - 系统配置 Publish over SSH 添加服务器
如生产服务器禁用Root登陆,则普通用户需要加入sudo 无密码

#visudo 

sunday     ALL=(ALL:ALL) NOPASSWD:ALL

重新登陆终端才生效
测试

sudo cat /etc/shadow

将deploy.sh 脚本放到 prod server服务器 /data/shell下

# deploy.sh
#!/bin/bash

harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
host_port=$5
container_port=$6
harbor_user="admin"
harbor_password="password"

if [ $# -lt 6 ]; then
   echo "Usg: $0 <harbor_url> <harbor_project_name> <project_name> <tag> <host_port> <container_port>"
   exit 1
fi

image_name=$harbor_url/$harbor_project_name/$project_name:$tag
container_id=`docker ps -a | grep ${project_name} | awk '{print $1}'`
image_id=`docker images | grep ${project_name} | awk '{print $3}'`

if [ "$container_id" != "" ] ; then
    docker stop $container_id
    docker rm $container_id
fi

if [ "$image_id" != "" ] ; then
    docker rmi -f $image_id
fi

if ! docker login -u $harbor_user -p $harbor_password $harbor_url; then
    echo "harbor login fail"
    exit 1
fi

if ! docker pull $image_name; then
    echo "imgage pull fail"
    exit 1
fi

if ! docker run -d -p $host_port:$container_port --name $project_name $image_name; then
    echo "container run fail"
    exit 1
fi

echo "$0 run success!"
chmod +x deploy.sh

image.png

image.png

image.png

sudo /data/shell/deploy.sh harbor.sundayhk.com java_project ${JOB_NAME} $tag $host_port $container_port > /var/log/deploy.log

image.png

[root@rancher shell]# docker ps -a | grep spring-boot
f38d87da58f9   harbor.sundayhk.com/java_project/spring-boot-hello-world:v1.0.0   "java -jar /app.jar"   34 seconds ago   Up 33 seconds   0.0.0.0:8081->8080/tcp, :::8081->8080/tcp                                        spring-boot-hello-world

Jenkins pipeline部署

Jenkins流水线任务

Jenkins的自由风格构建的项目,每个步骤流程都要通过不同的方式设置,并且构建过程中整体流程是不可见的,无法确认每个流程花费的时间,并且问题不方便定位问题。

Jenkins的Pipeline可以让项目的发布整体流程可视化,明确执行的阶段,可以快速的定位问题。并且整个项目的生命周期可以通过一个Jenkinsfile文件管理,而且Jenkinsfile文件是可以放在项目中维护。所以Pipeline相对自由风格或者其他的项目风格更容易操作。

新建任务 Jenkins流水线

image.png

生成Groovy脚本

image.png

image.png

image.png

项目发行 选择版本标签

参数化构建

构建参数,配置tag标签
image.png

配置端口参数

image.png

流水线语法生成

image.png

拉取Git代码 选择Git参数定义tag标签
流水线语法git checkout 生成为简化代码 不支持动态选择标签,则修改成如下

checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[credentialsId: 'be7a22f2-4859-4562-a720-eaed300e29ed', url: 'ssh://git@git.sundayhk.com:8022/zsp/spring-boot-hello-world.git']]])

配置pipeline

这里将Jenkinsfile 放在代码仓库中

注:由于采用变量,记得使用双引号
如 sshPublisher 中的execCommand

配置 Harbor 账户凭据
image.png

image.png

生成流水线语法
image.png

pipeline {
    agent any

    environment{
        harbor_host = 'harbor.sundayhk.com'
        harbor_repo = 'java_project'
        harbor_id = '7045de0f-8aa4-4ac5-905c-b4cab45f74cf'
    }

    stages {
        stage('拉取Git代码') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[credentialsId: 'be7a22f2-4859-4562-a720-eaed300e29ed', url: 'ssh://git@git.sundayhk.com:8022/zsp/spring-boot-hello-world.git']]])
            }
        }

        stage('构建代码') {
            steps {
                sh '/usr/local/maven/bin/mvn clean package -DskipTests'
            }
        }

        stage('检测代码质量') {
            steps {
                sh '/usr/local/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=squ_427af7410ee605dc171c84dabb09c9fea06e9164' 
            }
        }

        stage('制作自定义镜像并发布Harbor') {
            steps {
                sh '''docker build -t ${JOB_NAME}:${tag} ./'''
                withCredentials([usernamePassword(credentialsId: "${harbor_id}", passwordVariable: 'password', usernameVariable: 'username')]) {
                    sh '''docker login -u ${username} -p ${password} ${harbor_host}
                    docker tag ${JOB_NAME}:${tag} ${harbor_host}/${harbor_repo}/${JOB_NAME}:${tag}
                    docker push ${harbor_host}/${harbor_repo}/${JOB_NAME}:${tag}'''
                }

            }
        }

        stage('目标服务器拉取镜像并运行') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'TestServer', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/data/shell/deploy.sh ${env.harbor_host} ${env.harbor_repo} ${JOB_NAME} $tag $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
            }
        }
    }
}

image.png
image.png
image.png

钉钉通知

插件:DingTalk

image.png

image.png

复制Webhook信息

https://oapi.dingtalk.com/robot/send?access_token=1fc63b1d066a56cc04a8261ba61cbb1362cea2a3e9ae9c9167ae8e98fc64f065

image.png

image.png

image.png

JenkinsFile

pipeline {
    agent any

    environment{
        harbor_host = 'harbor.sundayhk.com'
        harbor_repo = 'java_project'
        harbor_id = '7045de0f-8aa4-4ac5-905c-b4cab45f74cf'
    }

    stages {
        stage('拉取Git代码') {
            steps {
                checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[credentialsId: 'be7a22f2-4859-4562-a720-eaed300e29ed', url: 'ssh://git@git.sundayhk.com:8022/zsp/spring-boot-hello-world.git']]])
            }
        }

        stage('构建代码') {
            steps {
                sh '/usr/local/maven/bin/mvn clean package -DskipTests'
            }
        }

        stage('检测代码质量') {
            steps {
                sh '/usr/local/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=squ_427af7410ee605dc171c84dabb09c9fea06e9164' 
            }
        }

        stage('制作自定义镜像并发布Harbor') {
            steps {
                sh '''docker build -t ${JOB_NAME}:${tag} ./'''
                withCredentials([usernamePassword(credentialsId: "${harbor_id}", passwordVariable: 'password', usernameVariable: 'username')]) {
                    sh '''docker login -u ${username} -p ${password} ${harbor_host}
                    docker tag ${JOB_NAME}:${tag} ${harbor_host}/${harbor_repo}/${JOB_NAME}:${tag}
                    docker push ${harbor_host}/${harbor_repo}/${JOB_NAME}:${tag}'''
                }

            }
        }

        stage('目标服务器拉取镜像并运行') {
            steps {
                sshPublisher(publishers: [sshPublisherDesc(configName: 'TestServer', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/data/shell/deploy.sh ${env.harbor_host} ${env.harbor_repo} ${JOB_NAME} $tag $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)])
            }
        }
    }
    post {
        success {
            dingtalk (
                robot: 'DingTalk-Bot',
                type:'MARKDOWN',
                title: "success: ${JOB_NAME}",
                text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
        failure {
            dingtalk (
                robot: 'DingTalk-Bot',
                type:'MARKDOWN',
                title: "fail: ${JOB_NAME}",
                text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"]
            )
        }
    }
}

image.png

相关文章

MacBook系统升级到Sequoia15.1 SSH密钥无权限解决
haproxy 负载rabbitmq集群 报client unexpectedly closed TCP connection
Nginx Apache CORS OPTIONS预检请求配置
windows 2012 命令行批量修改文件权限 删除
CICD持续集成 SonarQube 代码检测部署
win11 Microsoft Store 微软账户无法登陆 0x80190001 解决

发布评论