首先贴出启动命令

docker run -d \
  --name jenkins2 \
  --log-opt max-file=1 \
  --log-opt max-size=200m \
  -p 50000:50000/tcp \
  -p 8080:8080/tcp \
  --restart=always \
  --user root \
  -v /etc/localtime:/etc/localtime \
  -v /data/jenkins/jenkins_home:/var/jenkins_home \
  -v /data/jenkins:/data \
  -v /usr/bin/docker:/usr/bin/docker \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /data/jenkins/jenkins_war:/usr/share/jenkins \
jenkins/jenkins:lts

启动命令详解:

1.关于jenkins官方镜像

docker搭建jenkins,获取官方镜像是第一步

查看docker hub https://hub-stage.docker.com/search?q=jenkins 

镜像已经不维护

 

查看jenkins官网 https://www.jenkins.io/zh/doc/book/installing/#prerequisites 

尝试下载发现 jenkinsci/blueocean 最新版本为一年半之前更新,运行之后jenkins也并非比较新的版本

 

 就在我一筹莫展时看到这个篇:https://blog.csdn.net/weixin_44869002/article/details/133848647

使用docker search之后确认 jenkins/jenkins:lts 为官方镜像

 到此,最新官方镜像找到了:jenkins/jenkins:lts

下载下来之后,更新时间也很新

 

 2.启动命令参数详解

我jenkins通过docker部署有个原则,就是所有要用到的东西,能和主机共用尽量共用,能本地化尽量本地化存储,只是借用一个docker容器的壳,来保持jenkins运行环境的纯净和更新

 大部分启动命令参数jenkins官网都有解释:https://www.jenkins.io/zh/doc/book/installing/#prerequisites 

 

 

 docker run -d \                                                                   #后台运行
  --name jenkins2 \                                                              #容器名称
  --log-opt max-file=1 \                                                        #限制 jenkins容器日志个数
  --log-opt max-size=200m \                                               #限制 jenkins容器日志大小
  -p 50000:50000/tcp \                                                        #jenkins服务端口映射
  -p 8080:8080/tcp \                                                            #jenkins服务端口映射
  --restart=always \                                                             #容器自启动
  --user root \                                                                      #使用root用户启动
  -v /etc/localtime:/etc/localtime \                                        #和主机共用时区文件,保持容器内时区为CTS
  -v /data/jenkins/jenkins_home:/var/jenkins_home \         #映射宿主机本地目录为jenkins存储目录
  -v /data/jenkins:/data \                                                      #映射宿主机本地文件夹到jenkins容器(储存工具类软件)
  -v /usr/bin/docker:/usr/bin/docker \                                   #和主机共用docker文件(用于项目打包成docker镜像文件 docker build,docker push)
  -v /var/run/docker.sock:/var/run/docker.sock \                  #容器与Docker守护进程通信
  -v /data/jenkins/jenkins_war:/usr/share/jenkins \              #存储docker运行war包,始终保持最新war包存储在本地
jenkins/jenkins:lts

 

-v /etc/localtime:/etc/localtime

-v /usr/bin/docker:/usr/bin/docker

-v /var/run/docker.sock:/var/run/docker.sock

这三个不多说,一个是保持容器内时区和主机一样,为CTS,一个是共用主机docker组件用于打包,还有一个是容器与Docker守护进程通信

 

docker 容器内的jenkins运行命令为

 java -Duser.home=/var/jenkins_home -Djenkins.model.Jenkins.slaveAgentPort=50000 -Dhudson.lifecycle=hudson.lifecycle.ExitLifecycle -jar /usr/share/jenkins/jenkins.war

 

/var/jenkins_home:从启动命令可以看出,这是jenkins容器内部的部署目录,映射出来防止jenkins所有数据丢失

/usr/share/jenkins/:从启动命令可以看出,这是jenkins的war包存放目录,映射出来为了方便jenkins后续的升级,始终保持最新版本的war包不会丢失

 

容器内jdk版本为jdk17

 目前jenkins jdk主推17及以上了,原来我用的老版本的镜像时,会提示这个问题

 

3.编译环境搭建

 上面还有个映射目录没说,就是

 -v /data/jenkins:/data

这个主要是用来存储编译所要用到的工具,包括,jdk,maven,nodejs等

这里采取编译服务器和Jenkins服务器共用的方式,如果构建任务很多,可以采用jenkins单独部署,然后调用编译服务器Jenkins_slave的方式

 config dockerfiles为有些项目dockerfile是外置的,并没有储存在git上,这种场景所使用。当然这种方式不推荐,还是推荐dockerfile放在git上和代码一起存储的方式

下面着重说下编译环境和jenkins容器共用的配置方式

编译环境的配置在jenkins里有两种方式

一种是在jenkins里面配置:在系统管理,全局工具配置里配置,然后在搭建jenkins项目时选中对应的工具

第二中是不在jenkins里面配置:在搭建项目时直接在命令行指定工具的参数到环境变量里,作为系统临时变量使用

当然还是推荐用第一种方式,因为和jenkins集成度高,有利于平滑升级,也有利于后期修改参数:只用在全局工具配置一个地方修改就行

第二种方式不仅需要单独配置环境,一旦工具路径修改,要把所有相关的jenkins项目全部修改一遍,不推荐

 

(1)在jenkins里面配置

 打开系统管理

 打开全局工具配置

 配置jdk,路径为容器内路径,可以新增多个,然后在jenkins项目里选择

 配置maven,路径为容器内路径,可以新增多个,然后在jenkins项目里选择

 配置nodejs,路径为容器内路径,可以新增多个,然后在jenkins项目里选择

 

 最后在jenkins项目里引用即可

system为 jenkins容器自带的 jdk 17

 

nodejs版本可以在这里选

 

 

 (2)不在jenkins里面配置

有两种方式:

可以在docker容器内和容器映射目录建立/usr/local/bin/软连接的方式

ln -s /data/nodejs/nodejs/bin/node /usr/local/bin/node
ln -s /data/nodejs/nodejs/bin/npm /usr/local/bin/npm
ln -s /data/nodejs/nodejs/bin/yarn /usr/local/bin/yarn


ln -s /data/nodejs/pnpm/pnpm-linux-x64 /usr/local/bin/pnpm

另外我这里要配置pnpm的环境,jenkins里面暂时没找到,就手动下载并建立软连接,之后运行也是可行的

参照pnpm官网 https://pnpm.io/zh/installation 获得安装脚本

 

在脚本里获得包下载地址 https://github.com/pnpm/pnpm/releases/

 建立软连接之后,运行pnpm -v

 

或者在jenkins任务里面指定临时环境变量

export PATH="/data/nodejs/nodejs-20/node-v20.12.2-linux-x64/bin:$PATH"

这里有个疑问,就是如果path里面包含其他版本的node,这样会生效吗,其实不用担心,path也有优先级的概念,排在前面参数优先级高,就保证了用这种方式肯定生效

 参考文档:https://www.jianshu.com/p/00940e99252a

 

4.jenkins及容器的升级操作

(1)jenkins升级

很简单,直接在页面点升级,重启即可,由于做了war包存储空间映射本地,就是换jenkins镜像了,还是可以保持jenkins版本为最新版本

(2)jenkins镜像升级

直接拉取最新的官方镜像,删除原容器

docker有一点做的很好就是本地文件卷,删容器完全不用担心会影响到本地卷里的文件,重新启动镜像也会以本地路径覆盖容器内路径,这样就做到了删除和升级容器操作完全无影响

docker pull jenkins/jenkins:lts
docker rm -f jenkins2

重新执行启动命令

docker run -d \
  --name jenkins2 \
  --log-opt max-file=1 \
  --log-opt max-size=200m \
  -p 50000:50000/tcp \
  -p 8080:8080/tcp \
  --restart=always \
  --user root \
  -v /etc/localtime:/etc/localtime \
  -v /data/jenkins/jenkins_home:/var/jenkins_home \
  -v /data/jenkins:/data \
  -v /usr/bin/docker:/usr/bin/docker \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /data/jenkins/jenkins_war:/usr/share/jenkins \
jenkins/jenkins:lts

由于关键数据都进行了本地化映射,所以容器运行起来就可以,无需额外操作

不过如果有些工具没有通过jenkins工具配置,需要进入新的jenkins容器,执行建立软连接操作

docker exec -it jenkins /bin/bash

ln -s /data/nodejs/nodejs/bin/node /usr/local/bin/node
ln -s /data/nodejs/nodejs/bin/npm /usr/local/bin/npm
ln -s /data/nodejs/nodejs/bin/yarn /usr/local/bin/yarn

ln -s /data/nodejs/pnpm/pnpm-linux-x64 /usr/local/bin/pnpm

 

docker run命令启动不利于后期维护,所以这里换成docker-compose.yml文件的方式

#name: jekins
version: "3"
services:
    jenkins:
        container_name: jenkins3
        ports:
            - 50000:50000/tcp
            - 8080:8080/tcp
        restart: always
        user: root
        environment:
            JAVA_OPTS: "-server -Xms6144m -Xmx6144m"
        volumes:
            - /usr/bin/docker:/usr/bin/docker
            - /var/run/docker.sock:/var/run/docker.sock
            - /data/jenkins/jenkins_war:/usr/share/jenkins
            - /etc/localtime:/etc/localtime
            - /bin/zip:/bin/zip
            - /data/jenkins/jenkins_home:/var/jenkins_home
            - /data/jenkins:/data
        image: jenkins/jenkins:lts

日志大小限制,在/etc/docker/daemon.json文件里已经配置,所以这里就不加了

这里有个docker run命令转docker-compose.yml文件的工具,强烈推荐:https://www.composerize.com/

参考文档:https://blog.csdn.net/wohu1104/article/details/132159027

 

 

 

升级到最新版jenkins遇到的问题:

构建报错:Stderr: fatal: not in a git directory

一、问题描述:
使用jenkins构建一条流水线,拉取代码时,报错not in a git directory
已配置凭据。
二、问题原因:
这个安全问题在Git v2.35.2及更高版本中开始出现,Git现在检查文件夹的所有权,试图确保使用Git的文件夹的所有者与当前用户帐户的所有者相同。
三、问题解决
删除原workspace,重新执行,不报错了

 查看新建的目录权限,发现为root:root,正是jenkins容器内启动jenkins进程的用户

于是把workspace这个目录变成root:root权限即可

chown -R  root:root workspace

参考文档:https://blog.csdn.net/archereid/article/details/136376356

 

5.jenkins备份

jenkins备份的意义不言而喻,仅次于git的备份

检查jenkins目录,发现一个问题,就是占用空间最大的文件是jenkins_home里的workspace,这是用来进行编译打包的目录,这个文件夹是可以随意删除的,重新执行job就会自动生成

所以备份jenkins正好可以排除workspace目录,其他的文件占用空间还算合理,我这里就全量备份了,先看一下排除workspace后的空间

du -sh /data/jenkins --exclude="/data/jenkins/jenkins_home/workspace"

 

本来想先压缩再拷贝到其他目录

tar -zcvf jenkins.tar.gz /data/jenkins --exclude="/data/jenkins/jenkins_home/workspace"

问题来了,由于jenkins文件很多,压缩一下2小时,后面还要传输,考虑到再解压2小时,这对容灾恢复是不能容忍的

再看jenkins文件的压缩率也不高,就显得压缩没太大意义了

一番权衡之后,我觉得最佳的备份方式还是用rsync工具不压缩直接传输文件(忽略掉workspace目录),由于在内网传输速度很快,再加上rsync的特性:支持增量备份,后面备份只传输增量修改的内容,没修过的不传输,节省备份空间和时间,堪称完美!

下面是我的备份脚本

#!/bin/bash
datetime=`date +%Y%m%d-%H-%M-%S`
logfile=$1
echo "$datetime Rsync backup start "  > $logfile
rsync -e "ssh -p22" -avpgolr  --delete --exclude="jenkins_home/workspace" /data/jenkins  bigtree@10.30.30.6:/data/backup_data/bigtree/10.30.30.8/ >> $logfile 2>&1

ret=`tail -n 1 $logfile |grep "total size"|wc -l`
if [ "$ret" =  1 ] ; then
        echo "$datetime Rsync backup finish " >> $logfile
else
        echo "$datetime Rsync backup failure ,pls sendmail"  >> $logfile
fi

这里有一点要说明

1.使用rsync,首先要在源文件机器上做备份机器的对等性认证,实现免登录

2.rsync的排除文件参数 --exclude必须要使用相对路径!这点很重要

 rsync  --exclude 使用参考文档:https://www.cnblogs.com/xzongblogs/p/14326948.html

 

新建corntab定时任务,每天晚上12点备份

备份脚本在同步目录里(/data/jenkins),保证了jenkins备份脚本和日志也同样有备份

0 0 * * * /bin/bash -x /data/jenkins/backup/script/jenkins_rsync.sh /data/jenkins/backup/jenkins_rsync.log > /data/jenkins/backup/jenkins_cron.log 2>&1

 

-----------------------------------------------------------------------------实践分割线--------------------------------------------------------------------------------------------------------

刚通过docker搭了个jenkins用于生产环境发版,踩了一些坑,特意做个总结

业务背景:

1.生产环境和测试环境网络隔离

2.生产环境访问不了外网

3.生产环境开了一个网络白名单,只能连接测试环境的一台主机ssh端口,用于拉取发版文件

 

根据以上特点,综合考虑安全因素,这里采用在测试环境jenkins打包,生产环境jenkins部署的方式 

 

搭建遇到的问题:

1.离线导入jenkins镜像

由于生产机器连不了外网,所以这里只能在测试环境docker主机上拉取jenkins镜像,打包上传到生产环境机器,再导入镜像

-----测试环境

#拉取jenkins镜像
docker pull jenkins/jenkins:lts
#查看镜像
docker images
#打包
docker save -o jenkins_save.tar 镜像id

------生产环境

#导入镜像
docker load -i jenkins_save.tar
#查看镜像
docker images
#给镜像打tag
docker tag 镜像id jenkins/jenkins:lts

至此jenkins镜像导入生产环境

 

2.docker run命令转docker-compose

之前测试环境的jenkins是通过docker run命令启动的,不利于后期维护,这次直接转成docker-compose的方式

但是docker run命令涉及的参数比较多,所以我在想有没有一个工具可以转换的,还真找到了!

 

工具地址:https://www.composerize.com/

参考文档:https://blog.csdn.net/wohu1104/article/details/132159027

经过一番修改,docker-compose.yml文件如下

version: "3"                                                                                                                                                                                                                 
services:                                                                                                                                                                                                                     
    jenkins:                                                                                                                                                                                                                  
        container_name: jenkins                                                                                                                                                                                               
        ports:                                                                                                                                                                                                                
            - 50000:50000/tcp                                                                                                                                                                                                 
            - 1000:8080/tcp                                                                                                                                                                                                   
        restart: always                                                                                                                                                                                                       
        user: root                                                                                                                                                                                                            
        volumes:                                                                                                                                                                                                              
            - /usr/bin/docker:/usr/bin/docker                                                                                                                                                                                 
            - /var/run/docker.sock:/var/run/docker.sock                                                                                                                                                                       
            - /etc/localtime:/etc/localtime                                                                                                                                                                                   
            - /data/servers:/data/servers                                                                                                                                                                                     
            - /home/webs:/home/webs                                                                                                                                                                                           
            - /root/.ssh:/root/.ssh                                                                                                                                                                                           
            - /usr/bin/rsync:/usr/bin/rsync                                                                                                                                                                                   
            - /usr/lib64/libpopt.so.0:/usr/local/lib/libpopt.so.0                                                                                                                                                             
            - ./jenkins_home:/var/jenkins_home                                                                                                                                                                                
            - ./:/data/tools                                                                                                                                                                                                  
        image: jenkins/jenkins:lts

 

3.离线导入jenkins插件

这个一开始我乐观了,以为在页面上导入即可

从官网下载插件:https://updates.jenkins-ci.org/download/plugins/,再从页面导入

 后来发现不是这么回事,jenkins插件是互相调用的,有时候装一个插件要连续下10个插件,才能解决依赖关系

我知道jenkins有离线下载工具,但是下载的插件清单我也不清楚,而且还要搭建运行工具的环境,比较繁琐

就在我一筹莫展的时候看到这个:https://www.jianshu.com/p/f94405ea7727

方式二:
 先在有外网环境的机器上安装jenkins,在线安装需要的插件后,将.jenkins/plugins目录覆盖,重启即可完成插件安装。

对啊,我在外网搭建一个一样的jenkins,安装完需要的插件,再把目录拷贝至生产环境覆盖,不就行了!

docker搭建服务本就简单

于是开始操作

jenkins启动完,解锁之后

 

直接选择默认方式安装插件,这样会把所有常用的插件都装上,包括语言汉化等等

 

 

接着要选择jenkins远程部署必须的插件,这里我蒙圈了,不过还好理出了头绪

远程安装最常用的方式就是通过ssh,于是我搜索ssh插件

 这里ssh插件是 build步骤的 Execute shell script on remote host using ssh,官方已经不推荐使用了,有安全隐患,而且6年没更新了,直接pass

 

ssh server插件实际上是把jenkins作为ssh服务器,执行jenkins cli命令,暂时用不到

ssh agent插件意思是说允许你通过ssh私钥的方式调用ssh 节点,具体怎么用还没搞明白

https://plugins.jenkins.io/ssh-agent/

 

最符合jenkins通过ssh方式远程部署服务的插件是 Publish Over SSH

 

安装上即可

最后打包外网机器上的plugins目录上传至生产对应目录覆盖,插件安装完成。

 

4.拉取远程主机文件

这个问题困扰了我好久,jenkins没有现成可用的工具可以满足拉取远程服务器文件的功能

只能自己写脚本了,一开始想通过sftp命令,略显复杂,最终还是决定用 rsync命令拉取文件

rsync命令的配置又踩了不少坑。。

 (1)docker共用主机对等性认证文件

首先在宿主机上配置到远程文件服务器的对等性认证

 在测试环境服务器上新建package账号,赋权本地路径

#新建账号
useradd -m -s /bin/bash package
#设置密码
passwd package
#配置路径权限
chown -R package:package /data/jenkins/package

注意:这个路径同时为 测试机器上 jenkins容器映射路径,方便打包完之后,拷贝过来

在生产机器上执行

#生成密钥文件,输入完一直回车
ssh-keygen
#拷贝公钥文件到服务器主机上
ssh-copy-id -i ~/.ssh/id_rsa.pub -p 端口 package@10.30.30.6
#测试是否配置成功,可以免密登陆,即登陆成功
ssh package@10.30.30.6 -p 端口

到这里还没完,生产宿主机配置了对等性验证,还需要映射到jenkins容器中供容器使用

            - /root/.ssh:/root/.ssh   

配置映射到docker-compose.yml,启动并进入jenkins容器,再执行ssh命令测试,可以免密登陆了!

 

(2)共用主机rsync组件

jenkins容器内,并没有安装rsync命令,而生产环境连不了外网,所以最好的方式是让jenkins容器共用主机rsync组件

在生产宿主机上安装rsync,因为生产环境有单独的yum源

#在生产宿主机上安装rsync
yum install rsync -y
#测试rsync是否正常,这里测试连的是那台测试环境机器,指定了ssh端口,可以正常拉取文件即可
rsync -e "ssh -p端口" -av --delete package@ip:/data/jenkins/package/xxx/  /data/servers/xxx/jars 

映射rsync到jenkins容器

            - /usr/bin/rsync:/usr/bin/rsync 

把文件映射到jenkins容器内,重启容器后,本以为完事了,结果又报错了

#进入jenkins容器
docker exec -it jenkins /bin/bash
#执行rsync命令
rsync

报错:rsync: error while loading shared libraries: libpopt.so.0: cannot open shared object file: No such file or directory 

很明显缺少libpopt.so.0依赖,但是又不能连外网,安装不了啊

于是我就想既然rsync可以映射到jenkins容器内,libpopt.so.0应该也可以

于是开始查找宿主机上的libpopt.so.0文件

 find / |grep libpopt.so.0 

还真找到了

参考文档:https://blog.csdn.net/keeprunper/article/details/131896833 

于是映射到jenkins容器

            - /usr/lib64/libpopt.so.0:/usr/lib64/libpopt.so.0 

 本以为解决的时候,进入容器运行rsync命令还是报错

就这我一筹莫展的时候看到这篇文章:https://blog.csdn.net/qq_15821487/article/details/122985321

在/etc/ld.so.conf.d/目录下加入的任何以.conf为后缀的文件都能被识别到

 我在容器内看了下,/usr/loacal/lib天生就有,我把libpopt.so.0放到这里是不是就可以

于是开始重新映射

            - /usr/lib64/libpopt.so.0:/usr/local/lib/libpopt.so.0   

然后再重新进入容器,运行 ldconfig 命令,以更新配置文件;

#进入容器
docker exec -it jenkins /bin/bash
#运行ldconfig
ldconfig
#测试rsync
rsync

这个时候,rsync可用了,我可真是天才~

 

至此 jenkins容器内部rsync命令配置完成,jenkins通过ssh拉取远程主机的功能得以实现!

同样的,容器要用到zip命令也可以通过同样文件映射的方式共用宿主机的zip

            - /bin/zip:/bin/zip

 

5.共用主机相关的文件

就是在jenkins宿主机上有些服务需要jenkins部署,jenkins容器需要读取到他们的目录

            - /data/servers:/data/servers                                                                                                                                                                                     
            - /home/webs:/home/webs       

 

6.zip压缩多个文件,解压时不包含目录层级

这个问题也比较棘手,就是前端打包出的文件是dist,压缩时不想带上dist目录

一开始想到的时用

zip -rj

 -j : 只储存文件的名称,不含目录。

但是会有问题,就是dist目录里还是有文件夹的,打包的时候需要带上,用 -j内部文件夹也没了

看来需要其他办法,好在找到了

假设我们有个目录叫 dev,dev中有很多文件,我们想要将dev中的文件打包,名字可能叫dev.zip,但当我们解压的时候,不想要解压生成一个dev目录,想要直接解压在当前目录,这样如何压缩呢

# 进入dev目录
$ cd dev
$ zip -r ../dev.zip *
# 这时候一个dev.zip文件就已经被打包在dev目录上一级目录中了

以上!

参考文档:https://blog.csdn.net/w_monster/article/details/120314597

 

posted on 2023-06-13 11:22  06  阅读(84)  评论(0编辑  收藏  举报