一、前言
公司用的jenkins+docker自动发版,本人自己也试着配置了下,踩了无数的坑后,终于配置成功了。在此做下笔记,总结下碰到的坑和解决办法。
二、jenkins配置
1.首先,升级jenkins肯定要小心,不要任意升级。
原来想给jenkins下载个权限管理插件Matrix-based security(基于矩阵的安全性),效果提示jenkins版本太低,用不了;
问chatgpt,怎么升级jenkins,回答说换个新版jenkins的war包就行;
然后就出了各种问题,换了个比较新的war包后、流水线格式都乱了,根本没法用;
回退成原来的war包,发现流水线内容丢失,出现了无法辨认的数据,吓个半死,之前的流水线出了问题直接凉凉;
最后干脆换了个最新版的jenkins的war包,好歹流水线能正常表现了,但是权限管理插件还是用不了。
白忙活一场,证明升级jenkins,只换war包还是有问题的;可能需要装个完备版才行,然后想办法把旧的流水线迁移到新的jenkins。
2.创建流水线与配置
首先创建一个自由格式的;
这个链接类型,选的是Gitee,代码在Gitee上;
Url是gitee的代码所在;Credentials用的是ssh链接方式;代码分支选的是拉取master分支。
3.ssh链接方式配置方法
打开自己的gitee项目,下载时选ssh,这个链接就是填写到jenkins的下载链接(直接git@gitee.com)开头就行,不用修改;
下面这个下令,是告诉你怎么创建ssh公钥和私钥;
把这个下令复制到cmd窗口实行,一起回车,就会生成一个公钥和私钥;
此中,第一个回车是让你选择一个文件生成位置,不选就按默认路径;
第二个回车是让你输入加密空间,就当是读取私钥时用的密码就行,假如为空就是没有密码直接就能读取;
第三个回车是确认私钥密码;
然后就在提示的位置生成了公钥id_rsa.pub,私钥id_rsa。
下一步,把公钥配置到自己的gitee项目上;
打开自己的一个项目,点击右上的设置(Settings),左下是Key management,再点右边的添加key;
标题任意输入,下面的内容就是刚才创建的id_rsa.pub内里的内容,整个复制填进去就行,不用改;
添加完成后,回到jenkins,把刚才创建的私钥id_rsa配置进去;
本人项目里有其它的私钥了,就任意选一个,点全局域按钮;
点击添加;
类型选择ssh类型,作用域是global,ID任意写,Username任意写;私钥选直接输入;然后点击右边的Add按钮,把之前创建的私钥id_rsa整个复制进去就行,留意不要删掉第一行和最后一行注释;
下面的Passphrase就是刚才创建私钥时输入的密码,解密私钥用的,假如为空就不用写。(感觉像密码钥匙,没有密码就用不了钥匙一样)
创建好之后,jenkins流水线就能用这个ssh来拉取代码了。
4.jenkins报错无法拉取代码解决方法
这里有一个坑,jenkins流水线,填写刚才的gitee代码所在、选择ssh验证用私钥后,可能会报错;
因为jenkins默认对于ssh的设置是known hosts file模式,也就是知道代码服务器主机的意思;
假如没有配置过,那么jenkins就会认为,你这个代码所在的主机不安全,不是我已知的主机,不能拉取代码;
解决方法有两个,第一个,就是修改jenkins设置:
把这个改成Accept first connection,但是如许改不太好;
第二个方法就是,让jenkins知道这台代码主机。
可以登录jenkins所在的服务器,找到配置文件目次,比方/var/lib/jenkins/.ssh/known_hosts,这个文件里就是jenkins已知主机的配置;
然后实行:
- ssh-keyscan -H gitee.com >> ~./known_hosts
复制代码 如许,就能把gitee.com添加到jenkins已知主机列表里,就不会报错了。
5.配置jenkins代码钩子
代码钩子的作用是,当gitee上的代码被push后,gitee就会自动给你的jenkins服务器发送一个请求,表示自己的代码被更新了;
然后jenkins就会自动实行流水线操纵,自动发版。
假如不需要就跳过,需要的话就如下配置:
这个trigger里,选择了监听push events,opened pull requests events,然后jenkins给了一个钩子所在,这个稍后配置到gitee上;
jenkins还给了一个钩子密码,secret token for gitee webhook,这个稍后也配置到gitee上。
然后回到gitee堆栈,选webhook,添加,这里配置了push变乱,url和password就写jenkins提供的那两个,添加,就完成了;
后续这个代码堆栈、触发push时,就会调用jenkins接口,header参数里传密码,通知jenkins。
6.配置docker打包下令
继续jenkins配置:
增加一步,实行shell脚本;
参考内容如下:
- pwd
- export JAVA_HOME=/var/lib/jenkins/workspace/test/jdk8/jdk1.8.0_212
- /usr/bin/mvn clean package -f ./pom.xml
- echo 'start'
- service_name="homepage-backend-1.0"
- #search image id
- IID=$(docker images | grep "$service_name" | awk '{print $3}')
- echo "IID $IID"
- if [ -n "$IID" ]
- then
- echo "exist $service_name image,IID=$IID"
- #remvoe image
- docker image rm $service_name
- echo "delete $service_name image"
- #build image
- docker build -t $service_name .
- echo "build $service_name image"
- else
- echo "no exist $service_name image,build docker"
- #build image
- docker build -t $service_name .
- echo "build $service_name image"
- fi
- # save image
- docker save $service_name > ./$service_name.tar
复制代码 说明:
jenkins实行这个流水线后,第一步就是从gitee上拉取代码,上面配置过了;
第二步就是实行这个sh脚本;
首先,创建流水线的名字叫test,所以jenkins就会在本地/var/lib/jenkins/workspace/里,创建一个文件夹test,也就是/var/lib/jenkins/workspace/test/,然后把代码拉取到这个地方,这个sh脚本实行时的当前路径,也是这个路径;
然后实行export JAVA_HOME,是临时创建一个情况变量,只在这个脚本内生效,选择了1.8版本的jdk,打包会用;
然后实行/usr/bin/mvn clean package -f ./pom.xml,这个下令就是选择让/usr/bin/mvn这个文件,实行下令clean package,也就是服务器上安装了maven,maven实行打包下令,根据当前路径的./pom.xml来实行;代码已经拉取到这个路径下了,pom.xml文件是存在的;
打包完毕后,开始实行docker下令;
声明一个变量service_name,值是homepage-backend-1.0;
先用docker images查看下这个镜像是否存在,假如存在,就docker image rm删除这个镜像,docker build -t $service_name .创建一个新镜像;假如不存在,就直接创建一个新镜像;
留意最后的.是有作用的,表示用当前路径的Dockerfile来创建镜像;
创建完成后,就用docker save $service_name > ./$service_name.tar把这个镜像生存到当前路径,名字是homepage-backend-1.0.tar。
7.DockerFile内容
第六步中,主要就是先用maven把项目打成jar包,然后用docker把jar包打成tar包。
需要服务器上安装了docker,而且当前路径有Dockerfile文件;
本人项目的文件就是/var/lib/jenkins/workspace/test/Dockerfile,内容如下:
- # 使用java8 (1.8)
- FROM openjdk:8-jdk-alpine
- #创建一个挂载点
- VOLUME /tmp
- # 需要暴露的端口,这个不用
- #EXPOSE 9090
- #安装字体
- RUN apk add --update font-adobe-100dpi ttf-dejavu fontconfig
- #复制到容器内部
- COPY ./myproject/target/my.jar my.jar
- # 容器启动时执行的方法
- ENTRYPOINT ["java","-Duser.timezone=GMT+09","-jar","/my.jar", "&"]
复制代码 说明:
首先给容器内选了jdk8;
然后创建了一个挂载点/tmp,这个是把docker容器内的/tmp路径映射到宿主机的/tmp目次下,如许相称于容器内/tmp里的东西、也会写到宿主机/tmp;相称于做了数据长期化,当容器关闭的时候这些数据也会留下来;
然后把当前路径下的./myproject/target/my.jar复制到docker容器根目次下;这个jar包,是mvn打包完成后生成在target目次里的;
然后容器启动时,自动实行java -Duser.timezone=GMT+09 -jar /my.jar &下令。
8.jenkins把文件推送到目的服务器
如今的效果是、在当前路径下生成了tar包;需要把这个包推送到目的服务器,然后在目的服务器上启动这个docker镜像。
jenkins增加一步,Send files or execute commands over SSH;
选择目的服务器;
填写source files,就是当前路径下打包好的homepage-backend-1.0.tar;
填写远程服务器路径,到时候传过去就是/home/web/webcode/homepage-backend-1.0.tar;
填写需要实行的下令,先实行了cd下令,然后实行sh文件。
9.jenkins配置目的服务器方法
jenkins设置,找到SSH Server,增加;
name任意,hostname,比方128.128.128.1,username,比方root,远程服务器起始所在,/,远程服务器key,也用的ssh-key,私钥整个复制进去就行。
远程服务器配置ssh登录密钥的方法:
也是同样,先生成ssh公钥私钥;
然后找到服务器,某个用户的目次,然后找到authorized_keys文件,比方:/home/user1/.ssh/authorized_keys;(root用户在/root/.ssh)
把公钥里的内容整个复制到这个文件内里即可。
私钥就配置到jenkins里,登录用。
10.目的服务器启动docker下令
目的服务器,有一个/home/web/webcode/start_homepage_backend_docker.sh文件,内容如下:
- #!/bin/bash
- service_name="homepage-backend-1.0"
- image_port=9000
- service_port=9000
- image_pre=dev
- image_log=/H_LOG
- server_log=/home/web/webcode/logs
- #查看容器id
- CID=$(docker ps -a | grep "$service_name" | awk '{print $1}')
- echo "CID $CID"
- if [ -n "$CID" ]
- then
- echo "exist $service_name container,CID=$CID"
- #停止
- docker stop $service_name
- #删除容器
- docker rm $service_name
- else
- echo "no exist $service_name container"
- fi
- #查看镜像id
- IID=$(docker images | grep "$service_name" | awk '{print $3}')
- echo "IID $IID"
- if [ -n "$IID" ]
- then
- echo "exist $service_name image,IID=$IID"
- #删除镜像
- docker image rm $service_name
- echo "delete $service_name image"
- #构建
- docker load < ./$service_name.tar
- echo "load $service_name image"
- else
- echo "no exist $service_name image,build docker"
- docker load < ./$service_name.tar
- echo "load $service_name image"
- fi
- #启动
- echo "if use --network host, then -p is useless."
- docker run -d --name $service_name --network host -e e_logback_path="$image_log" -e e_spring_active="$image_pre" -p $service_port:$image_port -v $server_log:$image_log $service_name
- #查看启动日志
- #docker logs -f $service_name
复制代码 说明:
声明白好几个变量,供后面用;
首先用docker ps -a查看当前所有启动的容器,假如有目的容器,就先docker stop 停止容器,docker rm删除容器;
然后用docker images查看当前所有镜像,假如有目的镜像,就先docker image rm删除镜像,然后用tar文件docker load < ./$service_name.tar创建一个镜像,否则就直接创建;这个文件就是jenkins传来的homepage-backend-1.0.tar;
镜像有了后,就用docker run根据镜像启动容器,此中-d --name是启动后的容器名称,--network host表示这个容器的网络是主机模式,与宿主机共用ip端口;-e是传入两个体系情况变量;-p原来是把容器端口映射到宿主机端口用的,但是主机模式下这个写了没用;-v就是之前的VOLUME,把容器的路径映射到宿主机的路径;最后的一个参数$service_name表示容器启动依据的镜像名称。
11.docker相干笔记
docker可以分两部门,镜像与容器;
镜像用docker images查看;镜像可以方便的在不同服务器迁移(打好的tar包);
容器用docker ps -a查看;容器需要根据镜像启动;
个人感觉docker就相称于一个虚拟机了,一个linux上可以有很多多少个docker容器,每个容器/虚拟机内里都有自己的linux体系,有自己独立的ip:端口;
容器里有自己的文件路径,可以用-v映射到宿主机的路径,可以用来打印日志(查看日志的时候,在宿主机路径看就行了,不用进入容器内部了;当容器销毁,也不用担心日志消失);
容器有自己独立的ip:端口;可以用-p把容器端口映射到宿主机上;比方-p $service_port image_port,-p 80:8080,假如容器内启动了一个jar包,端口是8080;如今使用宿主机ip:80就相称于访问容器内jar包的8080端口;
由于本人项目中,mysql也在宿主机上,之前可以用localhost:3306访问;但是假如jar包在容器内部,就不能用localhost:3306访问了(如许访问的是容器自己的3306端口);虽然可以用docker给宿主机虚拟出来的本地ip来访问(局域网ip),但是雷同的本地应用另有很多;干脆换成--network host模式更简单,直接与宿主机共享ip端口,如许就可以继续用localhost访问了。
12.把docker运行时情况变量通报给jar包的方法
上面使用了-e e_spring_active="$image_pre",设置了两个docker容器情况变量,相称于-e e_spring_active="dev";
在java项目的application.yml里,是如许配置的:
- spring:
- profiles:
- active: ${e_spring_active:dev}
复制代码 这个意思是,假如有体系情况变量e_spring_active,那就用;假如没有,那就用dev;
如许就能读取application-dev.yml或者application-prod.yml,根据参数不同使用不同配置文件。
13.目的服务器实行sh失败的坑
由于jenkins链接目的服务器的用户权限不足,又不想把管理员用户配置到jenkins里,就出现了两个权限问题;
一个是sh文件实行权限,先换管理员用户,使用chmod 777 start_homepage_backend_docker.sh给这个sh文件设置了所有用户都可以实行的权限;
一个是docker权限,需要把用户参加docker组(docker规定,要不是管理员,要不就是docker组用户,才气用),才气实行,否则也会报错。
- #把user1添加到docker组
- groups user1
- sudo usermod -aG docker user1
复制代码 另有一个坑,是因为下令有docker load < ./$service_name.tar,是把当前目次的$service_name.tar读取成镜像,所以肯定要留意,实行下令时的位置在那里,肯定要先cd 到目的路径,才气找到这个tar文件,否则也会报错。(搜错误信息,很难想到是找不到tar的错误,坑)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |