kubectl create 一直处于 ContainerCreating 状态

使用命令查看 pods 状态,发现过去很久还是没有启动成功。

guoqingsongmbp:k8s guo$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 0/1 ContainerCreating 0 15s

1
2
3

继续查看详情

guoqingsongmbp:k8s guo$ kubectl describe pod nginx
Name: nginx
Namespace: default
Node: minikube/192.168.99.105
Start Time: Tue, 25 Dec 2018 17:45:28 +0800
Labels: app=nginx
Annotations: <none>
Status: Pending
IP:
Containers:
nginx:
Container ID:
Image: nginx
Image ID:
Port: 80/TCP
State: Waiting
Reason: ContainerCreating
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5bz7m (ro)
Conditions:
Type Status
Initialized True
Ready False
PodScheduled True
Volumes:
default-token-5bz7m:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-5bz7m
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: <none>
Events:
Type Reason Age From Message
—- —— —- —- ——-
Normal Scheduled 14s default-scheduler Successfully assigned nginx to minikube
Normal SuccessfulMountVolume 14s kubelet, minikube MountVolume.SetUp succeeded for volume “default-token-5bz7m”
Warning FailedCreatePodSandBox 0s kubelet, minikube Failed create pod sandbox.

 

发现最后出错了,Warning FailedCreatePodSandBox 0s kubelet, minikube Failed create pod sandbox.。

进入到 minikube 节点里面进行排查问题。

guoqingsongmbp:k8s guo$ minikube ssh
_ _
_ _ ( ) ( )
___ ___ (_) ___ (_)| |/’) _ _ | |_ __
/’ _ ` _ `\| |/’ _ `\| || , < ( ) ( )| ‘_`\ /’__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )( ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/’`\____)

# 查看日志
$ journalctl -xe

1
2
3
4
5
6
7
8
9
10

发现有这么一个错误,如下:

Dec 25 09:40:03 minikube dockerd[2468]: time=”2018-12-25T09:40:03.283646463Z” level=info msg=”Attempting next endpoint for pull after error: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)”
Dec 25 09:40:03 minikube dockerd[2468]: time=”2018-12-25T09:40:03.283664032Z” level=error msg=”Handler for POST /v1.31/images/create returned error: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)”
Dec 25 09:40:03 minikube localkube[3258]: E1225 09:40:03.284457 3258 remote_runtime.go:92] RunPodSandbox from runtime service failed: rpc error: code = Unknown desc = failed pulling image “gcr.io/google_containers/pause-amd64:3.0”: Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

1
2
3

这里是因为会使用地址 gcr.io/google_containers/pause-amd64:3.0 进行拉取镜像,但是这个地址被墙了,所以不通,这里的解决办事是去 docker hub 上拉取完毕之后然后再进行更改 tag。如下:

$ docker pull docker.io/kubernetes/pause
Using default tag: latest
latest: Pulling from kubernetes/pause
a3ed95caeb02: Pull complete
f72a00a23f01: Pull complete
Digest: sha256:2088df8eb02f10aae012e6d4bc212cabb0ada93cb05f09e504af0c9811e0ca14
Status: Downloaded newer image for kubernetes/pause:latest

$ docker tag kubernetes/pause:latest gcr.io/google_containers/pause-amd64:3.0

1
2
3
4
5
6
7
8
9

最后把原来的 pod 删除掉,再重新启动即可。

guoqingsongmbp:k8s guo$ kubectl delete -f pod_nginx.yml
pod “nginx” deleted

guoqingsongmbp:k8s guo$ kubectl create -f pod_nginx.yml
pod “nginx” created

guoqingsongmbp:k8s guo$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 14m

guoqingsongmbp:k8s guo$ kubectl describe pod nginx
Name: nginx
Namespace: default
Node: minikube/192.168.99.105
Start Time: Tue, 25 Dec 2018 18:00:56 +0800
Labels: app=nginx
Annotations: <none>
Status: Running
IP: 172.17.0.4
Containers:
nginx:
Container ID: docker://cf22052ba5626cf6d99fbdb3867fa545a20c16d6f02c7eb9d9ad25b6ce6500ad
Image: nginx
Image ID: docker-pullable://nginx@sha256:5d32f60db294b5deb55d078cd4feb410ad88e6fe77500c87d3970eca97f54dba
Port: 80/TCP
State: Running
Started: Tue, 25 Dec 2018 18:01:26 +0800
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-5bz7m (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
default-token-5bz7m:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-5bz7m
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: <none>
Events:
Type Reason Age From Message
—- —— —- —- ——-
Normal Scheduled 14m default-scheduler Successfully assigned nginx to minikube
Normal SuccessfulMountVolume 14m kubelet, minikube MountVolume.SetUp succeeded for volume “default-token-5bz7m”
Normal Pulling 14m kubelet, minikube pulling image “nginx”
Normal Pulled 14m kubelet, minikube Successfully pulled image “nginx”
Normal Created 14m kubelet, minikube Created container
Normal Started 14m kubelet, minikube Started container

HAproxy Web 负载均衡解决方案

HAProxy提供高可用性负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。HAProxy特别适用于那些负载特大的web站点, 这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。

下图是HAProxy的架构:

下图是HAProxy的监控页面截图:

HAProxy实现了一种事件驱动, 单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。

localedef增加中文支持

#查看语言支持列表
localedef --list-archive
#精简locale
cd /usr/lib/locale/
mv locale-archive locale-archive.old
localedef -i en_US -f UTF-8 en_US.UTF-8
# 添加中文支持(可选)
localedef -i zh_CN -f UTF-8 zh_CN.UTF-8
localedef -i zh_CN -f GB2312 zh_CN
localedef -i zh_CN -f GB2312 zh_CN.GB2312
localedef -i zh_CN -f GBK zh_CN.GBK
#下面这些也是可选的,可以丰富中文支持(香港/台湾/新加坡)
localedef -f UTF-8 -i zh_HK zh_HK.UTF-8
localedef -f UTF-8 -i zh_TW zh_TW.UTF-8
localedef -f UTF-8 -i zh_SG zh_SG.UTF-8

Centos添加环境变量(~/.bash_profile、/etc/profile、/etc/profile.d)

环境变量

bash shell用一个叫做环境变量的特性来存储有关shell会话和工作环境的信息。即允许在内存中存储数据,使得在程序或shell中运行的脚本能够访问到它们。

Linux中环境变量分为三种:

全局环境变量:对于shell会话和所有生成的子shell都是可见的
局部环境变量:只对创建它的shell可见,即当前创建的用户可见
用户定义变量:只对当前会话生效

创建全局环境变量

在/etc/profile文件中创建全局环境变量
/etc/profile文件:
**当一个用户登录Linux系统或使用su -命令切换到另一个用户时,也就是Login shell 启动时,首先要确保执行的启动脚本就是 /etc/profile 。**只有Login shell 启动时才会运行 /etc/profile 这个脚本,而Non-login shell 不会调用这个脚本。
一些重要的变量就是在这个脚本文件中设置的,含义如下:

PATH: 预设可执行文件或命令的搜索路径。
USER: 用户登录时使用的用户名。
LOGNAME: 其值为$USER。
HOSTNAME: 所使用的主机名。
MAIL: 存放用户电子邮件的邮箱(实际上是一个ASCII码文件)。
HISTSIZE: 历史记录的行数。
INPUTRC: 存放的是针对键盘热键的信息(也是一个ASCII码文件)。

打开/etc/profile文件,PATH=$PATH:/usr/local/php/sapi/fpm就是定义了一个全局变量

PATH=$PATH:/usr/local/php/sapi/fpm
PATH=$PATH:/usr/local/openresty/nginx/sbin
PATH=$PATH:/usr/local/php/bin
PATH=$PATH:/usr/local/mysql/bin:/usr/local/mysql/lib
#PATH=$PATH:/usr/local/apache24/bin/
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL

1
2
3
4
5
6

执行source /etc/profile后生效
创建局部环境变量

打开 ~/.bash_profile文件添加PATH:

# User specific environment and startup programs

PATH=$PATH:$HOME/bin
PATH=$PATH:/usr/local/apache24/bin

export PATH
#也可以通过这种方式给环境变量起别名
alias nginx2=/usr/local/nginx/sbin/nginx

1
2
3
4
5
6
7
8

执行source ~/.bash_profile后生效
创建用户定义变量

export PATH=$PATH:/usr/local/apache24/bin

1

/etc/profile文件和/etc/profile.d目录的区别

/etc/profile文件中存放的变量上面已经做过说明。

在/etc/profile.d 目录中存放的是一些应用程序所需的启动脚本,其中包括了颜色、语言、less、vim及which等命令的一些附加设置。
这些脚本文件之所以能够 被自动执行,是因为在/etc/profile 中使用一个for循环语句来调用这些脚本。而这些脚本文件是用来设置一些变量和运行一些初始化过程的。
在/etc/profile.d目录下创建全局变量

在/etc/profile.d目录下创建的变量也是全局变量,方法如下:

vim /etc/profile.d/httpd.sh

APACHE_HOME=/usr/local/apache24
PATH=$APACHE_HOME/bin:$PATH
export APACHE_HOME PATH

1
2
3
4
5

重新打开shell后生效

查看pod启动失败原因

Focusing specifically on the example showed in the question.

The setup is following:

  • 1 GKE node with: 1 vCPU and 3.75 GB of RAM

The resources scheduled onto this single node cluster:

  • 4 Deployments where each have following fields:
        resources:
          requests: # <-- IMPORTANT
            cpu: "100m" # <-- IMPORTANT
            memory: "128Mi"
          limits:
            cpu: "100m"
            memory: "128Mi"

For an example I tried to replicate setup as close as possible to the one in the question:

  • $ kubectl get pods
NAME                           READY   STATUS    RESTARTS   AGE
nginx-four-99d88fccb-v664b     0/1     Pending   0          51m
nginx-one-8584c66446-rcw4p     1/1     Running   0          53m
nginx-three-5bcb988986-jp22f   1/1     Running   0          51m
nginx-two-6c9545d7d4-mrpw6     1/1     Running   0          52m

As you can see there is a Pod that is in Pending state. Further investigation implies:

  • $ kubectl describe pod/nginx-four-99d88fccb-v664b

A lot of information will show about the Pod but the part that needs to be checked is Events:

Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  56m (x2 over 56m)  default-scheduler  0/1 nodes are available: 1 Insufficient cpu.
  Normal   Scheduled         56m                default-scheduler  Successfully assigned default/nginx-two-6c9545d7d4-mrpw6 to gke-gke-old-default-pool-641f10b7-36qb
  Normal   Pulling           56m                kubelet            Pulling image "nginx"
  Normal   Pulled            56m                kubelet            Successfully pulled image "nginx"
  Normal   Created           56m                kubelet            Created container nginx
  Normal   Started           56m                kubelet            Started container nginx

As you can see from above output:

  • FailedScheduling: ... 0/1 nodes are available: 1 Insufficient cpu

As posted in the question:

I keep getting not having enough cpu availability even the node is using only 9% cpu at the same time.

sonarqube排除路径不生效

首先要设置 语言:sonar.language=java /****

然后要设置 扫描源文件和编译文件

sonar.sources=./ sonar.java.binaries=./

在设置 排除文件:

sonar.exclusions=./

具体的匹配规则可以参考sonar的官方文档,非常简单 (docs.sonarqube.org )。注意使用maven项目时匹配的文件夹基础是project base dir。
Wildcard Matches
? 匹配单个字符
** 匹配0个或多个文件夹
* 匹配0个或多个字符

例子:

排除以bean.java和dto.java为结尾的所有java文件> sonar.exclusions=/*Bean.java,/*DTO.java
排除文件夹 “src/main/java/org/sonar” 中所有的java文件,不包括子文件夹
sonar.exclusions=src/main/java/org/sonar/*

表达式:

正确的写法: sonar.exclusions=**/*R*.java,**/*Test.java

有时如果不设置 sonar.sources=./ sonar.java.binaries=./ 那么sonar.exclusions=./ 会没有效果
————————————————
版权声明:本文为CSDN博主「lxlmycsdnfree」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lxlmycsdnfree/article/details/80185680

jenkins:集成sonar代码扫描+发送邮件

前提:

Jenkins

JDK

目录:

1、安装sonar插件:SonarQube Scanner for Jenkins

2、安装SonarQube

3、安装sonar-scanner

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

1.安装sonar插件:SonarQube Scanner for Jenkins

2、安装SonarQube,并配置mysql数据库

2.1 下载

下载地址:https://www.sonarqube.org/downloads/

  2.2 解压

下载后放在/usr/local目录下,并解压

  1. unzip sonarqube7.4.zip

 2.3 配置环境变量

  1. vi /etc/profile

里面写如下

  1. #set sonarqube
  2. export SONAR_HOME=/usr/local/sonarqube7.4
  3. PATH=$PATH:$SONAR_HOME/bin

使配置生效

  1. source /etc/profile

 2.4 启动并测试

进入到启动目录

  1. /usr/local/sonarqube7.4/bin/linuxx8664

执行启动命令

  1. ./sonar.sh start

启动时要查看es.log和sonar.log日志,还有web.log,关于数据库配置的错误会在此处显示

  1. tail f /usr/local/sonarqube6.7.6/logs/es.log
  1. tail f /usr/local/sonarqube6.7.6/logs/sonar.log
  1. tail f /usr/local/sonarqube6.7./logs/web.log

用root启动会报错,请参考我的另一篇文章:https://www.cnblogs.com/gcgc/p/10239590.html

所有问题解决完后启动,并测试,访问ip+port,OK了

如果默认的9000端口被占用了,则修改默认端口 vi /usr/local/sonarqube-7.4/conf/sonar.properties

注意sonar中还集成了elastic search默认端口为9001,所以要查看9001否也被占用lsof -i:9001,如果被占用,也是修改上面的文件

  2.5 sonar配置mysql数据库

sonar自带测试数据库,但是具体应用还是的换其他数据,这里我们使用mysql,

创建sonar数据库

  1. DROP DATABASE sonar;
  2.  
  3. CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;
  4.  
  5. CREATE USER ‘sonar’ IDENTIFIED BY ‘sonar’;
  6.  
  7. GRANT ALL ON sonar.* TO ‘sonar’@‘%’ IDENTIFIED BY ‘sonar’;
  8.  
  9. GRANT ALL ON sonar.* TO ‘sonar’@‘localhost’ IDENTIFIED BY ‘sonar’;
  10.  
  11. FLUSH PRIVILEGES;

2.6 修改配置文件

修改vi /usr/local/sonarqube-7.4/conf/sonar.properties文件,如下的蓝色加粗字体

  1. # Property values can:
  2. # – reference an environment variable, for example sonar.jdbc.url= ${env:SONAR_JDBC_URL}
  3. # – be encrypted. See https://redirect.sonarsource.com/doc/settings-encryption.html
  4.  
  5. #————————————————————————————————–
  6. # DATABASE
  7. #
  8. # IMPORTANT:
  9. # – The embedded H2 database is used by default. It is recommended for tests but not for
  10. # production use. Supported databases are MySQL, Oracle, PostgreSQL and Microsoft SQLServer.
  11. # – Changes to database connection URL (sonar.jdbc.url) can affect SonarSource licensed products.
  12.  
  13. # User credentials.
  14. # Permissions to create tables, indices and triggers must be granted to JDBC user.
  15. # The schema must be created first.
  16. #sonar.jdbc.username=
  17. #sonar.jdbc.password=
  18. sonar.jdbc.username=sonar
  19. sonar.jdbc.password=sonar
  20. sonar.sorceEncoding=UTF8
  21. sonar.login=admin
  22. sonar.password=admin
  23.  
  24. #—– Embedded Database (default)
  25. # H2 embedded database server listening port, defaults to
  26. #sonar.embeddedDatabase.port=
  27.  
  28. #—– DEPRECATED
  29. #—– MySQL >=5.6 && <8.0
  30. # Support of MySQL is dropped in Data Center Editions and deprecated in all other editions
  31. # Only InnoDB storage engine is supported (not myISAM).
  32. # Only the bundled driver is supported. It can not be changed.
  33. sonar.jdbc.url=jdbc:mysql://192.168.207.160:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance&useSSL=false
  34.  
  35. #—– Oracle 11g/12c
  36. # The Oracle JDBC driver must be copied into the directory extensions/jdbc-driver/oracle/.
  37. # Only the thin client is supported, and only the versions 11.2.x or 12.2.x must be used. See
  38. # https://jira.sonarsource.com/browse/SONAR-9758 for more details.
  39. # If you need to set the schema, please refer to http://jira.sonarsource.com/browse/SONAR-5000
  40. #sonar.jdbc.url=jdbc:oracle:thin:@localhost:/XE
  41.  
  42. #—– PostgreSQL 9.3 or greater
  43. # By default the schema named “public” is used. It can be overridden with the parameter “currentSchema”.
  44. #sonar.jdbc.url=jdbc:postgresql://localhost/sonarqube?currentSchema=my_schema
  45.  
  46. #—– Microsoft SQLServer / and SQL Azure
  47. # A database named sonar must exist and its collation must be case-sensitive (CS) and accent-sensitive (AS)
  48. # Use the following connection string if you want to use integrated security with Microsoft Sql Server
  49. # Do not set sonar.jdbc.username or sonar.jdbc.password property if you are using Integrated Security
  50. # For Integrated Security to work, you have to download the Microsoft SQL JDBC driver package from
  51. # https://www.microsoft.com/en-us/download/details.aspx?id=55539
  52. # and copy sqljdbc_auth.dll to your path. You have to copy the bit or bit version of the dll
  53. # depending upon the architecture of your server machine.
  54. #sonar.jdbc.url=jdbc:sqlserver://localhost;databaseName=sonar;integratedSecurity=true
  55.  
  56. # Use the following connection string if you want to use SQL Auth while connecting to MS Sql Server.
  57. # Set the sonar.jdbc.username and sonar.jdbc.password appropriately.
  58. #sonar.jdbc.url=jdbc:sqlserver://localhost;databaseName=sonar
  59.  
  60. #—– Connection pool settings
  61. # The maximum number of active connections that can be allocated
  62. # at the same time, or negative for no limit.
  63. # The recommended value is 1.2 * max sizes of HTTP pools. For example if HTTP ports are
  64. # enabled with default sizes (, see property sonar.web.http.maxThreads)
  65. # then sonar.jdbc.maxActive should be 1.2 * = .
  66. #sonar.jdbc.maxActive=
  67.  
  68. # The maximum number of connections that can remain idle in the
  69. # pool, without extra ones being released, or negative for no limit.
  70. #sonar.jdbc.maxIdle=
  71.  
  72. # The minimum number of connections that can remain idle in the pool,
  73. # without extra ones being created, or zero to create none.
  74. #sonar.jdbc.minIdle=
  75.  
  76. # The maximum number of milliseconds that the pool will wait (when there
  77. # are no available connections) for a connection to be returned before
  78. # throwing an exception, or <= to wait indefinitely.
  79. #sonar.jdbc.maxWait=
  80.  
  81. #sonar.jdbc.minEvictableIdleTimeMillis=
  82. #sonar.jdbc.timeBetweenEvictionRunsMillis=
  83.  
  84. #————————————————————————————————–
  85. # WEB SERVER
  86. # Web server is executed in a dedicated Java process. By default heap size is 512Mb.
  87. # Use the following property to customize JVM options.
  88. # Recommendations:
  89. #
  90. # The HotSpot Server VM is recommended. The property -server should be added if server mode
  91. # is not enabled by default on your environment:
  92. # http://docs.oracle.com/javase/8/docs/technotes/guides/vm/server-class.html
  93. #
  94. # Startup can be long if entropy source is short of entropy. Adding
  95. # -Djava.security.egd=file:/dev/./urandom is an option to resolve the problem.
  96. # See https://wiki.apache.org/tomcat/HowTo/FasterStartUp#Entropy_Source
  97. #
  98. #sonar.web.javaOpts=-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError
  99.  
  100. # Same as previous property, but allows to not repeat all other settings like -Xmx
  101. #sonar.web.javaAdditionalOpts=
  102.  
  103. # Binding IP address. For servers with more than one IP address, this property specifies which
  104. # address will be used for listening on the specified ports.
  105. # By default, ports will be used on all IP addresses associated with the server.
  106. #sonar.web.host=0.0.0.0
  107.  
  108. # Web context. When set, it must start with forward slash (for example /sonarqube).
  109. # The default value is root context (empty value).
  110. #sonar.web.context=
  111. # TCP port for incoming HTTP connections. Default value is .
  112. sonar.web.port=9000
  113.  
  114. # The maximum number of connections that the server will accept and process at any given time.
  115. # When this number has been reached, the server will not accept any more connections until
  116. # the number of connections falls below this value. The operating system may still accept connections
  117. # based on the sonar.web.connections.acceptCount property. The default value is .
  118. #sonar.web.http.maxThreads=
  119.  
  120. # The minimum number of threads always kept running. The default value is .
  121. #sonar.web.http.minThreads=
  122.  
  123. # The maximum queue length for incoming connection requests when all possible request processing
  124. # threads are in use. Any requests received when the queue is full will be refused.
  125. # The default value is .
  126. #sonar.web.http.acceptCount=
  127.  
  128. # By default users are logged out and sessions closed when server is restarted.
  129. # If you prefer keeping user sessions open, a secret should be defined. Value is
  130. # HS256 key encoded with base64. It must be unique for each installation of SonarQube.
  131. # Example of command-line:
  132. # echo -n “type_what_you_want” | openssl dgst -sha256 -hmac “key” -binary | base64
  133. #sonar.auth.jwtBase64Hs256Secret=
  134.  
  135. # The inactivity timeout duration of user sessions, in minutes. After the configured
  136. # period of time, the user is logged out.
  137. # The default value is set to days ( minutes)
  138. # and cannot be greater than months. Value must be strictly positive.
  139. #sonar.web.sessionTimeoutInMinutes=
  140.  
  141. # A passcode can be defined to access some web services from monitoring
  142. # tools without having to use the credentials of a system administrator.
  143. # Check the Web API documentation to know which web services are supporting this authentication mode.
  144. # The passcode should be provided in HTTP requests with the header “X-Sonar-Passcode”.
  145. # By default feature is disabled.
  146. #sonar.web.systemPasscode=
  147.  
  148. #————————————————————————————————–
  149. # SSO AUTHENTICATION
  150.  
  151. # Enable authentication using HTTP headers
  152. #sonar.web.sso.enable=false
  153.  
  154. # Name of the header to get the user login.
  155. # Only alphanumeric, ‘.’ and ‘@’ characters are allowed
  156. #sonar.web.sso.loginHeader=X-Forwarded-Login
  157.  
  158. # Name of the header to get the user name
  159. #sonar.web.sso.nameHeader=X-Forwarded-Name
  160.  
  161. # Name of the header to get the user email (optional)
  162. #sonar.web.sso.emailHeader=X-Forwarded-Email
  163.  
  164. # Name of the header to get the list of user groups, separated by comma (optional).
  165. # If the sonar.sso.groupsHeader is set, the user will belong to those groups if groups exist in SonarQube.
  166. # If none of the provided groups exists in SonarQube, the user will only belong to the default group.
  167. # Note that the default group will always be set.
  168. #sonar.web.sso.groupsHeader=X-Forwarded-Groups
  169.  
  170. # Interval used to know when to refresh name, email and groups.
  171. # During this interval, if for instance the name of the user is changed in the header, it will only be updated after X minutes.
  172. #sonar.web.sso.refreshIntervalInMinutes=
  173.  
  174. #————————————————————————————————–
  175. # LDAP CONFIGURATION
  176.  
  177. # Enable the LDAP feature
  178. # sonar.security.realm=LDAP
  179.  
  180. # Set to true when connecting to a LDAP server using a case-insensitive setup.
  181. # sonar.authenticator.downcase=true
  182.  
  183. # URL of the LDAP server. Note that if you are using ldaps, then you should install the server certificate into the Java truststore.
  184. # ldap.url=ldap://localhost:10389
  185.  
  186. # Bind DN is the username of an LDAP user to connect (or bind) with. Leave this blank for anonymous access to the LDAP directory (optional)
  187. # ldap.bindDn=cn=sonar,ou=users,o=mycompany
  188.  
  189. # Bind Password is the password of the user to connect with. Leave this blank for anonymous access to the LDAP directory (optional)
  190. # ldap.bindPassword=secret
  191.  
  192. # Possible values: simple | CRAM-MD5 | DIGEST-MD5 | GSSAPI See http://java.sun.com/products/jndi/tutorial/ldap/security/auth.html (default: simple)
  193. # ldap.authentication=simple
  194.  
  195. # See :
  196. # * http://java.sun.com/products/jndi/tutorial/ldap/security/digest.html
  197. # * http://java.sun.com/products/jndi/tutorial/ldap/security/crammd5.html
  198. # (optional)
  199. # ldap.realm=example.org
  200.  
  201. # Context factory class (optional)
  202. # ldap.contextFactoryClass=com.sun.jndi.ldap.LdapCtxFactory
  203.  
  204. # Enable usage of StartTLS (default : false)
  205. # ldap.StartTLS=true
  206.  
  207. # Follow or not referrals. See http://docs.oracle.com/javase/jndi/tutorial/ldap/referral/jndi.html (default: true)
  208. # ldap.followReferrals=false
  209.  
  210. # USER MAPPING
  211.  
  212. # Distinguished Name (DN) of the root node in LDAP from which to search for users (mandatory)
  213. # ldap.user.baseDn=cn=users,dc=example,dc=org
  214.  
  215. # LDAP user request. (default: (&(objectClass=inetOrgPerson)(uid={login})) )
  216. # ldap.user.request=(&(objectClass=user)(sAMAccountName={login}))
  217.  
  218. # Attribute in LDAP defining the user’s real name. (default: cn)
  219. # ldap.user.realNameAttribute=name
  220.  
  221. # Attribute in LDAP defining the user’s email. (default: mail)
  222. # ldap.user.emailAttribute=email
  223.  
  224. # GROUP MAPPING
  225.  
  226. # Distinguished Name (DN) of the root node in LDAP from which to search for groups. (optional, default: empty)
  227. # ldap.group.baseDn=cn=groups,dc=example,dc=org
  228.  
  229. # LDAP group request (default: (&(objectClass=groupOfUniqueNames)(uniqueMember={dn})) )
  230. # ldap.group.request=(&(objectClass=group)(member={dn}))
  231.  
  232. # Property used to specifiy the attribute to be used for returning the list of user groups in the compatibility mode. (default: cn)
  233. # ldap.group.idAttribute=sAMAccountName
  234.  
  235. #————————————————————————————————–
  236. # COMPUTE ENGINE
  237. # The Compute Engine is responsible for processing background tasks.
  238. # Compute Engine is executed in a dedicated Java process. Default heap size is 512Mb.
  239. # Use the following property to customize JVM options.
  240. # Recommendations:
  241. #
  242. # The HotSpot Server VM is recommended. The property -server should be added if server mode
  243. # is not enabled by default on your environment:
  244. # http://docs.oracle.com/javase/8/docs/technotes/guides/vm/server-class.html
  245. #
  246. #sonar.ce.javaOpts=-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError
  247.  
  248. # Same as previous property, but allows to not repeat all other settings like -Xmx
  249. #sonar.ce.javaAdditionalOpts=
  250.  
  251. #————————————————————————————————–
  252. # ELASTICSEARCH
  253. # Elasticsearch is used to facilitate fast and accurate information retrieval.
  254. # It is executed in a dedicated Java process. Default heap size is 512Mb.
  255. #
  256. # ————————————————–
  257. # Word of caution for Linux users on 64bits systems
  258. # ————————————————–
  259. # Please ensure Virtual Memory on your system is correctly configured for Elasticsearch to run properly
  260. # (see https://www.elastic.co/guide/en/elasticsearch/reference/5.5/vm-max-map-count.html for details).
  261. #
  262. # When SonarQube runs standalone, a warning such as the following may appear in logs/es.log:
  263. # “max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]”
  264. # When SonarQube runs as a cluster, however, Elasticsearch will refuse to start.
  265. #
  266.  
  267. # JVM options of Elasticsearch process
  268. #sonar.search.javaOpts=-Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError
  269.  
  270. # Same as previous property, but allows to not repeat all other settings like -Xmx
  271. #sonar.search.javaAdditionalOpts=
  272.  
  273. # Elasticsearch port. Default is . Use to get a free port.
  274. # As a security precaution, should be blocked by a firewall and not exposed to the Internet.
  275. sonar.search.port=9002
  276.  
  277. # Elasticsearch host. The search server will bind this address and the search client will connect to it.
  278. # Default is loopback address.
  279. # As a security precaution, should NOT be set to a publicly available address.
  280. #sonar.search.host=
  281.  
  282. #————————————————————————————————–
  283. # UPDATE CENTER
  284.  
  285. # Update Center requires an internet connection to request https://update.sonarsource.org
  286. # It is enabled by default.
  287. #sonar.updatecenter.activate=true
  288.  
  289. # HTTP proxy (default none)
  290. #http.proxyHost=
  291. #http.proxyPort=
  292. # HTTPS proxy (defaults are values of http.proxyHost and http.proxyPort)
  293. #https.proxyHost=
  294. #https.proxyPort=
  295.  
  296. # NT domain name if NTLM proxy is used
  297. #http.auth.ntlm.domain=
  298.  
  299. # SOCKS proxy (default none)
  300. #socksProxyHost=
  301. #socksProxyPort=
  302.  
  303. # Proxy authentication (used for HTTP, HTTPS and SOCKS proxies)
  304. #http.proxyUser=
  305. #http.proxyPassword=
  306.  
  307. #————————————————————————————————–
  308. # LOGGING
  309.  
  310. # SonarQube produces logs in logs files located in the same directory (see property sonar.path.logs below),
  311. # one per process:
  312. # Main process (aka. App) logs in sonar.log
  313. # Web Server (aka. Web) logs in web.log
  314. # Compute Engine (aka. CE) logs in ce.log
  315. # Elasticsearch (aka. ES) logs in es.log
  316. #
  317. # All files follow the same rolling policy (see sonar.log.rollingPolicy and sonar.log.maxFiles) but it applies
  318. # individually (eg. if sonar.log.maxFiles=, there can be at most of each files, ie. files in total).
  319. #
  320. # All files have logs in the same format:
  321. #
  322. # |—————–| |—| |-|——————–||——————————| |——————————————————————————————————————————|
  323. # 2016.11. :: INFO ce[AVht0dNXFcyiYejytc3m][o.s.s.c.t.CeWorkerCallableImpl] Executed task | project=org.sonarqube:example-java-maven | type=REPORT | id=AVht0dNXFcyiYejytc3m | submitter=admin | time=1699ms
  324. #
  325. # : timestamp. Format is YYYY.MM.DD HH:MM:SS
  326. # YYYY: year on digits
  327. # MM: month on digits
  328. # DD: day on digits
  329. # HH: hour of day on digits in hours format
  330. # MM: minutes on digits
  331. # SS: seconds on digits
  332. # : log level.
  333. # Possible values (in order of descending criticality): ERROR, WARN, INFO, DEBUG and TRACE
  334. # : process identifier. Possible values: app (main), web (Web Server), ce (Compute Engine) and es (Elasticsearch)
  335. # : SQ thread identifier. Can be empty.
  336. # In the Web Server, if present, it will be the HTTP request ID.
  337. # In the Compute Engine, if present, it will be the task ID.
  338. # : logger name. Usually a class canonical name.
  339. # Package names are truncated to keep the whole field to characters max
  340. # : log payload. Content of this field does not follow any specific format, can vary in length and include line returns.
  341. # Some logs, however, will follow the convention to provide data in payload in the format ” | key=value”
  342. # Especially, log of profiled pieces of code will end with ” | time=XXXXms”.
  343.  
  344. # Global level of logs (applies to all processes).
  345. # Supported values are INFO (default), DEBUG and TRACE
  346. #sonar.log.level=INFO
  347.  
  348. # Level of logs of each process can be controlled individually with their respective properties.
  349. # When specified, they overwrite the level defined at global level.
  350. # Supported values are INFO, DEBUG and TRACE
  351. #sonar.log.level.app=INFO
  352. #sonar.log.level.web=INFO
  353. #sonar.log.level.ce=INFO
  354. #sonar.log.level.es=INFO
  355.  
  356. # Path to log files. Can be absolute or relative to installation directory.
  357. # Default is <installation home>/logs
  358. #sonar.path.logs=logs
  359.  
  360. # Rolling policy of log files
  361. # – based on time if value starts with “time:”, for example by day (“time:yyyy-MM-dd”)
  362. # or by month (“time:yyyy-MM”)
  363. # – based on size if value starts with “size:”, for example “size:10MB”
  364. # – disabled if value is “none”. That needs logs to be managed by an external system like logrotate.
  365. #sonar.log.rollingPolicy=time:yyyy-MM-dd
  366.  
  367. # Maximum number of files to keep if a rolling policy is enabled.
  368. # – maximum value is on size rolling policy
  369. # – unlimited on time rolling policy. Set to zero to disable old file purging.
  370. #sonar.log.maxFiles=
  371.  
  372. # Access log is the list of all the HTTP requests received by server. If enabled, it is stored
  373. # in the file {sonar.path.logs}/access.log. This file follows the same rolling policy as other log file
  374. # (see sonar.log.rollingPolicy and sonar.log.maxFiles).
  375. #sonar.web.accessLogs.enable=true
  376.  
  377. # Format of access log. It is ignored if sonar.web.accessLogs.enable=false. Possible values are:
  378. # – “common” is the Common Log Format, shortcut to: %h %l %u %user %date “%r” %s %b
  379. # – “combined” is another format widely recognized, shortcut to: %h %l %u [%t] “%r” %s %b “%i{Referer}” “%i{User-Agent}”
  380. # – else a custom pattern. See http://logback.qos.ch/manual/layouts.html#AccessPatternLayout.
  381. # The login of authenticated user is not implemented with “%u” but with “%reqAttribute{LOGIN}” (since version 6.1).
  382. # The value displayed for anonymous users is “-“.
  383. # The SonarQube’s HTTP request ID can be added to the pattern with “%reqAttribute{ID}” (since version 6.2).
  384. # If SonarQube is behind a reverse proxy, then the following value allows to display the correct remote IP address:
  385. #sonar.web.accessLogs.pattern=%i{X-Forwarded-For} %l %u [%t] “%r” %s %b “%i{Referer}” “%i{User-Agent}” “%reqAttribute{ID}”
  386. # Default value (which was “combined” before version 6.2) is equivalent to “combined + SQ HTTP request ID”:
  387. #sonar.web.accessLogs.pattern=%h %l %u [%t] “%r” %s %b “%i{Referer}” “%i{User-Agent}” “%reqAttribute{ID}”
  388.  
  389. #————————————————————————————————–
  390. # OTHERS
  391.  
  392. # Delay in seconds between processing of notification queue. Default is seconds.
  393. #sonar.notifications.delay=
  394.  
  395. # Paths to persistent data files (embedded database and search index) and temporary files.
  396. # Can be absolute or relative to installation directory.
  397. # Defaults are respectively <installation home>/data and <installation home>/temp
  398. #sonar.path.data=data
  399. #sonar.path.temp=temp
  400.  
  401. # Telemetry – Share anonymous SonarQube statistics
  402. # By sharing anonymous SonarQube statistics, you help us understand how SonarQube is used so we can improve the product to work even better for you.
  403. # We don’t collect source code or IP addresses. And we don’t share the data with anyone else.
  404. # To see an example of the data shared: login as a global administrator, call the WS api/system/info and check the Statistics field.
  405. #sonar.telemetry.enable=true
  406.  
  407. #————————————————————————————————–
  408. # DEVELOPMENT – only for developers
  409. # The following properties MUST NOT be used in production environments.
  410.  
  411. # Elasticsearch HTTP connector
  412. #sonar.search.httpPort=-

重新启动sonar,好了测试一下

3、安装sonar-scanner

3.1 下载

https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner

3.2 解压

下载后放在/usr/local目录下,并解压

  1. unzip sonarscannercli3.2.0.1227linux.zip

3.3 配置环境变量

和上面一样修改/etc/profile文件,修改完记得 source /etc/profile

  1. #set sonarqube
  2. export SONAR_HOME=/usr/local/sonarqube7.4
  3. export SONAR_SCANNER_HOME=/usr/local/sonarscanner3.2.0.1227linux
  4. PATH=$PATH:$SONAR_HOME/bin:$SONAR_SCANNER_HOME/bin

修改完记得 source /etc/profile

3.4 测试

进入/usr/local/sonar-scanner-3.2.0.1227-linux/bin执行:

  1. ./sonarscanner h

如果出现如下就说明安装好了

  1. [root@iZbp1bb2egi7w0ueys548qZ bin]# ./sonarscanner h
  2. INFO:
  3. INFO: usage: sonarscanner [options]
  4. INFO:
  5. INFO: Options:
  6. INFO: D,–define <arg> Define property
  7. INFO: h,–help Display help information
  8. INFO: v,–version Display version information
  9. INFO: X,–debug Produce execution debug output

4、在Jenkins中配置sonar

SonarScanner和SonarQube的关系类似于客户端与服务端,由于SonarScanner工具需要把扫描的代码及结果发送到SonarQube服务器上,所以需要配置SonarQube服务地址。

在Jenkins系统配置>>系统设中配置如下:

5、在Jenkins中配置sonar-scanner

全局工具配置中配置如下:

6、增加构建步骤

Analysis properties 内容如下

  1. sonar.projectKey=eauth
  2. sonar.projectName=电商用户服务-auth
  3. sonar.projectVersion=1.0
  4. sonar.sources=./
  5. sonar.language=java
  6. sonar.sourceEncoding=UTF
  7. sonar.java.binaries=./
  8. sonar.login=admin
  9. sonar.password=admin

7、构建一下

8、添加自定义邮件模板

在jenkins所在机器上/root/.jenkins目录下,新建/sonar_script文件夹,里面放如下脚本:sonar.py和table.html

sonar.py内容如下

  1. #!/usr/bin/python
  2. # -*- coding:utf-8 -*-
  3.  
  4. import pymysql,os,sys
  5. from jinja2 import FileSystemLoader,Environment
  6.  
  7. def select_project_uuid(project_name):
  8. db = pymysql.connect(host=“192.168.207.160”, port=3306, user=“sonar”, passwd=“sonar”, db=“sonar”)
  9. cursor = db.cursor()
  10. select_p_uuid=“SELECT project_uuid,kee FROM projects WHERE `name`= ‘%s'” %(project_name)
  11. cursor.execute(select_p_uuid)
  12. result = cursor.fetchone()
  13. p_uuid = result[0]
  14. projectKey = result[1]
  15. db.close()
  16. return(p_uuid, projectKey)
  17.  
  18. def select_total_info(p_uuid):
  19. total_info=[]
  20. # 使用cursor()方法获取操作游标
  21. db = pymysql.connect(host=“192.168.207.160”, port=3306, user=“sonar”, passwd=“sonar”, db=“sonar”)
  22. cursor = db.cursor()
  23.  
  24. select_p_links = “SELECT text_value FROM project_measures WHERE text_value LIKE ‘java=%’ and component_uuid=” + “\'” + p_uuid + “\'”
  25. cursor.execute(select_p_links)
  26. p_links = cursor.fetchone()[0].split(“=”)[1]
  27.  
  28. sql_info = “SELECT count(*) FROM issues WHERE project_uuid=’%s’ and issue_type =%s”
  29. for leak in [2,3,1]:
  30. search_data = sql_info %(p_uuid, leak)
  31. cursor.execute(search_data)
  32. total_info.append(cursor.fetchone()[0])
  33. db.close()
  34. return p_links,total_info
  35.  
  36. def select_bugs(p_uuid):
  37. bugs=[]
  38. db = pymysql.connect(host=“192.168.207.160”, port=3306, user=“sonar”, passwd=“sonar”, db=“sonar”)
  39. cursor = db.cursor()
  40.  
  41. sql_info = “SELECT count(*) FROM issues WHERE project_uuid=’%s’ and issue_type =2 AND severity =’%s'”
  42. for leak in [‘BLOCKER’,‘CRITICAL’,“MAJOR”,‘MINOR’,‘INFO’]:
  43. search_data=sql_info % (p_uuid,leak)
  44. cursor.execute(search_data)
  45. bugs.append(cursor.fetchone()[0])
  46. db.close()
  47. return bugs
  48.  
  49. def select_leaks(p_uuid):
  50. leaks=[]
  51. db = pymysql.connect(host=“192.168.207.160”, port=3306, user=“sonar”, passwd=“sonar”, db=“sonar”)
  52. cursor = db.cursor()
  53.  
  54. sql_info = “SELECT count(*) FROM issues WHERE project_uuid=’%s’ and issue_type =3 AND severity =’%s'”
  55. for leak in [‘BLOCKER’,‘CRITICAL’,“MAJOR”,‘MINOR’,‘INFO’]:
  56. search_data=sql_info % (p_uuid,leak)
  57. cursor.execute(search_data)
  58. leaks.append(cursor.fetchone()[0])
  59. db.close()
  60. return leaks
  61.  
  62. def select_bad_tastes(p_uuid):
  63. tastes=[]
  64. db = pymysql.connect(host=“192.168.207.160”, port=3306, user=“sonar”, passwd=“sonar”, db=“sonar”)
  65. cursor = db.cursor()
  66.  
  67. sql_info=“SELECT count(*) FROM issues WHERE project_uuid=’%s’ and issue_type =1 AND severity =’%s'”
  68. for leak in [‘BLOCKER’,‘CRITICAL’,“MAJOR”,‘MINOR’,‘INFO’]:
  69. search_data=sql_info % (p_uuid,leak)
  70. cursor.execute(search_data)
  71. tastes.append(cursor.fetchone()[0])
  72. return tastes
  73. db.close()
  74.  
  75. curpath = os.getcwd()
  76. table_tem_name=“table.html”
  77. def generate_errmsg_table(s_lines=“”, total_data=[], bugs=[],leaks=[],tastes=[],report_url=“”):
  78. env = Environment(loader=FileSystemLoader(curpath, ‘utf-8’)) # 创建一个包加载器对象
  79. template = env.get_template(table_tem_name)
  80. html_content = (template.render(lins=s_lines,total_data=total_data, bugs=bugs,leaks = leaks,tastes=tastes,report_url=report_url))
  81. fh = open(report_html_path, ‘w’)
  82. fh.write(html_content)
  83. fh.close()
  84.  
  85. project_name = sys.argv[1]
  86. report_html_path=“report\\”+project_name+“.html”
  87. p_uuid, projectKey=select_project_uuid(project_name)
  88. s_lines,total_data=select_total_info(p_uuid)
  89. bugs=select_bugs(p_uuid)
  90. leaks=select_leaks(p_uuid)
  91. tastes=select_bad_tastes(p_uuid)
  92. report_url=“http://192.168.207.140:9000/dashboard?id=%s” %(projectKey)
  93. generate_errmsg_table(s_lines,total_data,bugs,leaks,tastes,report_url)

 table.html内容:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4. <meta charset=“GBK”>
  5. <body>
  6. <p style=fontweight:bold;>一、总体情况:</p>
  7. <ul>
  8. <li style=fontweight:bold;>整体运行情况:扫描代码行数:<span style=color:blue>{{lins}}</span>, bugs:<span style=color:red>{{total_data[0]}}</span>, 漏洞:<span style=color:red>{{total_data[1]}}</span>, 坏味道:<span style=color:red>{{total_data[2]}}</span></li>
  9. <li style=fontweight:bold;>URL地址:<a style=fontweight:bold; href={{report_url}} >{{report_url}}</a></li>
  10. </ul>
  11. <p style=fontweight:bold;>二、错误信息详情:</p>
  12. <table border=“1” cellpadding=“10” width=“540” height=“120”>
  13. <tr ><th></th><th>阻断</th><th>严重</th><th>主要</th><th>次要</th><th>提示</th><th>总数</th></tr>
  14. <tr bgcolor=#ECFFFF><td>bugs</td><td align=“center”>{{bugs[0]}}</td><td align=“center”>{{bugs[1]}}</td><td align=“center”>{{bugs[2]}}</td><td align=“center”>{{bugs[3]}}</td><td align=“center”>{{bugs[4]}}</td><td align=“center” style=color:red>{{total_data[0]}}</td></tr>
  15. <tr bgcolor=#D2E9FF><td>漏洞</td><td align=“center”>{{leaks[0]}}</td><td align=“center”>{{leaks[1]}}</td><td align=“center”>{{leaks[2]}}</td><td align=“center”>{{leaks[3]}}</td><td align=“center”>{{leaks[4]}}</td><td align=“center” style=color:red>{{total_data[1]}}</td></tr>
  16. <tr bgcolor=#ECFFFF><td>坏味道</td><td align=“center”>{{tastes[0]}}</td><td align=“center”>{{tastes[1]}}</td><td align=“center”>{{tastes[2]}}</td><td align=“center”>{{tastes[3]}}</td><td align=“center”>{{tastes[4]}}</td><td align=“center” style=color:red>{{total_data[2]}}</td></tr>
  17. </table>
  18. <br></br>
  19. </body>
  20. </html>

9、添加执行自定义生成邮件模板步骤

前提:由于要执行sonar.py脚本,所以jenkins所在机器要有python3环境,且安装了pymysql、jinja2,

     centos安装python3:

进入到sonar.py所在目录,执行命令:python3 sonar.py 项目名

执行完成后会在/root/.jenkins/sonar_script目录下生成html文件,

10、配置发送邮件

10.1 安装插件:Email Extension

10.2 在系统管理》》系统设置中设置

11、发送邮件

在job中添加步骤

内容选择HTML,打开高级选项

增加触发器,并打开高级选项

输入发送邮箱列表,以英文逗号分隔,和邮件内容,html就是上面步骤生成的

最终的邮件如下图:

jenkins构建结果企业微信提醒

每当jenkin在构建之后我们想把构建结果SUCCESS/FAILURE或者其他信息通知给其他人,也许有人会说,不是有邮件提醒吗?但是我这里的环境邮件提醒的话所被通知者并不会第一时间去阅读,所以我们用“钉钉”,“企业微信”来第一时间去通知你想通知的小伙伴们。

因为我这里的环境用的是企业微信所以本文都是基于企业微信来说的,不过在钉钉上也可以使用,也可以利用钉钉在jenkins上的插件,那样更方便些。

进入正题

我们要获得jenkin的构建结果是SUCCESS还是FAILURE是需要jenkin构建完毕才能获取到的,那么我们从哪里能获得构建结果以及其他信息呢?

我们可以用日志信息或者api的构建信息来获取

我们 我们可以用日志信息或者api的构建信息来获取,这里我们是基于查看日志来查看构建结果以及其他信息,我这里以windows环境以及jenkins默认安装环境来举例

每一次日志文件的位置我们可以在如图位置找到

我们去最后一次构建结果查看日志文件

在结果查看构建结果是否成功

那么我们可以用python来写个读取结果的脚本,用jenkins来自动运行

import requests import json import urllib.request import urllib.error import time # 获取构建结果 def getResult(): fname = pathGitLab with open(fname, ‘rb’) as f: #打开文件 first_line = f.readline() #读第一行 #print (first_line) off = -50 #设置偏移量 while True: f.seek(off, 2) #seek(off, 2)表示文件指针:从文件末尾(2)开始向前50个字符(-50) lines = f.readlines() #读取文件指针范围内所有行 # print (lines) if len(lines)>=2: #判断是否最后至少有两行,这样保证了最后一行是完整的 last_line = lines[-1] #取最后一行 print (last_line) break off *= 2 if ‘FAILURE’ in last_line.decode() : return 1 # else: # return 0 #获取下一次构建的Number和当前构建的number def getNextNumber(): f = open(r’C:\Program Files (x86)\Jenkins\jobs\Developer\nextBuildNumber’, ‘r’) currentNumber=int(f.read())-1 return currentNumber #网络模块,用于企业微信发送信息 def jenkins(result): url=‘https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=2ef5c862-b2a6-45bc-a183-ee6666666666666666’ # 企业微信机器人的webhook if result==1: con={“msgtype”: “text”,“text”: {“content”: “站点构建提醒\r\n构建站点:Developer\r\n构建结果:FAILURE\r\n构建失败,请您检查代码并重新构建,谢谢”},} # else : # con={“msgtype”: “text”,”text”: {“content”: “developer构建结果:构建失败,请检查代码后重试!”},} jd=json.dumps(con).encode(‘utf-8’) req=urllib.request.Request(url,jd) req.add_header(‘Content-Type’, ‘application/json’) response=urllib.request.urlopen(req) if __name__ == ‘__main__’: jobCurrentNumber=getNextNumber() #获取当前构建number # print (jobCurrentNumber) # myDict=getDict()#获取同事所有联系方式 #获取当前构建的目录比如D:\Jenkins\jobs\gk_check\builds\153, path=“C:\\Program Files (x86)\\Jenkins\\jobs\\Developer\\builds\\”+str(jobCurrentNumber)+“\\” pathGitLab=path+“log” # 获取svn版本和id信息的文件路径 pathAuthor=path+“changelog.xml” # 获取递交者信息的文件路径 result=getResult() # 读取构建结果 # print (result) jenkins(result) # 最后执行函数 getResult()

这里的企业微信的webhook地址我们可以在如下的地方添加机器人

这样就可以获得webhook的地址来进行来进行企业微信提醒

接下来我们在jenkins的构建模块进行构建后操作

ping 127.1 -n 5 >nul # 延迟5秒,目的是的等jenkins构建完成来获取结果 @echo off D: cd D:\test start python developer_error.py #执行脚本

这里再简单说下curl 进行企业微信提醒

可以在构建最开始和结尾执行curl的命令

ios和Android的自动化构建结果也可以企业微信通知,如下图

还可以增加其他功能,等待大家去尝试,如果有什么问题或者创新想法大家可以说一哈

jenkins 通过shell启动java应用程序会随着job完成而被自动关闭的解决方法

我们使用jenkins进行构建打包后,实现自动部署,但 通过shell启动应用程序后,构建job完成应用程序也会自动关闭。下面以tomcat为例

如上执行后,tomcat先关闭,而后部署启动成功,可以访问。但构建job只完成后,tomcat自动关闭。

解决如下:

在脚本前面添加上BUILD_ID=XXXXX,即可如下:

这样job结束后,tomcat不会自动关闭。