DevOps 之 Jenkins+GitLab+SonarQube (三)

五、代码质量测试

  • 官方网站:http://www.sonarqube.org/
  • SonarQube 是一个用于代码质量管理的开放平台,通过插件机制,SonarQube 可以集成不同的测试工具,代码分析工具,以及持续集成工具,例如 Hudson/Jenkins 等。
  • 下载地址:https://www.sonarqube.org/downloads/
  • 七个维度检测代码质量
    • 复杂度分布:代码复杂度过高将难以理解
    • 重复代码:程序中包含大量复制、粘贴的代码而导致代码臃肿,sonar 可以展示源码中重复严重的地方
    • 单元测试统计:统计并展示单元测试覆盖率,开发或测试可以清楚测试代码的覆盖情况
    • 代码规则检查:检查代码是否符合规范
    • 注释率:若代码注释过少,特别是人员变动后,其他人接手比较难接手;若过多,又不利于阅读潜在的
    • Bug:检测潜在的 bug
    • 结构与设计:找出循环,展示包与包、类与类之间的依赖、检查程序之间耦合度

5.1 代码测试工具 SonarQube 简介

  • 7.9.x 版本不再支持 MySQL
  • server端需要 OpenJDK 11 或 Oracle JRE 11
    参考 https://docs.sonarqube.org/latest/setup/upgrade-notes/

  • 下载官方安装文件:

5.2 基础环境依赖

5.2.1 数据库环境依赖

  • SonarQube 6.7.X LTS 版本要求数据库要使用 MySQ 5.6 及以上版本,不支持 5.5 及更早的版本, 7.9.X LTS 版本不再使用 MySQL 。
    https://docs.sonarqube.org/6.7/Requirements.html

5.2.2 java 环境依赖

6.7.X 要求

7.9.X 要求

5.2.3 系统及内核参数

useradd -s /bin/bash -m sonarqube  # 使用普通账户启动 sonarqube
vim /etc/sysctl.conf
vm.max_map_count=262144
fs.file-max=65536

sysctl -p #生效

vim /etc/security/limits.conf
sonarqube - nofile 65536
sonarqube - nproc 65536

# 重启机器生效

5.3 部署 SonarQube

5.3.1 PostgreSQL 及 SonarQube 7.9.X 部署

安装 JDK 11

apt-cache madison openjdk-11-jdk
apt install -y openjdk-11-jdk
java -version
openjdk version "11.0.9.1" 2020-11-04
OpenJDK Runtime Environment (build 11.0.9.1+1-Ubuntu-0ubuntu1.18.04)
OpenJDK 64-Bit Server VM (build 11.0.9.1+1-Ubuntu-0ubuntu1.18.04, mixed mode, sharing)

部署 PostgreSQL 服务器

apt-cache  madison  postgresql
apt install postgresql -y

#配置 postgrepsql
su - postgres # 切换到 postgres 操作,PostgresSQL 安装后会自动创建 postgres 用户且没有密码
psql -U postgres # 登录 postgresql 数据库
#创建数据库并进行授权普通用户访问:
CREATE DATABASE sonar;  #创建数据库
CREATE USER sonar WITH ENCRYPTED PASSWORD '123456'; #创建用户
GRANT ALL PRIVILEGES ON DATABASE sonar TO sonar; #授权用户
ALTER DATABASE sonar OWNER TO sonar; #执行变更
#修改监听地址
vim /etc/postgresql/10/main/postgresql.conf
listen_addresses = '*'
#开启远程访问
vim  /etc/postgresql/10/main/pg_hba.conf
92 host    all             all             0.0.0.0/0            md5

systemctl restart postgresql

部署 7.9.X SonarQube

cd /apps
unzip sonarqube-7.9.5.zip
ln -sv /apps/sonarqube-7.9.5 /apps/sonarqube
useradd -s /bin/bash -m sonarqube
chown sonarqube:sonarqube /apps/sonarqube-7.9.5 /apps/sonarqube -R
vim /apps/sonarqube/conf/sonar.properties #修改配置
sonar.jdbc.username=sonar
sonar.jdbc.password=123456
sonar.jdbc.url=jdbc:postgresql://192.168.7.104/sonar
# 启动
su sonarqube
/apps/sonarqube/bin/linux-x86-64/sonar.sh start

制作启动脚本

vim /etc/systemd/system/sonarqube.service
[Unit]
Description=SonarQube service
After=syslog.target network.target

[Service]
Type=simple
User=sonarqube
Group=sonarqube
PermissionsStartOnly=true
ExecStart=/usr/bin/nohup /usr/bin/java -Xms2048m -Xmx2048m -Djava.net.preferIPv4Stack=true -jar /apps/sonarqube/lib/sonar-application-7.9.5.jar
StandardOutput=syslog
LimitNOFILE=65536
LimitNPROC=65536
TimeoutStartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

验证 SonarQube :

访问 SonarQube web 界面

  • 192.168.7.104:9000 登录账户名和密码默认都是 admin

安装中文插件

常见错误

app[][o.s.a.p.AbstractManagedProcess] Process exited with exit value [es]: 143
  • 这个报错一般是数据库连接问题,请查看sonar/logs/web.log
app[][o.s.a.p.AbstractManagedProcess] Process exited with exit value [es]: 1
  • 这个报错一般是es不能使用root启动原因导致
Caused by: org.postgresql.util.PSQLException: ERROR: no schema has been selected to create in
  • 是因为没权限,要注意授权
java.lang.IllegalStateException: Fail to connect to database
  • 无法连接数据库,注意IP地址

5.4 jenkins 服务器部署扫描器 sonar-scanner

  • 下载地址:https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/
  • 官方文档:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/

5.4.1 部署 sonar-scanner

  • sonarqube 通过调用扫描器 sonar-scanner 进行代码质量分析,即扫描器的具体工作就
    是扫描代码:
cd /usr/local/src/
unzip sonar-scanner-cli-4.6.0.2311-linux.zip
ln -sv /usr/local/src/sonar-scanner-4.6.0.2311-linux/ /usr/local/sonar-scanner
cd /usr/local/sonar-scanner

# 修改配置
vim /usr/local/sonar-scanner/conf/sonar-scanner.properties
sonar.host.url=http://192.168.7.104:9000
sonar.sourceEncoding=UTF-8

5.4.2 准备测试代码

cd /data
unzip sonar-examples-master.zip
cd /data/sonar-examples-master/projects/languages/python/python-sonar-runner
ll # 查看示例文件
-rw-r--r-- 1 root root  461 Jul 25  2016 README.md
-rw-r--r-- 1 root root  338 Jul 25  2016 sonar-project.properties
drwxr-xr-x 5 root root 4096 Jul 25  2016 src/
-rw-r--r-- 1 root root  290 Jul 25  2016 validation.txt

cat sonar-project.properties
# Required metadata
sonar.projectKey=org.sonarqube:php-simple-sq-scanner #自定义项目 key
sonar.projectName=PHP :: Simple Project :: SonarQube Scanner #项目名称,会显示在web
sonar.projectVersion=1.0 #项目版本
# Comma-separated paths to directories with sources (required)
sonar.sources=src #源代码目录
# Language
sonar.language=php #代码语言类型
# Encoding of the source files
sonar.sourceEncoding=UTF-8 #编码格式

5.4.3 在源代码目录执行扫描

  • 执行:/usr/local/sonar-scanner/bin/sonar-scanner,手动在当前项目代码目录执行扫描,以下是扫描过程的提示信息,扫描的配置文件sonar-project.propertie 每个项目都要有

5.4.4 sonarquebe web 界面验证扫描结果

5.5 jenkins 执行代码扫描

5.5.1 jenkins 安装 SonarQube 插件

5.5.2 添加 SonarQube URL

  • Jenkins—系统管理—系统设置–SonarQube servers

5.5.3 让 jenkins 添加 Sonar scanner 扫描器

  • 添加扫描器:Jenkins–系统管理-全局工具配置–手动指定绝对路径(也可自动安装)

5.5.4 配置扫描

  • 选择自己的job–>配置–>增加构建步骤–>execute sonarqube scanner ,将配置文件的内容修改成如下格式填写完成后点保存:
# Required metadata
sonar.projectKey=Java-test
sonar.projectName=Java-test
sonar.projectVersion=1.0

# Comma-separated paths to directories with sources (required)
sonar.sources=./

# Language
sonar.language=java

# Encoding of the source files

5.5.5 构建项目并测试 sonar-scanner 是否生效

5.5.6 web界面查看

六、Jenkins 实现 DevOps 流水线代码部署

  • 通过 shell 脚本实现自动化部署与回滚代码

6.1 job配置

插件:Parameterized Trigger

6.2 shell脚本

#!/bin/bash
DATE=`date +%Y-%m-%d_%H-%M-%S`
METHOD=1
BRANCH=2
GROUP_LIST=3

function IP_list(){
  if [[{GROUP_LIST} == "GROUP1" ]];then
     Server_IP="192.168.7.105"
     echo {Server_IP}
     ssh root@192.168.7.103 "echo "disable  server web-80/192.168.7.105" | socat stdio /run/haproxy/admin.sock"
     ssh root@192.168.7.104 "echo "disable  server web-80/192.168.7.105" | socat stdio /run/haproxy/admin.sock"
  elif [[{GROUP_LIST} == "GROUP2" ]];then
     Server_IP="192.168.7.106 192.168.7.107"
     echo {Server_IP}
     ssh root@192.168.7.103 "echo "enable  server web-80/192.168.7.105" | socat stdio /run/haproxy/admin.sock"
     ssh root@192.168.7.104 "echo "enable  server web-80/192.168.7.105" | socat stdio /run/haproxy/admin.sock"
  elif [[{GROUP_LIST} == "GROUP3" ]];then
     Server_IP="192.168.7.105 192.168.7.106 192.168.7.107"
     echo {Server_IP}
  fi
}

function clone_code(){
  cd /data/app/ && rm -rf project-test1
  git clone -b{BRANCH} git@192.168.7.101:group-test1/project-test1.git
  echo "代码clone完成"
}

function scanner_code(){
  cd /data/app/project-test1 && /usr/local/sonar-scanner/bin/sonar-scanner
  echo "代码扫描完成,请打开sonarqube查看扫描结果"
}

function code_maven(){
  echo  "cd /data/app/project-test1 && mvn clean package -Dmaven.test.skip=true"
  echo "代码编译完成"
}


function make_zip(){
  cd /data/app/project-test1   && zip -r code.zip ./
  echo "代码打包完成"
}


down_node(){
  for node in {Server_IP};do
    ssh root@192.168.7.103 "echo "disable server  web-80/{node}" | socat stdio /run/haproxy/admin.sock"
    echo "{node} 从负载均衡192.168.7.103下线成功"
    ssh root@192.168.7.104 "echo "disable server  web-80/{node}" | socat stdio /run/haproxy/admin.sock"
    echo "{node} 从负载均衡192.168.7.104下线成功"
  done
}

function scp_zipfile(){
  for node in{Server_IP};do
    scp /data/app/project-test1/code.zip  tomcat@{node}:/apps/tomcat/tomcat_appdir/code-{DATE}.zip
    ssh tomcat@{node} "unzip /apps/tomcat/tomcat_appdir/code-{DATE}.zip  -d /apps/tomcat/tomcat_webdir/code-{DATE} && rm -rf  /apps/tomcat/tomcat_webapps/myapp && ln -sv  /apps/tomcat/tomcat_webdir/code-{DATE} /apps/tomcat/tomcat_webapps/myapp"
  done
}

function stop_tomcat(){
  for node in {Server_IP};do
    ssh tomcat@{node}   "/etc/init.d/tomcat stop"
  done
}

function start_tomcat(){
  for node in {Server_IP};do
    ssh tomcat@{node}   "/etc/init.d/tomcat start"
    #sleep 5
  done
}

function web_test(){
  sleep 5
  for node in {Server_IP};do
    NUM=`curl -s  -I -m 10 -o /dev/null  -w %{http_code}  http://{node}:8080/myapp/index.html`
    if [[ {NUM} -eq 200 ]];then
       echo "{node} 测试通过,即将添加到负载"
       add_node {node}
    else
       echo "{node} 测试失败,请检查该服务器是否成功启动tomcat"
    fi
  done
}

function add_node(){
   node=1
    echo{node},"----->"
    #if [[ {GROUP_LIST} == "GROUP2" ]];then
    #  ssh root@192.168.7.103 ""echo enable  server web-80/192.168.7.105" | socat stdio /run/haproxy/admin.sock"
    #  ssh root@192.168.7.104 ""echo enable  server web-80/192.168.7.105" | socat stdio /run/haproxy/admin.sock"
    #fi
    ##########################################
    if [{node} == "192.168.7.105" ];then
       echo "192.168.7.105 部署完毕,请进行代码测试!"
    else
      ssh root@192.168.7.103 ""echo enable  server web-80/{node}" | socat stdio /run/haproxy/admin.sock"
      ssh root@192.168.7.104 ""echo enable  server web-80/{node}" | socat stdio /run/haproxy/admin.sock"
    fi
}

function rollback_last_version(){
  for node in {Server_IP};do
   echonode
   NOW_VERSION=`ssh tomcat@{node} ""/bin/ls -l  -rt /apps/tomcat/tomcat_webapps/ | awk -F"->" '{print2}'  | tail -n1""`
   NOW_VERSION=`basename {NOW_VERSION}`
   echoNOW_VERSION,"NOW_VERSION"
    NAME=`ssh  tomcat@{node}  ""ls  -l  -rt  /apps/tomcat/tomcat_webdir/ | grep -B 1{NOW_VERSION} | head -n1 | awk '{print 9}'""`
   echoNAME,""NAME
   ssh tomcat@{node} "rm -rf /apps/tomcat/tomcat_webapps/myapp && ln -sv  /apps/tomcat/tomcat_webdir/{NAME} /apps/tomcat/tomcat_webapps/myapp"
  done
}

function delete_history_version(){
  for node in {Server_IP};do
    ssh tomcat@{node} "rm -rf /apps/tomcat/tomcat_appdir/*"
    NUM=`ssh tomcat@{node}  ""/bin/ls -l -d   -rt /apps/tomcat/tomcat_webdir/code-* | wc -l""`
    echoNUM
      if [ {NUM} -gt 10 ];then
         NAME=`ssh tomcat@{node} ""/bin/ls -l -d   -rt /apps/tomcat/tomcat_webdir/code-* | head -n1 | awk '{print 9}'""`
         ssh tomcat@{node} "rm -rf {NAME}"
        echo "{node} 删除历史版本 /apps/tomcat/tomcat_webdir/{NAME}成功!"
      fi
  done
}

main(){
   case1  in
      deploy)
        IP_list;
        clone_code;
        scanner_code;
        make_zip;
        down_node;
        stop_tomcat;
        scp_zipfile;
        start_tomcat;
        web_test;
        delete_history_version;
         ;;
      rollback_last_version)
        IP_list;
        #echo {Server_IP}
        down_node;
        stop_tomcat;
        rollback_last_version;
        start_tomcat;
        web_test;
         ;;
    esac
}

main1 23

6.3 规划图

6.4.1 自动化部署流程

gitlab上传测试分支代码

jenkins执行构建105

105节点进行测试

若测试不通过进行代码回滚

测试通过则构建106和107

验证

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇