CICD03 Jenkins对golang项目构建, 结合ansible, 构建通知, 自动化构建(定时,webhook), docker容器化构建 ubuntu使用
2.7.2 基于 Maven 风格的任务构建基于WAR包运行 Tomcat服务器 JAVA 项目
目前最高依赖到tomcat9,更高版本的tomcat不支持
2.7.2.2 安装 tomcat 服务器和配置
#在gitlab新建 java 项目(此项目使用JDK-11,不支持JDK-8) https://gitee.com/lbtooth/hello-world-war.git #目标服务器 #安装tomcat ]#apt install tomcat9 #tomcat环境装备(tomcat管理页面功能) ]#apt install tomcat9-admin ]#vim /etc/tomcat9/tomcat-users.xml ... <role rolename="manager-gui"/> <role rolename="manager-script"/> <user username="tomcat" password="tomcat" roles="manager-gui,manager-script"/> </tomcat-users> ]#systemctl restart tomcat9.service #此时tomcat的管理页面可以登录进入 (用户名密码都是tomcat) http://10.0.0.153:8080/ #jenkins插件依赖tomcat的管理页面可以实现部署(角色manager-script是jenkins控制需要的)
安装 Maven Integration 插件实现Maven风格的任务
安装 Deploy to container 插件实现连接 tomcat
2.7.2.4 Jenkins 服务器上安装 maven 和配置镜像加速
[root@jenkins ~]#apt -y install maven #镜像加速 [root@jenkins ~]#vim /etc/maven/settings.xml <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> <name>Nexus aliyun</name> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror> </mirrors>
让jenkins知道mvn命令在哪
#左侧系统管理,右侧全局工具配置,在maven安装下点击新增maven #这里如选择自动安装, jenkins会自动下载对应maven安装,安装在jenkins目录下(/var/lib/jenkins/),使用该maven #如果用手动装的maven,就不要点自动安装,输入maven路径如:/usr/share/maven (mvn -v可以查出)
让jenkins具有访问tomcat的权限
根据tomcat的用户权限配置,创建jenkins连接tomcat的用户和权限
#左侧系统管理,右侧凭据管理,在下面的Stores scoped to Jenkins下点击全局(随便点哪都一样) #右上角Add Credentials添加凭据,类型用户名和密码(上面tomcat配置创建的tomcat账号) #用户名 tomcat 密码 tomcat #ID和描述写 tomcat-user-password 相当于说明 #创建
2.7.2.7 创建 Maven 风格的任务
#创建任务,一个maven项目,输入一个war包项目地址,分支 */main #下面Build下,Goals and options下输入maven的编译选项 clean package -Dmaven.test.skip=true #上面的POM因为在项目的根目录下,所以不用改了 #注意编译出来的war包决定了以后访问的路径名,要做下更改 #下面Post Steps下,选执行shell mv target/hello-world-war-*.war target/hello.war #然后要调用插件部署到目标服务器的tomcat里 #在构建后操作下,选Deploy war/ear to a container #WAR/EAR files输入 target/hello.war Context path 放入应用目录。如不指定,则由war的文件名决定访问目录,可以指定为ROOT,则表示访问路径为网站的根 #选择容器地址 #点击add container,这里用的是9,所以选择 Tomcat 9.x Remote #选择前面配置的tomcat连接凭据 #输入tomcat地址,这里是 http://10.0.0.153:8080/ #多个就重复添加容器 http://10.0.0.154:8080/ #点击保存 #点击构建任务 #在tomcat管理页面 http://10.0.0.153:8080/manager 会看到多出hello项目 #可以访问该项目 http://10.0.0.153:8080/hello/ #测试更新项目代码提交,然后重新构建,查看网页发生变化,更新成功 http://10.0.0.153:8080/hello/
2.8.1 在Jenkins 安装 Golang 环境
#基于仓库安装 [root@ubuntu2004 ~]#apt update && apt -y install golang
#ginweb 项目,导入gitlab库里 https://gitee.com/lbtooth/ginweb.git #在一台机器上安装mysql,redis ]#apt install mysql-server redis #修改MySQL配置 [root@ubuntu2204 ~]#sed -i '/127.0.0.1/s/^/#/' /etc/mysql/mysql.conf.d/mysqld.cnf [root@ubuntu2204 ~]#systemctl restart mysql.service #配置MySQL环境 [root@ubuntu2204 ~]#mysql mysql> create database ginweb; mysql> create user ginweb@'10.0.0.%' identified by '123456'; mysql> grant all on ginweb.* to ginweb@'10.0.0.%'; #导入表结构 [root@ubuntu2204 ginweb]#mysql -uginweb -p123456 -h10.0.0.152 ginweb < ginweb.sql #确认下 [root@ubuntu2204 ginweb]#mysql -uginweb -p123456 -h10.0.0.152 ginweb -e 'show tables;' #准备redis [root@ubuntu2204 ~]#vim /etc/redis/redis.conf bind 0.0.0.0 requirepass 123456 [root@ubuntu2204 ~]#systemctl restart redis #验证 ]#redis-cli -a 123456 > info #拉取代码,查看配置,确保域名在目标服务器上可以被解析 ~]#git clone git@gitlab.wang.org:example1/ginweb.git ~]#cd ginweb/ ginweb]#vim conf/ginweb.ini [mysql] host = "mysql.wang.org" port = 3306 databases = "ginweb" user = "ginweb" passwd = "123456" [redis] host = "redis.wang.org" port = 6379 passwd = "123456" #确保目标服务器8888端口没有被应用,ginweb服务要用该端口
#jenkins机器上写执行脚本 [root@jenkins ~]#vim /data/jenkins/scripts/ginweb.sh #!/bin/bash APP=ginweb APP_PATH=/data DATE=`date +%F_%H-%M-%S` HOST_LIST=" 10.0.0.153 10.0.0.154 " build () { #go env 可以查看到下面变量信息,如下环境变量不支持相对路径,只支持绝对路径 #root用户运行脚本 #export GOCACHE="/root/.cache/go-build" #export GOPATH="/root/go" #Jenkins用户运行脚本 export GOCACHE="/var/lib/jenkins/.cache/go-build" export GOPATH="/var/lib/jenkins/go" #go env -w GOPROXY=https://goproxy.cn,direct #下载加速 export GOPROXY="https://goproxy.cn,direct" #CGO_ENABLED=0表示静态编译,可以运行在任何机器上,不需要任何依赖 CGO_ENABLED=0 go build -o ${APP} } deloy () { for host in $HOST_LIST;do ssh root@$host "mkdir -p $APP_PATH/${APP}-${DATE}" scp -r * root@$host:$APP_PATH/${APP}-${DATE}/ ssh root@$host "killall -0 ${APP} &> /dev/null && killall -9 ${APP}; rm -f ${APP_PATH}/${APP} && \ ln -s ${APP_PATH}/${APP}-${DATE} ${APP_PATH}/${APP}; \ cd ${APP_PATH}/${APP}/ && nohup ./${APP}&>/dev/null" & done } build deloy
#创建自由风格任务,git输入仓库地址 #Build Steps选择执行shell bash -x /data/jenkins/scripts/ginweb.sh #点击构建,在jenkins服务器可以看到编译后的二进制文件 [root@jenkins ~]#ldd /var/lib/jenkins/workspace/freestyle-ginweb/ginweb not a dynamic executable #静态文件,拷到任意服务器都能执行 #访问测试,默认用户名和密码:admin/123456 http://10.0.0.154:8888/
2.9.1 安装 Ansible 环境
在jenkins机器上部署ansible
[root@jenkins ~]#apt update && apt -y install ansible #Ubuntu22.04默认没有配置文件,可以手动创建一个空文件,使用默认值即可 [root@jenkins ~]#ansible --version ansible 2.10.8 config file = None #创建空文件即可 [root@jenkins ~]#mkdir -p /etc/ansible/ && touch /etc/ansible/ansible.cfg [root@jenkins ~]#ansible --version ansible 2.10.8 config file = /etc/ansible/ansible.cfg #准备主机清单文件(ansible_ssh_user以root身份去连对方,不然以当前身份jenkins去连对方,对方没该用户) [root@jenkins ~]#vim /etc/ansible/hosts [webservers] 10.0.0.153 ansible_ssh_user=root 10.0.0.154 ansible_ssh_user=root [appservers] 10.0.0.153 ansible_ssh_user=root 10.0.0.154 ansible_ssh_user=root #因为Jenkins服务是以jenkins用户身份运行,所以需要实现Jenkins用户到被控制端的免密码验证 [root@jenkins ~]#su - jenkins jenkins@jenkins:~$ ssh-keygen #如果ls .ssh 已经有了,就不用再创建了,直接下面copy过去 jenkins@jenkins:~$ ssh-copy-id root@10.0.0.153 #如果之前拷贝过就不用再做了 jenkins@jenkins:~$ ssh-copy-id root@10.0.0.154 #测试是否可以ping通 [root@jenkins ~]#ansible all -m ping [root@jenkins ~]#ansible all -m shell -a 'hostname'
在jenkins插件里安装Ansible插件
任务编辑中build steps会多
2.9.3 使用 Ansible Ad-Hoc 实现任务
Ad-Hoc实际生产中更适合调试用
#jenkins创建自由风格任务 #Build Steps下点Invoke Ansible Ad-Hoc Command #Host pattern主机清单模式,这里写主机清单中的 webservers #Inventory 主机清单文件名,点击 File or host list, 输入 /etc/ansible/hosts #Module 使用模块,这里输入 shell #Module arguments or command to execute 命令参数,这里输入 hostname #点击保存 点击构建任务测试
[root@jenkins ~]#mkdir /data/jenkins/playbook [root@jenkins ~]#vim /data/jenkins/playbook/test.yml - hosts: webservers remote_user: root tasks: - name: excute cmd shell: cmd: hostname -I register: result - name: show result debug: msg: "{{ result }}" #创建自由风格任务 #Build Steps选Invoke Ansible Playbook #Playbook path写 /data/jenkins/playbook/test.yml #Inventory 主机清单文件名,点击 File or host list, 输入 /etc/ansible/hosts #点击保存 点击构建任务测试
#准备两个不同环境的主机清单文件(通过不同的主机清单名来区分生产环境, 测试环境) [root@jenkins ~]#cat /etc/ansible/hosts_test [webservers] 10.0.0.102 [root@jenkins ~]#cat /etc/ansible/hosts_product [webservers] 10.0.0.103 #构建自由风格任务,参数化构建,添加选项参数 定义生产环境还是测试环境 inventory #选项 (把路径直接做成选项) /etc/ansible/hosts_test /etc/ansible/hosts_product #Build Steps选Invoke Ansible Playbook #Playbook path写 /data/jenkins/playbook/test.yml #Inventory 主机清单文件名,点击 File or host list, 输入 $inventory #点击保存
根据选项让playbook执行webservers还是appservers
#编写Playbook文件 [root@jenkins ~]#cat /data/jenkins/playbook/test.yml - hosts: "{{ servers }}" #指定ansible 变量,后面在Jenkins中对其赋值 remote_user: root tasks: - name: excute cmd shell: cmd: hostname register: result - name: show result debug: msg: "{{ result }}" #ansible执行方法,主要要切到jenkins用户,因为上面配的公钥是jenkins用户下的 #ansible-playbook -e servers=appservers /data/jenkins/playbook/test.yml #构建自由风格任务,参数化构建,添加选项参数 定义生产环境还是测试环境 inventory #选项 (把路径直接做成选项) /etc/ansible/hosts_test /etc/ansible/hosts_product #添加选项参数 group #选项 webservers appservers #Build Steps选Invoke Ansible Playbook #Playbook path写 /data/jenkins/playbook/test.yml #Inventory 主机清单文件名,点击 File or host list, 输入 $inventory #下面点击高级,Extra Variable下点Add Extra Variable #Key 输入ansible变量 servers #Value 输入 ${group} #点击保存
#创建3个自由风格任务 #两种方法: 1.前置任务定义后置任务是谁 2.后置任务定义前置任务是谁 第一种 #任务编辑,构建后操作,增加步骤点击构建其他工程,选择后置任务(可以多选),保存 #任务页面会显示下级项目,下级任务会显示上级项目 第二种 #任务编辑,构建触发器下,其他工程构建后触发,关注的项目输入前置项目名(可以多选) #任务页面会显示下级项目,下级任务会显示上级项目 job1定义后置任务job2, job2定义后置任务job3, 那么执行job1,完成会调job2,job2完成会调job3 注意调用不要构成环路
jenkins安装Blue Ocean插件, 用于显示pipline执行过程
安装完jenkins左侧会出现打开Blue Ocean, 里面的界面更好看
2.10 构建后通知
2.10.1 邮件通知
Mailer 和 Email Extension 插件都可以实现邮件通知功能
下面是Mailer实现邮件通知功能
#准备告警邮箱配置 #jenkins左侧系统管理下系统配置,系统管理员邮件地址 配置发件人邮箱 #往下拉到邮件通知 #配置SMTP邮箱 如 smtp.163.com(这个要自己去查) #用户默认邮箱后缀 如 @163.com #点高级,使用SMTP认证 用户名就是邮箱名 密码就是申请的授权码(非登录密码) #使用SSL协议,TLS SMTP端口为465(加密就是465) #可以点击 通过发送测试邮件测试配置 输入收通知的目标邮箱 做测试 #保存 #创建自由风格任务,在构建后操作选择 E-mail Notification #Recipients 输入 收件人的邮箱(如果有多个,空格隔开) #保存,构建任务,邮件成功失败会不一样 注意:失败会发,失败变成功会发,后续一直成功不会发邮件
官网说明
https://jenkinsci.github.io/dingtalk-plugin/
钉钉上的配置
#钉钉里建个群组(群聊) #右侧群设置里面添加机器人,自定义webhook接入 #自定义关键字 (发的信息中必须带该关键字) 这里选上 #加签 (发的时候必须带该密码才能发) 这里选上 #IP地址 (必须在该公网地址才能发) webhook的发送地址,还有加签的密码记下来
jenkins上的配置
Jenkins 安装 DingTalk 插件 #安装完插后,建议重启 #jenkins左侧系统管理下,右侧多一个钉钉配置 #通知时机选择 #下方增加机器人,输入id和名称(名称和钉钉创建的机器人名相同) #webhook填入 钉钉上的webhook #加密填入 钉钉上的 加签密码 #点击测试,看消息有没有发出去 #jenkins任务配置多了个钉钉机器人选项,选上面配的钉钉机器人 #高级里,可以选择通知谁 手机号支持多个,每个手机号一行,也可选 atall 即所有群里的人员(不必再输入手机号) #自定义内容需要使用Markdown格式,比如: - 构建ID: ${BUILD_ID} - 部署项目: ${JOB_NAME} - 部署目录: ${WORKSPACE}
#添加企业微信群,添加机器人,会生成webhook地址 Jenkins 安装 Qy Wechat Notification 插件 #jenkins创建任务,构建后操作,点企业微信通知 #输入webhook地址 #通知UserID,这里所有人都发,就写 ALL #通知手机号码, 这里写 ALL #更多消息定制消息格式 - 构建ID: ${BUILD_ID} - 部署项目: ${JOB_NAME} - 部署目录: ${WORKSPACE} #保存,构建
周期性构建
Webhook 触发构建
2.11.1 定时和 SCM 构建
1.定时构建: 按时间周期性的触发构建 2.轮询SCM(Source Code Management): 定期到代码仓库检查代码是否有变更,存在代码变更时就构建 #jenkins在定时任务指令上发明了H,表示任意值 # Every fifteen minutes (perhaps at :07, :22, :37, :52): H/15 * * * * #可能第1分钟,每过15分钟执行 #*/15表示0,15,30,45 # Every ten minutes in the first half of every hour (three times, perhaps at :04, :14, :24): H(0-29)/10 * * * * #0-29中间的某一个值,每10分钟执行 #每小时随机分钟执行一次 H * * * * #定时构建 #创建自由风格任务,构建触发器点定时构建 #日程表输入定时时间规则,下面会显示下次的执行时间示例 H * * * * #随便执行一个shell命令,保存 #SCM 构建 对比定时构建增加了一个轮询探测SCM机制 #创建自由风格任务,git输入仓库地址,构建触发器点 轮询SCM #日程表输入定时时间规则,下面会显示下次的执行时间示例 H * * * * #保存(构建时,到时间会去gitlab上查看代码变没变,没变就不构建) #点击构建,代码不变没执行构建,细节可以在左侧git轮询日志查看
#可以使用多种方式实现 Webhook 触发构建 (3种方法选一种即可) 1.触发远程构建: 此方式无需安装插件 2.Build when a change is pushed to GitLab. GitLab webhook URL: 需要安装Gitlab插件 3.Generic Webhook Trigger : 需要安装 Generic Webhook Trigger Plugin 插件
2.11.2.1 触发远程构建
#创建自由风格任务,输入git地址 #构建触发器下,点 触发远程构建 (例如,使用脚本) #身份验证令牌写入token (可以随便写,也可用命令生成) 666666 #这里随便写个token #根据下面的提示,触发webhook地址为 http://jenkins.wang.org:8080/job/freestyle-webhook-gitlab/build?token=666666 #点击右上角用户头像下设置,添加token,这个token是给应用程序使用的密码 #起个名字,这里写gitlab,点生成 出现token如下,点击保存 114eaf7199dd74fb07dd632d40aaf529da #验证是否可以触发(http后面加上用户名和上面给出的token) 有些版本可以加上用户名和密码,但不安全 ]#curl 'http://admin:114eaf7199dd74fb07dd632d40aaf529da@jenkins.wang.org:8080/job/freestyle-webhook-gitlab/build?token=666666' -I #curl不加用户名和token,命令端可能可以,gitlab端不行 ]#curl 'http://jenkins.wang.org:8080/job/freestyle-webhook-gitlab/build?token=666666' -I #在gitlab首页,点击左侧放大镜搜索,进入管理中心(必须管理员身份) #左侧设置下的网络,出站请求,把 允许来自 webhooks 和集成对本地网络的请求 勾上 #保存更改 #上面curl发送测试成功后,配置gitlab #在gitlab上进入对应项目,左侧设置里点webhooks,点击添加新的webhook #URL输入 http://admin:114eaf7199dd74fb07dd632d40aaf529da@jenkins.wang.org:8080/job/freestyle-webhook-gitlab/build?token=666666 #触发来源,这里选 推送事件,标签推送事件,合并请求事件 #不启用SSL验证,点击添加webhook(如报错,gitlab默认不允许向网络发送http请求,上面gitlab网络配置下) #点击测试,推送事件,jenkins成功开始构建任务 #gitlab上修改代码提交,成功触发jenkins构建任务
第二种方法
需要安装 GitLab 插件,默认无此选项功能
#创建自由风格任务,输入git地址 #构建触发器下,点 Build when a change is pushed to GitLab. GitLab webhook URL: http://.../freestyle-webhook-gitlab webhook地址就是上面显示的地址,记下来 #选择下面触发时机 #下面高级下,Secret token直接点生成会出现token,记下来 #保存 #gitlab上网络出站请求如果没有设置过需要设置下 #gitlab上项目下,左侧设置webhooks,添加新的webhook #输入URL,Secret令牌 #下面的触发事件无所谓(多点也没用),jenkins这边定义了触发事件 #添加
#范例: 编写脚本 [root@jenkins ~]#vim /data/jenkins/scripts/spring-boot-helloworld-docker.sh #!/bin/bash REGISTRY=harbor.wang.org PORT=8888 HOSTS=" 10.0.0.153 10.0.0.154" mvn clean package -Dmaven.test.skip=true #项目中已有dockerfile文件,直接构建,推送到仓库 docker build -t ${REGISTRY}/example/myapp:v$BUILD_ID . docker push ${REGISTRY}/example/myapp:v$BUILD_ID #目标服务器docker要允许远程连接 for i in $HOSTS;do docker -H $i rm -f myapp docker -H $i run -d -p ${PORT}:8888 --restart always --name myapp ${REGISTRY}/example/myapp:v$BUILD_ID #ssh root@$i docker rm -f myapp #ssh root@$i docker run -d -p ${PORT}:8888 --restart always --name myapp ${REGISTRY}/example/myapp:v$BUILD_ID done #在两台目标服务器上安装docker,并打开远程连接端口 [root@web01 ~]#apt install docker.io -y #配置 Docker 监听2375端口 #打开监听端口2375/tcp [root@web01 ~]#vim /lib/systemd/system/docker.service ..... #修改此行 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 ..... [root@web01 ~]#systemctl daemon-reload [root@web01 ~]#systemctl restart docker.service #查看2375端口是否打开 #jenkins上安装docer(作为客户端使用,去连接目标服务器的docker服务) [root@jenkins ~]#apt install docker.io -y #连接目标docker服务测试 [root@jenkins ~]#docker -H 10.0.0.153 info #查看对方镜像 [root@jenkins ~]#docker -H 10.0.0.153 images #安装harbor #新机器准备4g内存,安装包harbor-offline-installer-v2.10.0.tgz,install_harbor.sh #harbor不要和gitlab装一起,会有端口冲突 ~]#bash install_harbor.sh 请访问链接: http://10.0.0.155/ 用户和密码: admin/123456 #harbor创建用户,通过这个用户上传下载镜像 xiaoming/Abcd1234 #harbor创建项目example,公开;在该项目中,加入xiaoming用户,选择角色 #两台目标服务器测试:目标 推送alpine镜像到dockerhub #注:如果docker配了代理,要访问内网域名,该域名要加入docker代理NO_PROXY中如下 #Environment="NO_PROXY=127.0.0.0/8,10.0.0.0/16,harbor.wang.org" #先打个tag [root@web01 ~]#docker tag alpine harbor.wang.org/example/alpine:v1.0 #让docker信任harbor的http请求,修改下面行 [root@web01 ~]#vim /lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 --insecure-registry harbor.wang.org [root@web01 ~]#systemctl daemon-reload [root@web01 ~]#systemctl restart docker #下面命令可以查看http协议是否加入成功过(看Insecure Registries:) [root@web01 ~]#docker info #登录harbor,再上传dockerhub (xiaoming/Abcd1234) [root@web01 ~]#docker login harbor.wang.org #两台机器都登录下 [root@web01 ~]#docker push harbor.wang.org/example/alpine:v1.0 #另一台目标服务器测试拉取镜像,因为是公共的,不需要验证 [root@web02 ~]#docker pull harbor.wang.org/example/alpine:v1.0 #jenkins服务器测试:目标 推送alpine镜像到dockerhub #让docker信任harbor的http请求,修改下面行 [root@jenkins ~]#vim /lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry harbor.wang.org [root@jenkins ~]#systemctl daemon-reload [root@jenkins ~]#systemctl restart docker #把jenkins加到docker组里,这样jenkins用户才对/var/run/docker.sock有权限 [root@jenkins ~]#usermod -aG docker jenkins [root@jenkins ~]#id jenkins #查看 #切换到jenkins用户,因为docker登录用户名密码要记录在jenkins家目录下 [root@jenkins ~]#su - jenkins jenkins@jenkins:~$ docker login harbor.wang.org #拉取测试 jenkins@jenkins:~$ docker pull harbor.wang.org/example/alpine:v1.0 #注:jenkins用户加入组,但jenkins程序之前启动的,要重启才能获取新的jenkins用户成员关系(否则jenkins无法提交镜像) [root@jenkins ~]#systemctl restart jenkins #jenkins创建自由风格任务,git输入仓库地址,指定分支 #Build Steps选执行shell,输入 bash -x /data/jenkins/scripts/spring-boot-helloworld-docker.sh #点击构建任务, harbor上多出example/myapp镜像,目标服务器能看到跑起来的容器 #gitlab上修改代码提交,jenkins再次构建,harbor上example/myapp多一个版本,目标服务器新容器运行