0.简介

Jenkins是一个流行的开源持续集成和持续交付(CI/CD)工具,用于自动化构建、测试和部署软件项目。它提供了一个可扩展的平台,使开发团队能够自动化构建、测试和发布软件,以便更快地交付高质量的应用程序。

以下是一些Jenkins的主要特点和功能:

1. 自动化构建:Jenkins可以从源代码管理系统(如Git、Subversion等)中获取最新的代码,并自动执行构建过程,生成可部署的软件包。它支持各种编程语言和构建工具,如Java、Python、Maven、Gradle等。

2. 持续集成:Jenkins可以持续集成开发人员提交的代码变更。它可以在代码提交后自动触发构建和测试过程,以确保新的代码与现有代码的集成没有引入错误。

3. 测试和报告:Jenkins可以与各种测试框架和工具集成,例如JUnit、Selenium、Robot Framework等。它可以自动执行测试用例,并生成详细的测试报告和统计信息,以便开发人员和团队了解测试覆盖率和质量指标。

4. 可扩展性:Jenkins具有丰富的插件生态系统,支持各种插件来扩展其功能。这些插件涵盖了各种领域,包括构建、测试、部署、通知、版本控制等,使得Jenkins能够适应不同项目的需求。

5. 可视化界面:Jenkins提供了一个易于使用的Web界面,使得用户可以轻松地配置和管理项目、构建和部署作业。它还提供了丰富的图表和可视化工具,用于监控构建和测试的状态、趋势和历史记录。

6. 分布式构建:Jenkins支持分布式构建,可以将构建任务分发到多个代理节点上并行执行,以加快构建过程。这对于大型项目和复杂的构建任务非常有用。

总之,Jenkins是一个功能强大且灵活的CI/CD工具,可以帮助开发团队自动化构建、测试和部署软件项目。它的可扩展性、易用性和丰富的插件生态系统使得它成为开发人员和团队在持续集成和持续交付中的首选工具。

1.Jenkins安装

方法1:需要切换root用户 (win10子系统不适用,看方法2)

官网 或 https://www.jenkins.io/download/

这是 Jenkins 的 Debian 软件包存储库,用于自动安装和升级。 要使用此存储库,请先将密钥添加到系统中:

curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee \
    /usr/share/keyrings/jenkins-keyring.asc > /dev/null

然后添加一个 Jenkins apt 存储库条目:
 

echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
    https://pkg.jenkins.io/debian binary/ | sudo tee \
    /etc/apt/sources.list.d/jenkins.list > /dev/null

更新本地包索引,然后最终安装 Jenkins:

sudo apt-get update
sudo apt-get install fontconfig openjdk-11-jre
sudo apt-get install jenkins

1.1修改端口号

要更改Jenkins的端口号,你需要编辑Jenkins的配置文件,并将其端口号配置更改为你想要的值。以下是一些常见的步骤,可以帮助你完成这个任务:

  1. 登录到Jenkins服务器: 首先,通过SSH或直接登录到运行Jenkins的服务器。

  2. 找到Jenkins的配置文件: Jenkins的配置文件通常位于 /etc/default/jenkins 或 /etc/sysconfig/jenkins 中,具体位置可能因操作系统而异。你可以使用文本编辑器打开这个文件,例如:

    sudo vim /etc/default/jenkins
  3. 找到并编辑端口号设置: 在配置文件中,你应该能够找到一个名为 HTTP_PORT 或类似的设置,它指定了Jenkins使用的端口号。例如:

    HTTP_PORT=8080

    你可以将端口号更改为你想要的值,例如:

    HTTP_PORT=8888
  4. 保存配置文件: 保存你所做的更改并退出文本编辑器。

  5. 重新启动Jenkins服务: 为了使更改生效,你需要重新启动Jenkins服务。具体的命令可能因操作系统而异,以下是一些常见的命令示例:

    • 如果你的系统使用Systemd(如Ubuntu 16.04+):

      sudo systemctl restart jenkins
    • 如果你的系统使用SysVinit(如Ubuntu 14.04):

      sudo service jenkins restart
    • 如果你的系统使用其他启动系统,请查看该系统的文档以确定如何重新启动Jenkins服务。

  6. 验证更改: 确保Jenkins现在在新端口上运行。访问新的端口号,例如 http://your-server-ip:8888,并确保Jenkins界面可访问。

请注意,如果你在云服务提供商上运行Jenkins,还需要确保你的防火墙规则允许新端口的流量。另外,如果你使用反向代理服务器(如Nginx或Apache)来代理Jenkins,你还需要相应地配置代理服务器以反映新的端口号。

 

方法2:需要设置开机启动

java参考下载地址:Java Downloads | Oracle

首先装javajdk

sudo apt-get install openjdk-16-jdk

1、创建部署目录

cd /home/yys && mkdir jenkins

2、下载Jenkins

cd  jenkins
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war/latest/jenkins.war

3、运行jenkins

java -jar jenkins.war --enable-future-java --httpPort=8081

 

说明:如果不加--enable-future-java,

因为当前版本存在与本地java不兼容的情况,会报如下错误:

严重: Running with Java class version 60 which is not in the list of supported versions: [55, 61]. Run with the --enable-future-java flag to enable such behavior. See https://jenkins.io/redirect/java-support/
 

输入127.0.0.1:8081即可访问

需要输入管理员密码:

这个管理员密码是在启动日志中,我们从控制台找到这个密码:

访问

Please use the following password to proceed to installation:

81e59176dd16488e8390b06202d6ebc7

输入后点  继续 按钮

选择 安装推荐的插件 即可

因为网络原因,可能有一些插件会安装失败,都取消选中,后面可以换国内源安装

如果有失败的情况,点继续

 点击继续后:

我们在这里创建一个管理员账户后,点击 保存并完成 按钮

 确认url:

 点保存并完成 按钮后,会提示已就绪:

 

修改Jenkins插件下载地址
Jenkins国外官方插件地址下载速度非常慢,所以可以修改为国内插件地址:
Jenkins->Manage Jenkins->Manage Plugins,点击Available

 

更换插件镜像地址:

http://mirror.esuni.jp/jenkins/updates/update-center.json

,然后提交(submit),然后提交并点立即获取(check now)一下,重新启动Jenkins会发现之前下载安装失败的安装ok了。具体跟内网配置的代理有很大关系,我同事使用原有的可以使用我提供的不行,可以都试试。

2.GitLab安装(自动化用不上)

Ubuntu:20.04

1.安装需要的库和软件(sudo apt install net-tools)

 sudo apt-get install curl openssh-server ca-certificates postfix 

2.添加GitLab的包并进行安装

curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh |sudo bash 
sudo apt-get install gitlab-ce 

网络可能不好,需要重试几次
PS:也可以直接下载安装包


出现以下提示,表示安装成功

It looks like GitLab has not been configured yet; skipping the upgrade script.

       *.                  *.
      ***                 ***
     *****               *****
    .******             *******
    ********            ********
   ,,,,,,,,,***********,,,,,,,,,
  ,,,,,,,,,,,*********,,,,,,,,,,,
  .,,,,,,,,,,,*******,,,,,,,,,,,,
      ,,,,,,,,,*****,,,,,,,,,.
         ,,,,,,,****,,,,,,
            .,,,***,,,,
                ,*,.
  


     _______ __  __          __
    / ____(_) /_/ /   ____ _/ /_
   / / __/ / __/ /   / __ `/ __ \
  / /_/ / / /_/ /___/ /_/ / /_/ /
  \____/_/\__/_____/\__,_/_.___/
  

Thank you for installing GitLab!
 

3.配置GitLab
PS:unbuntu 下vi 输入i 不进入insert插入模式
原因:ubuntu预装的是vim tiny版本,需要的是vim full版本 —执行 sudo apt install vim

vim /etc/gitlab/gitlab.rb


1)配置对外IP和默认端口
external_url 'http://192.168.204.139:8082'

2)配置邮件通知
gitlab_rails['gitlab_email_from'] = '534640040@qq.com'

4.启动GitLab
输入下面的命令:

sudo gitlab-ctl stop     //--停止服务
sudo gitlab-ctl reconfigure  //--启动服务
sudo gitlab-ctl restart         //--重启所有gitlab组件
sudo gitlab-ctl start     

5.验证邮箱是否成功

先输入如下命令:

  sudo gitlab-rails console

-------------------------------------------------------------------------------
 GitLab:       12.1.4 (34d086f3e14)
 GitLab Shell: 9.3.0
 PostgreSQL:   10.7
--------------------------------------------------------------------------------
Loading production environment (Rails 5.2.3)
irb(main):001:0> 

 

再输入:

Notify.test_email('1434594542@qq.com','Message subject','Message body').deliver_now

 

6.初始化密码

PS:默认密码在/etc/gitlab/initial_root_password

1)切换到相应路径下

cd /opt/gitlab/bin/


2)打开控制台

sudo gitlab-rails console -e production


3)查询用户账号信息并赋值给u

u=User.where(id:1).first


4)设置该用户名的密码

 

u.password=12345678


5)确认密码

u.password_confirmation=12345678


6)保存信息

u.save!

备注:通过命令行修改密码不支持字母格式,密码要大于等于8位

可以用新的密码登录gitlab

7.配置GitLab开机自启动、关闭开机自启动
 启用 Gitlab开机自启动 :

systemctl enable gitlab-runsvdir.service


 禁止 Gitlab 开机自启动:

systemctl disable gitlab-runsvdir.service

访问设置的ip的http://192.168.204.140:8082,第一次让输入刚才设置密码,输入两次确认

就可以进入登录,刚才设置账号和密码输入可以登录
 

3.构建git持续集成

3.1Jenkins凭证管理

凭据可以用来存储需要密文保护的数据库密码、Gitlab密码信息、Docker私有仓库密码等,以便

Jenkins可以和这些第三方的应用进行交互。

安装Credentials Binding插件

要在Jenkins使用凭证管理功能,需要安装Credentials Binding插件(我没有找到)

常用的凭证类型有:Username with password(用户密码)和SSH Username with private key(SSH

密钥)接下来以使用Git工具到Gitlab拉取项目源码为例,演示Jenkins的如何管理Gitlab的凭证。

 

3.2 Git插件安装:

 安装Git插件和Git工具

为了让Jenkins支持从Gitlab拉取源码,需要安装Git插件以及在linux上安装Git工具。

3.3 用户密码类型

1) 创建凭证

Jenkins->凭证->系统->全局凭证->添加凭证  切记是点击全局 添加

选择"Username with password",输入Gitlab的用户名root和密码12345678,点击"确定"

找到"源码管理"->"Git",1.在Repository URL复制Gitlab中的项目URL,2.Credentials选择刚才创建凭证,3.指定分支(为空时代表any),选对不然会报错

如果用默认master会报错

Started by user yys
Running as SYSTEM
Building in workspace /home/yys/.jenkins/workspace/test01
The recommended git tool is: NONE
using credential 0df27c56-de1f-4cfd-9d6b-9ee048204b62
 > git rev-parse --resolve-git-dir /home/yys/.jenkins/workspace/test01/.git # timeout=10
Fetching changes from the remote Git repository
 > git config remote.origin.url http://192.168.204.140:8082/yys_group/web_demo.git # timeout=10
Fetching upstream changes from http://192.168.204.140:8082/yys_group/web_demo.git
 > git --version # timeout=10
 > git --version # 'git version 2.25.1'
using GIT_ASKPASS to set credentials 
 > git fetch --tags --force --progress -- http://192.168.204.140:8082/yys_group/web_demo.git +refs/heads/*:refs/remotes/origin/* # timeout=10
 > git rev-parse refs/remotes/origin/master^{commit} # timeout=10
 > git rev-parse origin/master^{commit} # timeout=10
ERROR: Couldn't find any revision to build. Verify the repository and branch configuration for this job.
Finished: FAILURE

根据提示发现是因为jenkins 构建配置中的gitlab的分支不对造成的,
 

4.设置开启启动

 

通用操作步骤

  • 创建希望开机马上执行的脚本,本文举例脚本存放位置为/home/yys/jenkins/start.sh,脚本内容如下:
  • /home/yys/jenkins/start.sh

     

#!/bin/bash
cd /home/yys/jenkins
java -jar jenkins.war --enable-future-java --httpPort=8081
  • 开机执行的脚本需增加可执行权限才能被 systemd 运行,使用如下命令
sudo chmod u+x /home/yys/jenkins/start.sh
sudo chmod g+x /home/yys/jenkins/start.sh
  • 进入 systemd 放置 service 的目录,在该目录下可看到大量服务配置文件,命令如下
# 进入 systemd 的 service 目录
cd /etc/systemd/system
# 查看文件列表
ls -al
  • 在该目录创建一个新的 .service 文件用于配置开机启动脚本,本例中的文件名为 StartupExample.service,所执行命令和文件中的配置内容如下:
  • # 创建服务配置文件
    sudo touch /etc/systemd/system/StartupExample.service

     

# 以下为 StartupExample.service 配置文件的内容
[Unit]
Description=Startup Example

[Service]
ExecStart=/home/yys/jenkins/start.sh

[Install]
WantedBy=multi-user.target
  • 尝试手动运行新创建的 service,使用如下命令:
# 手动运行 StartupExample.service
sudo systemctl start StartupExample.service
# 查看运行日志
systemctl status StartupExample.service
  • 将服务设置为 enable 状态,再重启计算机,看服务是否能正常运行。使用如下命令:
# 设置服务为 enable 状态,使之能开机运行
sudo systemctl enable StartupExample.service
# 重启机器
systemctl reboot

5.定时执行

 如上图所示,我们只需要在日程表里面写入相应的定时时间,即可完成定时任务的构建。

 

01 00 * * *
32 07 * * *
57 09 * * *
57 15 * * *
01 18 * * *

日程表内容语法:

*

*

*

*

*

分钟

小时

周(星期)

0-59

0-23

1-31

1-12

0-6

 

日程表里面只要写5个*(中间要空格),然后根据自己的不同需求,把对应的*换成想要的数字即可。

符号H可表示为范围,在一定范围内可被认为是一个随机值。

(M-N)/X   表示在M到N的这个范围内每隔X次,构建一次定时执行任务 

 

运行脚本

Build

Execute shell?

Command

See the list of available environment variables

 

cd /home/yys/test
python3 te.py

6.解决jenkins或cmd中运行python脚本报ImportError: No module named XXX的问题

1、直接在脚本最上方添加两行代码:

import sys
print (sys.path)

2、执行后,会打印出很多路径,如下:

['', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/home/yys/.local/lib/python3.8/site-packages', '/usr/local/lib/python3.8/dist-packages', '/usr/lib/python3/dist-packages']

 

3、再添加语句sys.path.append(""),有多少个路径添加多少条append,如

sys.path.append('/usr/lib/python3.8')
sys.path.append('/home/yys/.local/lib/python3.8/site-packages')
sys.path.append('/usr/local/lib/python3.8/dist-packages')
sys.path.append('/usr/lib/python3/dist-packages')

4、再次在jenkins运行,成功!!!

 

5.加入组中

Jenkins 新建shell

whoami

发现jenkins默认root用户

 

安卓adb授权

Linux:两个用户都有

/home/yys/.android/adbkey

/root/.android/adbkey

首次启动 adb 服务时,会在本地生成一对密钥 adbkey(私钥)与 adbkey.pub(公钥)。当执行 adb shell 时,adb 服务会将当前 PC 的公钥(或公钥hash值)发送给 Android 设备

下面几条好像没有效果cheeky

sudo vim /etc/group

可以加入一行 

jenkins:x:345:yys

yys 或root 

sudo gpasswd -a yys jenkins

6.SonarQube代码审查

SonarQube是一个用于管理代码质量的开放平台,可以快速的定位代码中潜在的或者明显的错误。目前支持java,C#,C/C++,Python,PL/SQL,Cobol,JavaScrip,Groovy等二十几种编程语言的代码质量管理与检 测,底层使用elasticsearch作为代码检索工具
sonarqube 7.9以上已经不支持mysql了,而且需要java11以上

7.添加环境变量

1.Build Executor Status→齿轮→Node Properties→Environment variables

 

name填path可以多个环境变量 

path

C:\Users\yys53\OneDrive\python\install;C:\Users\yys53\OneDrive\python\bestscript\allure\bin;

Name

Value

 

关机失败,加绝对路径

os.system("C:\Windows\System32\shutdown.exe -s -t 60")

8.运行gitlable报错git.exc.GitCommandError

git.exc.GitCommandError: Cmd('git') failed due to: exit code(128)
  cmdline: git fetch -v -- origin
  stderr: 'fatal: detected dubious ownership in repository at '/home/yys/mobile''
Build step 'Execute shell' marked build as failure
Finished: FAILURE 

sudo chown -R username:group /home/yys/mobile

sudo chown -R root:root /home/yys/mobile

 

9.jenkins运行reboot报错:

Started by user 杨永生 Running as SYSTEM Building in workspace /root/.jenkins/workspace/电脑重启 [电脑重启] $ /bin/sh -xe /tmp/jenkins3620306396645804747.sh + reboot /tmp/jenkins3620306396645804747.sh: 2: reboot: not found Build step 'Execute shell' marked build as failure Finished: FAILURE

 reboot 命令没有在 $PATH 环境变量中,你需要在 Jenkins 中指定完整的命令路径。你可以通过将 reboot 命令的完整路径写入 Jenkins 构建中的 Shell 脚本来解决此问题。例如:

/sbin/reboot

另外,确保你已经在正确的机器上运行 Jenkins 作业,因为如果你在远程机器上运行此作业,可能会导致此错误。

10.搭建go运行环境

GOPATH不是必须的

#export GOPATH=/usr/local/go/bin
export GOMODCACHE=/home/yys/mobile/gomodcache/
export GOCACHE=$HOME/.cache/go-build
cd /home/yys/mobile
pwd
/usr/local/go/bin/go run /home/yys/mobile/download_android_app.go

 

11.Jenkins 中遇到只能同时运行两个任务的限制

配置并行度:检查 Jenkins 的系统配置或节点配置,确保并行度(Concurrent Builds)设置得足够大。并行度控制可以限制 Jenkins 同时执行的构建任务数量。如果并行度设置为较小的值,你可以将其增加到允许同时运行更多任务的数量。

  • 在 Jenkins 管理界面中,点击 "Manage Jenkins"(管理 Jenkins)→"Configure System"(配置系统) 新版叫system
  • # of executors

设置10就可以运行10个任务

# of executors

 

12. Jenkins中使用git submodule时报fatal: could not read Username for xxxx: No such device or address的解决方案

本质原因是 服务器没有权限去拉取git子库,有如下几种解决方案:

1.将服务器的公钥配置到gitlab中,但这样服务器上的所有人都能clone你的代码
2.将username和password配置到服务器中,存在同样的问题
3.将gitlab的子仓库设置成public,这相当于裤衩都被脱掉了。。。
4.使用高级子模块克隆功能,可以完美解决这个问题
我用方法3.

13.Jenkins部署在docker容器中

要将Jenkins部署在容器中,你可以按照以下步骤进行操作:

  1. 安装Docker:确保你的系统上已经安装了Docker。根据你的操作系统,你可以按照Docker官方文档中的说明进行安装。

  2. 获取Jenkins镜像:使用Docker Hub上的Jenkins官方镜像,可以运行以下命令来获取Jenkins镜像:

    docker pull jenkins/jenkins
  3. 创建Jenkins容器:运行以下命令来创建一个基于Jenkins镜像的容器:

    docker run -d -p 8080:8080 -p 50000:50000 --name jenkins_container jenkins/jenkins

    这将创建一个名为jenkins_container的容器,将主机的8080端口映射到容器的8080端口(用于访问Jenkins Web界面),并将主机的50000端口映射到容器的50000端口(用于Jenkins的代理节点)。

  4. 访问Jenkins Web界面:在浏览器中打开 http://localhost:8080(如果你在本地运行)或 http://<your-server-ip>:8080(如果你在远程服务器上运行),即可访问Jenkins Web界面。

  5. 解锁Jenkins:在第一次访问Jenkins时,你需要提供解锁密钥。在容器的控制台输出或日志中,可以找到解锁密钥。复制密钥并按照界面上的指示进行解锁。

  6. 完成Jenkins安装:在解锁Jenkins后,你将被要求安装插件。你可以选择安装推荐的插件或自定义插件列表。等待插件安装完成。

  7. 创建管理员用户:创建Jenkins的管理员用户,包括用户名、密码和电子邮件地址。

  8. 完成配置:根据你的需求,可以进一步配置Jenkins,如设置全局工具、全局凭据、构建代理等。

现在,你已经成功地将Jenkins部署在Docker容器中了。你可以使用Jenkins Web界面创建和管理你的构建作业、构建代理等。请注意,上述步骤仅提供了基本的部署过程,你可能需要根据你的具体需求和环境进行适当的调整和配置。

 

14.切换为root用户

在官网安装方法用whoani是Jenkins用户,很多权限没有,切换root用户

参考Jenkins修改端口和工作目录并使用root用户执行

 

修改启动用户为root:

同样修改/etc/default/jenkins文件中如下位置

vim /etc/default/jenkins
# user and group to be invoked as (default to jenkins)
JENKINS_USER=root
JENKINS_GROUP=root

和/usr/lib/systemd/system/jenkins.service文件中如下位置

vim /usr/lib/systemd/system/jenkins.service
# $JENKINS_WEBROOT.
User=root
Group=root

#这步好像个不需要

chown -R root.root /data/jenkins

最后重启Jenkins:

systemctl daemon-reload
systemctl restart jenkins.service

 

15.修改Jenkins的最大内存占用

 

vim /etc/default/jenkins

根据/etc/default/jenkins提供的Jenkins配置文件内容,当前没有设置Jenkins的最大内存占用。可以通过修改 JAVA_ARGS 变量来设置Jenkins的最大内存占用。例如,如果想将Jenkins的最大内存占用限制为2GB,可以将 JAVA_ARGS 变量修改为:

JAVA_ARGS="-Djava.awt.headless=true -Xmx2048m"

修改完成后,保存文件并重启Jenkins服务以使更改生效。

16.备份

要自动备份Jenkins的/var/lib/jenkins数据,你可以使用脚本和定时任务来实现。以下是一个简单的备份脚本的例子,以及如何设置定时任务来定期执行该脚本:

1. 创建备份脚本:

创建一个Shell脚本,比如 backup_jenkins.sh,并添加以下内容:

#!/bin/bash

# 设置备份目录
backup_dir="/path/to/backup/directory"

# 设置备份文件名
backup_file="jenkins_backup_$(date +"%Y%m%d_%H%M%S").tar.gz"

# 执行备份
tar -czvf "$backup_dir/$backup_file" /var/lib/jenkins

echo "Jenkins data backup completed: $backup_dir/$backup_file"

# 获取当前星期几(1-7,星期一到星期日)current_day=$(date +%u)

确保给予脚本执行权限:

chmod +x backup_jenkins.sh

2. 设置定时任务:

使用cron来定期执行备份脚本。打开cron表编辑器:

crontab -e

在编辑器中添加定时任务。例如,每天凌晨3点执行备份:

0 3 * * * /path/to/backup_jenkins.sh

保存并退出编辑器。

这将在每天凌晨3点自动执行备份脚本。你可以根据需要调整cron表达式以满足你的需求。

注意事项:

  1. 确保备份目录存在: 确保指定的备份目录已经存在,或者在脚本中添加创建目录的逻辑。

  2. 定期监测备份文件数量和大小: 定期检查备份文件的数量和大小,以免占用过多磁盘空间。你可以根据需要保留一定数量的备份文件,并删除旧的备份文件。

  3. 注意文件权限: 确保脚本和备份目录的文件权限设置正确,以便Jenkins用户或相关用户能够执行备份操作。

以上示例脚本和定时任务是基本的示例,你可能需要根据实际情况进行调整。

扩展:python实现windows文件共享操作 (yys.zone)

17. 解决Jenkins中文字符编码问题:一个系统化的方法

摘要:
本研究旨在解决在Linux服务器上部署的Docker容器中运行的Jenkins服务不识别中文字符的问题。通过分析Jenkins及其宿主操作系统的字符编码配置,本文提出了一个基于环境变量设置的解决方案,以确保Jenkins在处理中文字符时的正确性和有效性。

关键词: Jenkins, 中文编码, Docker,, UTF-8

1. 引言

在持续集成和持续部署(CI/CD)的环境中,Jenkins是一个广泛使用的自动化服务器。然而,当Jenkins部署在非英文环境下时,字符编码问题经常成为挑战。特别是,Jenkins处理中文字符时出现的错误,如“Malformed input or input contains unmappable character”,严重影响了其在中文用户中的应用。本文旨在探索并解决Jenkins不识别中文字符的问题。

2. 背景

Jenkins是一个开源自动化服务器,它帮助自动化软件开发过程中的各种任务,如构建、测试和部署。在全球范围内,Jenkins因其强大的功能和灵活性而受到开发社区的青睐。然而,Jenkins在处理非英文字符时遇到的编码问题成为了一个普遍存在的障碍,尤其是在处理中文字符时。

3. 方法

本研究首先通过检查Jenkins系统的字符集编码设置来识别问题源头。我们发现,即便Jenkins运行在UTF-8编码支持良好的环境中,如果没有正确配置环境变量,它仍然可能无法正确处理中文字符。

3.1 系统环境和配置

研究对象为部署在CentOS服务器上的Jenkins,该Jenkins通过Docker镜像运行。我们通过访问Jenkins的系统信息页面, 比如你的jenkins地址是http://localhost:8083,那就访问http://localhost:8083//systemInfo 即可显示系统信息的页面,识别了字符集编码的不一致性,特别是sun.jnu.encoding 和 file.encoding变量未设置为UTF-8。

3.2 解决方案实施

为解决上述问题,我们在Docker容器的配置中加入了特定的环境变量设置。具体而言,在docker-compose.yml文件中添加了如下配置:

version: '3'
services:
  your-service:
    image: your-image
    environment:
      - LANG=C.UTF-8
      - JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8

这一改变确保了Jenkins及其Java环境使用UTF-8作为默认字符编码,从而正确处理中文字符。

4. 结果

应用了上述配置后,Jenkins能够正确识别和显示中文字符。这一结果验证了我们的假设,即通过设置正确的环境变量,可以解决Jenkins中文编码的问题。

5. 讨论

尽管此方法在我们的测试环境中成功解决了问题,但需要注意的是,对于非Java应用,JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8的设置可能不适用。因此,针对不同的应用场景,可能需要进一步的配置调整。

6. 结论

本文通过对Jenkins字符编码设置的调查和调整,成功解决了Jenkins不识别中文字符的问题。这一发现不仅增强了Jenkins在中文环境中的应用,也为解决类似的编码问题提供了参考。

18.读取已创建任务

import requests
import xml.etree.ElementTree as ET

def get_jenkins_jobs(jenkins_url, username, password):
    # 创建一个session对象
    s = requests.Session()

    # Jenkins的登录信息
    s.auth = (username, password)

    # 获取所有任务的列表
    jobs_url = f"{jenkins_url}/api/json"
    r = s.get(jobs_url)
    jobs_data = r.json()

    # 结果列表
    result = []

    # 遍历所有任务
    for job in jobs_data['jobs']:
        # 获取任务的配置
        config_url = f"{jenkins_url}/job/{job['name']}/config.xml"
        r = s.get(config_url)
        config_xml = r.text

        # 解析XML
        root = ET.fromstring(config_xml)

        # 找到任务的描述
        job_description = root.find("description").text if root.find("description") is not None else ""

        # 找到所有的"Build periodically"和"Execute shell"
        build_periodically_list = [bp.text.strip().split('\n') if bp.text else [] for bp in root.findall(".//hudson.triggers.TimerTrigger/spec")]
        execute_shell_list = [es.text.strip().split('\n') if es.text else [] for es in root.findall(".//hudson.tasks.Shell/command")]

        # 查找参数
        parameters = []
        for param_def in root.findall(".//hudson.model.ParametersDefinitionProperty/parameterDefinitions/*"):
            param_name = param_def.find("name").text if param_def.find("name") is not None else ""
            param_description = param_def.find("description").text if param_def.find("description") is not None else ""
            param_type = param_def.tag.split('.')[-1]  # 获取参数类型
            param_default_value = param_def.find("defaultValue").text if param_def.find("defaultValue") is not None else ""
            parameters.append({
                'name': param_name,
                'description': param_description,
                'type': param_type,
                'default_value': param_default_value
            })

        # 添加到结果列表
        result.append({
            'job_name': job['name'],
            'job_description': job_description,
            'build_periodically': build_periodically_list[0] if build_periodically_list else [],
            'execute_shell': execute_shell_list[0] if execute_shell_list else [],
            'parameters': parameters
        })

    return result

# 使用示例
jenkins_url = 'http://192.168.31.113:8084/'
user = 'yys'
passwd = '123456'
jenkins_jobs = get_jenkins_jobs(jenkins_url, user, passwd)
print(jenkins_jobs)

代码说明

  1. 查找参数

    • 在 XML 中查找 hudson.model.ParametersDefinitionProperty/parameterDefinitions 节点下的所有子节点。
    • 提取每个参数的名称 (name)、类型(从标签名称中获取)、默认值 (defaultValue)。
  2. 结果

    • 每个任务的结果包含 job_namebuild_periodicallyexecute_shell 和 parameters。参数是一个包含名称、类型和默认值的字典列表。

通过这种方式,你可以获取 Jenkins 任务的所有参数,并将其包含在结果中。

19.用代码创建任务

可以用18读取字典来创建,已知jobs_list 中字符含有&&会不成功,建议分开写

import requests
from requests.auth import HTTPBasicAuth

def create_jenkins_jobs(jenkins_url, user, passwd, jobs_list):
    for job_dict in jobs_list:
        job_name = job_dict["job_name"]
        job_description = job_dict.get("job_description", "")
        
        # 获取此任务的构建周期设置
        build_periodically = job_dict.get("build_periodically", [])
        if build_periodically:
            html_periodically = "<spec>" + '\n'.join(build_periodically) + "</spec>"
            html_triggers = f"""
            <triggers>
                <hudson.triggers.TimerTrigger>
                    {html_periodically}
                </hudson.triggers.TimerTrigger>
            </triggers>
            """
        else:
            html_triggers = "<triggers/>"
        
        # 获取此任务的执行shell命令列表
        execute_shell_commands = job_dict.get("execute_shell", [])
        html_shell = '\n'.join(execute_shell_commands)
        if html_shell:
            html_builders = f"""
            <builders>
                <hudson.tasks.Shell>
                    <command>{html_shell}</command>
                </hudson.tasks.Shell>
            </builders>
            """
        else:
            html_builders = "<builders/>"
        
        # 获取此任务的参数
        parameters = job_dict.get("parameters", [])
        if parameters:
            html_parameters = "<properties><hudson.model.ParametersDefinitionProperty><parameterDefinitions>"
            for param in parameters:
                param_name = param.get("name", "")
                param_description = param.get("description", "")
                param_type = param.get("type", "")
                param_default_value = param.get("default_value", "")
                if param_type == "StringParameterDefinition":
                    html_parameters += f"""
                    <hudson.model.StringParameterDefinition>
                        <name>{param_name}</name>
                        <description>{param_description}</description>
                        <defaultValue>{param_default_value}</defaultValue>
                        <trim>false</trim>
                    </hudson.model.StringParameterDefinition>
                    """
                # 添加其他参数类型的支持
            html_parameters += "</parameterDefinitions></hudson.model.ParametersDefinitionProperty></properties>"
        else:
            html_parameters = "<properties/>"

        # 生成配置XML
        config_xml = f"""
        <project>
          <actions/>
          <description>{job_description}</description>
          <keepDependencies>false</keepDependencies>
          {html_parameters}
          <scm class="hudson.scm.NullSCM"/>
          <canRoam>true</canRoam>
          <disabled>false</disabled>
          <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
          <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
          {html_triggers}
          <concurrentBuild>false</concurrentBuild>
          {html_builders}
          <publishers/>
          <buildWrappers/>
        </project>
        """
        
        session = requests.Session()
        session.auth = HTTPBasicAuth(user, passwd)
        
        # 获取crumb
        crumb_issue_url = f"{jenkins_url}/crumbIssuer/api/json"
        r = session.get(crumb_issue_url)
        if r.status_code != 200:
            print("获取crumb失败")
            return False
        
        crumb_data = r.json()
        crumb_field = crumb_data['crumbRequestField']
        crumb = crumb_data['crumb']
        
        create_job_url = f"{jenkins_url}/createItem?name={job_name}"
        headers = {'Content-Type': 'application/xml', crumb_field: crumb}
        
        # 发送创建任务请求
        r = session.post(create_job_url, data=config_xml, headers=headers)
        
        if r.status_code in [200, 201]:
            print(job_name + " 任务创建成功")
        else:
            print(job_name + " 任务创建失败,状态码:", r.status_code)
           

# 使用封装函数
jenkins_url = 'http://192.168.31.113:8084/'
user = 'yys'
passwd = '123456'
jobs_list = [
    {
        "job_name": "测试job1",
        "job_description": "这是测试job1的描述",
        "build_periodically": ['H */4 * * *', 'H 15 * * 1-5'],
        "execute_shell": ['echo "Hello, this is Jenkins job 1!"', 'echo "Running first set of commands."'],
        "parameters": [
            {
                "name": "myStringParam",
                "description": "这是一个字符串参数",
                "type": "StringParameterDefinition",
                "default_value": "defaultValue1"
            },
            # 添加更多参数类型
        ]
    },
    {
        "job_name": "测试job2",
        "job_description": "这是测试job2的描述",
        "build_periodically": [],
        "execute_shell": ['echo "Hello, this is Jenkins job 2!"', 'echo "Running second set of commands."'],
        "parameters": [
            {
                "name": "anotherStringParam",
                "description": "这是另一个字符串参数",
                "type": "StringParameterDefinition",
                "default_value": "defaultValue2"
            },
            # 添加更多参数类型
        ]
    }
]
print("每个任务的所有description 中文汉字相加不能超过4个,不然500")
create_jenkins_jobs(jenkins_url, user, passwd, jobs_list)

代码说明

  1. 处理定时触发器

    • 检查 build_periodically 是否存在并生成相应的 XML。
    • 如果不存在,则生成空的触发器节点。
  2. 处理 Shell 命令

    • 检查 execute_shell 是否存在并生成相应的 XML。
    • 如果不存在,则生成空的构建器节点。
  3. 处理参数

    • 检查 parameters 是否存在并生成相应的 XML。
    • 目前仅支持字符串参数,可以根据需要添加更多参数类型。
  4. 生成和发送请求

    • 使用 requests.Session 进行会话管理,并处理 Jenkins 的 crumb 认证。
    • 根据配置生成 XML,并发送创建任务的请求。

通过这种方式,你可以根据任务的具体配置,灵活地创建带有定时触发器、Shell 命令和参数的 Jenkins 任务。18获取的数据可以直接写入

 

已知description输入中文不能超过4个,不然创建失败

 

20.检测已创建的任务,没运行时,则运行

如下方法实现:

import requests
from requests.auth import HTTPBasicAuth

def run_jenkins_job_if_not_running(jenkins_url, user, passwd, job_name):
    session = requests.Session()
    session.auth = HTTPBasicAuth(user, passwd)
    
    # 获取crumb
    crumb_issue_url = f"{jenkins_url}/crumbIssuer/api/json"
    try:
        r = session.get(crumb_issue_url)
        r.raise_for_status()
        crumb_data = r.json()
    except requests.exceptions.RequestException as e:
        print("获取crumb失败: ", e)
        return False

    crumb_field = crumb_data['crumbRequestField']
    crumb = crumb_data['crumb']

    # 检查任务是否在运行
    job_info_url = f"{jenkins_url}/job/{job_name}/api/json?tree=builds[building]"
    headers = {crumb_field: crumb}
    try:
        r = session.get(job_info_url, headers=headers)
        r.raise_for_status()
        job_data = r.json()
    except requests.exceptions.RequestException as e:
        print(f"获取 {job_name} 任务信息失败: ", e)
        return False
    
    is_building = any(build['building'] for build in job_data['builds'])

    if not is_building:
        # 如果任务不在运行,触发任务
        build_url = f"{jenkins_url}/job/{job_name}/build"
        try:
            r = session.post(build_url, headers=headers)
            if r.status_code == 201:
                print(f"{job_name} 任务触发成功")
                return True
            else:
                print(f"{job_name} 任务触发失败,状态码:{r.status_code}")
                return False
        except requests.exceptions.RequestException as e:
            print(f"触发 {job_name} 任务失败: ", e)
            return False
    else:
        print(f"{job_name} 任务已经在运行中")
        return True

# 使用封装函数
jenkins_url = 'http://192.168.31.113:8084/'
user = 'yys'
passwd = '123456'
job_name = "全任务"

run_jenkins_job_if_not_running(jenkins_url, user, passwd, job_name)

这里run_jenkins_job_if_not_running 函数会检查指定名为 "全任务" 的 Jenkins 任务的当前状态。如果该任务没有在运行,该函数会触发这个任务。如果任务已经在运行中,则不会执行任何操作。需要注意的是,这段代码可能需要根据您的 Jenkins 配置进行适当的调整。