[TOC]
0x00 前言简述 看过我前面Jenkins学习之路的朋友肯定知道,在Kubenetes中使用Jenkins可以进行动态生成分布式jnlp-slave的agent节点,相比于传统的agent节点来说极大的节约资源。
但是某一天开发反馈某个项目CICD无法正常进行,作为运维人员(搬砖)立马进入K8S集群,排除安装在集群中的Jenkins的异常问题,排查可知由于K8S集群证书到期导致动态jenkins agent节点无法正常被创建,此时项目又比较紧急。
遂利用装有Docker的机器,立即使用自行构建的jenkins-jnlp-agent镜像,并在 jenkins 中创建一个固定节点,通过docker运行该镜像并连接到Jenkins,在流水线项目绑定到该节点执行,通过几分钟的时间就快速解决了jenkins agent问题,在项目完成持续集成和交互后,趁着间隙更新Jenkins上配置连接kubernetes apiserver的证书,恢复了动态生成agent节点。
所以,为了便于自己总结知识,以及有相同需求的看友,遂将jenkins外部agent节点接入以及自行构建jnlp-agent镜像流程进行实践,希望能帮助到大家。
如果此篇文章对你有用,请您也转发、点赞、在看、给周边的朋友吧!
温馨提示: 若需要企业 Jenkins Pipeline 流水线脚本的朋友,可以关注【WeiyiGeek】后回复【Jenkins流水线代码】即可下载 Jenkins-Pipeline.groovy
示例文件。
weiyigeek.top-Jenkins流水线代码图
0x01 基础环境准备 1.环境说明
[TOC]
0x00 前言简述 看过我前面Jenkins学习之路的朋友肯定知道,在Kubenetes中使用Jenkins可以进行动态生成分布式jnlp-slave的agent节点,相比于传统的agent节点来说极大的节约资源。
但是某一天开发反馈某个项目CICD无法正常进行,作为运维人员(搬砖)立马进入K8S集群,排除安装在集群中的Jenkins的异常问题,排查可知由于K8S集群证书到期导致动态jenkins agent节点无法正常被创建,此时项目又比较紧急。
遂利用装有Docker的机器,立即使用自行构建的jenkins-jnlp-agent镜像,并在 jenkins 中创建一个固定节点,通过docker运行该镜像并连接到Jenkins,在流水线项目绑定到该节点执行,通过几分钟的时间就快速解决了jenkins agent问题,在项目完成持续集成和交互后,趁着间隙更新Jenkins上配置连接kubernetes apiserver的证书,恢复了动态生成agent节点。
所以,为了便于自己总结知识,以及有相同需求的看友,遂将jenkins外部agent节点接入以及自行构建jnlp-agent镜像流程进行实践,希望能帮助到大家。
如果此篇文章对你有用,请您也转发、点赞、在看、给周边的朋友吧!
温馨提示: 若需要企业 Jenkins Pipeline 流水线脚本的朋友,可以关注【WeiyiGeek】后回复【Jenkins流水线代码】即可下载 Jenkins-Pipeline.groovy
示例文件。
weiyigeek.top-Jenkins流水线代码图
0x01 基础环境准备 1.环境说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ~$ kubectl get pod,svc -n devops -l app=jenkins NAME READY STATUS RESTARTS AGE pod/jenkins-7fc6f4fcf6-glqxj 1/1 Running 0 28h NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/jenkins NodePort 10.109.163.223 <none> 8080:30001/TCP,50000:30634/TCP 382d Jenkins 2.330 Jenkins 面板: http://192.168.12.107:30001/ TCP port for inbound agents(Agent 端口): http://192.168.12.107:30634/ ( 内部为 50000,若是在集群中使用则需要将nodePort端口改成,可通过转发的形式 因为K8S默认nodePort范围在 30000-32767 之中)
温馨提示: 我们需要修改 Jenkins Agent 端口 可以访问 Dashboard 全局安全配置 -> 代理 (TCP port for inbound agents) 指定端口设置为 30634,注意相对应Pod暴露的端口也要一同修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ kubectl edit deployments.apps -n devops jenkins ports: - containerPort: 8080 name: web protocol: TCP - containerPort: 30634 name: agent protocol: TCP $ kubectl edit svc -n devops jenkins - name: agent nodePort: 30634 port: 30634 protocol: TCP:q targetPort: agent $ kubectl get svc,pod -n devops -l app=jenkins NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/jenkins NodePort 10.109.163.223 <none> 8080:30001/TCP,30634:30634/TCP 382d NAME READY STATUS RESTARTS AGE pod/jenkins-856bc9b47f-4t7k5 1/1 Running 0 2m9s
weiyigeek.top-Jenkins-inbound agents端口修改图
或者采用如下临时解决办法(下面实践1中采用的是此种方法,正式环境下还是建议使用上面的方法稳定,但是需要更改和注意的事项更多了)
1 2 3 4 5 6 7 $ kubectl -n devops port-forward --address 127.0.0.1,192.168.12.107 jenkins-7fc6f4fcf6-glqxj 50000:50000
温馨提示: 若看友不了解Jenkins持续集成的,或者需要安装实践的,可以参考博主学习【Jenkins学习之路汇总】汇总,关注 WeiyiGeek
公众号回复【jenkins学习之路
】即可获得学习资料:
2.添加新的Jenkins agent节点 操作步骤如下: Dashboard 系统管理 -> 节点管理 -> 新建节点 -> 按照提示输入如下信息 -> 最后点击保存
1 2 3 4 5 6 7 8 9 10 11 12 13 节点名字: docker-jenkins-jnlp Number of executors (最大执行数): 1~5 远程工作目录: /home/jenkins/agent 标签: docker-jnlp-1 启动方式: 通过 Java Web 启动代理 可用性: 尽量保持代理在线 - 工具位置: 请按照实际情况填写。 - 环境变量:
weiyigeek.top-新建Docker-agent节点图
温馨提示: 在点击保存后,我们可以点击此节点,看到其提示节点连接Jenkins的方式如下:1 2 3 4 5 6 7 8 9 java -jar agent.jar -jnlpUrl http://192.168.12.107:30001/computer/docker%2Djenkins%2Djnlp/jenkins-agent.jnlp -secret b97b9d1e0cf083f9da5721caa6ebc63f6fe648375bd90cb2c2f484681d887bb7 -workDir "/home/jenkins/agent" java -Xms512m -Xmx1g -Xss1m -jar /usr/local /bin/agent.jar -jnlpUrl http://192.168.12.107:30001/computer/jenkinsAgentWork1/jenkins-agent.jnlp -secret 2a789bbbd0193ef576e7b62eb2d205d1d024d0ea7b14f6f79f1cccdd6fb1ed20 -workDir "/home/jenkins/agent" echo b97b9d1e0cf083f9da5721caa6ebc63f6fe648375bd90cb2c2f484681d887bb7 > secret-filejava -jar agent.jar -jnlpUrl http://192.168.12.107:30001/computer/docker%2Djenkins%2Djnlp/jenkins-agent.jnlp -secret @secret-file -workDir "/home/jenkins/agent"
weiyigeek.top-节点连接Jenkins的方式图
3.自行构建Jenkins Agent镜像(干货) 描述: 在WeiyiGeek
微信公众号回复20230206
关键字,即可获取最新Jenkins-jnlp镜像构建的Dockerfile及下述相关脚本文件,此处我们自定义的jnlp容器镜像主要实现功能如下:
用户权限控制(sudo)
ssh 远程连接
git 代码版本控制
docker 容器管理
kubectl 集群管理
Java 运行环境
Maven 运行环境
NodeJS 环境
SonarQube 扫描环境
Gitlab-Release 上传环境
中文环境支持
时区更改配置
自定义工作目录(/home/jenkins/agent)
温馨提示: 如下操作构建依赖于Docker环境,若你没有安装Docker环境或者不了解的Docker容器的朋友,可以参考博主学习【Docker的系列笔记】汇总,关注 WeiyiGeek
公众号回复【Docker容器学习之路汇总
】即可获得学习资料:
构建目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ~/k8s/jenkins/jnlp-slave$ tree . . ├── agent.jar ├── agent.jar.bak ├── apache-maven-3.8.4-bin.tar.gz ├── build │ └── Dockerfile ├── docker ├── glibc-2.32-r0.apk ├── glibc-bin-2.32-r0.apk ├── glibc-i18n-2.32-r0.apk ├── jdk-8u281-linux-x64.tar.gz ├── jenkins-agent.sh ├── kubectl ├── locale.md ├── release-cli-0.10.0-linux-amd64 ├── remoting-4.11.2.jar ├── sgerrand.rsa.pub └── sonar-scanner-cli-4.5.0.2216-linux.zip 1 directory, 16 files
温馨提示: 在Jenkins 2.330版本中添加一个新的节点, 即可获取匹配当前版本的 agent.jar (http://youjenkins-domainname-or-ip/jnlpJars/agent.jar) , 或者是在 jenkins 官网 https://repo.jenkins-ci.org/public/org/jenkins-ci/main/remoting 进行下载;
自定义jnlp镜像的 Dockerfile 博主自定义jnlp镜像hub地址: https://hub.docker.com/r/weiyigeek/alpine-jenkins-jnlp 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 $ cat build/Dockerfile FROM alpine:3.13 .1 MAINTAINER Jenkins Custom Work Node Jnlp Container - <master@weiyigeek.top> - WeiyiGeekARG USERNAME=jenkins \ AGENT_WORKDIR=/home/jenkins \ BASE_DIR=/usr/local \ BASE_BIN=/usr/local/bin \ BASE_URL=http://192.168 .12.107 :8080 \ LOCALE=locale.md \ JDK_NAME=jdk-8 u281-linux-x64 \ JDK_DIR=/usr/local/jdk1.8.0 _281 \ GLIBC_NAME=glibc-2.32 -r0.apk \ GLIBC_BIN_NAME=glibc-bin-2.32 -r0.apk \ GLIBC_I18N_NAME=glibc-i18n-2.32 -r0.apk \ MAVEN_NAME=apache-maven-3.8 .4 -bin \ MAVEN_DIR=/usr/local/apache-maven-3.8 .4 \ SONAR_SCANNER_NAME=sonar-scanner-cli-4.5 .0.2216 -linux \ SONAR_SCANNER_DIR=/usr/local/sonar-scanner-4.5 .0.2216 -linux \ GITLAB_CLI=release-cli-0.10 .0 -linux-amd64 ENV LANG=en_US.UTF-8 \ LC_ALL=en_US.UTF-8 \ JAVA_HOME=/usr/local/jdk8 \ JRE_HOME=/usr/local/jdk8/jre \ MAVEN_HOME=/usr/local/maven \ MAVEN_RPEO=/home/jenkins/.m2 \ SONAR_SCANNER_HOME=/usr/local/sonar-scanner \ NODEJS_MODULES=/usr/lib/node_modules USER rootRUN sed -i 's/dl-cdn.alpinelinux.org/mirror.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \ && apk update \ && apk add --no-cache openssh tzdata curl tar sudo git ca-certificates wget unzip docker zlib nodejs npm jq \ && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && chmod 4755 /bin/busybox \ && addgroup -g 1000 -S ${USERNAME} \ && adduser ${USERNAME} -D -g ${USERNAME} -G root -u 1000 -s /bin/sh \ && echo "jenkins ALL=(root) NOPASSWD:ALL" >> /etc/sudoers \ && mkdir -p ${AGENT_WORKDIR} /.ssh ${AGENT_WORKDIR} /.m2 ${AGENT_WORKDIR} /agent\ && wget -q -O /tmp/${GLIBC_NAME} ${BASE_URL} /${GLIBC_NAME} \ && wget -q -O /tmp/${GLIBC_BIN_NAME} ${BASE_URL} /${GLIBC_BIN_NAME} \ && wget -q -O /tmp/${GLIBC_I18N_NAME} ${BASE_URL} /${GLIBC_I18N_NAME} \ && wget -q -O /etc/apk/keys/sgerrand.rsa.pub ${BASE_URL} /sgerrand.rsa.pub \ && wget -q -O /tmp/${LOCALE} ${BASE_URL} /${LOCALE} \ && wget -q -O /tmp/${JDK_NAME} .tar.gz ${BASE_URL} /${JDK_NAME} .tar.gz \ && wget -q -O ${BASE_BIN} /agent.jar ${BASE_URL} /agent.jar \ && curl -fsSL -o ${BASE_BIN} /jenkins-agent.sh ${BASE_URL} /jenkins-agent.sh \ && curl -fsSL -o /tmp/${MAVEN_NAME} .tar.gz ${BASE_URL} /${MAVEN_NAME} .tar.gz \ && curl -fsSL -o /tmp/${SONAR_SCANNER_NAME} .zip ${BASE_URL} /${SONAR_SCANNER_NAME} .zip \ && curl -fsSL -o /usr/local /bin/release-cli ${BASE_URL} /${GITLAB_CLI} \ && curl -fsSL -o /usr/local /bin/kubectl ${BASE_URL} /kubectl \ && curl -fsSL -o /usr/local /bin/docker ${BASE_URL} /docker \ && sed -i "s/#PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config \ && sed -i "s/^#\s*StrictHostKeyChecking ask/StrictHostKeyChecking no/g" /etc/ssh/ssh_config \ && ssh-keygen -t dsa -P "" -f /etc/ssh/ssh_host_dsa_key \ && ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key \ && ssh-keygen -t ecdsa -P "" -f /etc/ssh/ssh_host_ecdsa_key \ && ssh-keygen -t ed25519 -P "" -f /etc/ssh/ssh_host_ed25519_key \ && ssh-keygen -t ed25519 -P "" -C "master@weiyigeek.top" -f /home/jenkins/.ssh/id_ed25519 \ && apk add /tmp/${GLIBC_NAME} /tmp/${GLIBC_BIN_NAME} /tmp/${GLIBC_I18N_NAME} \ && tar -zxf /tmp/${JDK_NAME} .tar.gz -C ${BASE_DIR} \ && mv ${JDK_DIR} ${JAVA_HOME} \ && tar -zxf /tmp/${MAVEN_NAME} .tar.gz -C ${BASE_DIR} \ && mv ${MAVEN_DIR} ${MAVEN_HOME} \ && unzip /tmp/${SONAR_SCANNER_NAME} .zip -d ${BASE_DIR} \ && mv ${SONAR_SCANNER_DIR} ${SONAR_SCANNER_HOME} \ && npm config set registry https://registry.npm.taobao.org \ && chmod a+x ${BASE_BIN} /* \ && chown -R jenkins:jenkins ${BASE_DIR} / ${AGENT_WORKDIR} / ${NODEJS_MODULES} / \ && echo "root:WeiyiGeek" | chpasswd \ && echo "jenkins:WeiyiGeek" | chpasswd \ && cat /tmp/${LOCALE} | xargs -i /usr/glibc-compat/bin/localedef -i {} -f UTF-8 {}.UTF-8 \ && sed -i "s#use_embedded_jre=true#use_embedded_jre=false#g" ${SONAR_SCANNER_HOME} /bin/sonar-scanner \ && rm -rf /var/cache/apk/* /tmp/* ${SONAR_SCANNER_HOME} /jre/* \ && cd ${JAVA_HOME} \ && rm -rf COPYRIGHT LICENSE README release THIRDPARTYLICENSEREADME-JAVAFX.txt THIRDPARTYLICENSEREADME.txt Welcome.html javafx-src.zip src.zip \ lib/plugin.jar \ lib/ext/jfxrt.jar \ bin/javaws \ lib/javaws.jar \ lib/desktop \ plugin \ lib/deploy* \ lib/*javafx* \ lib/*jfx* \ lib/amd64/libdecora_sse.so \ lib/amd64/libprism_*.so \ lib/amd64/libfxplugins.so \ lib/amd64/libglass.so \ lib/amd64/libgstreamer-lite.so \ lib/amd64/libjavafx*.so \ lib/amd64/libjfx*.so \ && echo "export LANG=zh_CN.UTF-8" > /etc/profile.d/locale.sh USER jenkinsWORKDIR ${AGENT_WORKDIR} ENV CLASSPATH=.:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar \ PATH=${JAVA_HOME}/bin:${MAVEN_HOME}/bin:${SONAR_SCANNER_HOME}/bin:$PATH ENTRYPOINT ["/usr/local/bin/jenkins-agent.sh" ]
镜像构建操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 ~/k8s/jenkins/jnlp-slave$ python3 -m http.server 8080 Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ... ... docker build -t weiyigeek/alpine-jenkins-jnlp --platform linux/amd64 . docker images weiyigeek/alpine-jenkins-jnlp --all docker push weiyigeek/alpine-jenkins-jnlp ansible node -m shell -a "docker pull weiyigeek/alpine-jenkins-jnlp"
至此,Jenkins Agent 镜像构建完毕!
0x02 项目实践 1.使用在K8S部署的Jenkins连接Docker容器中运行的Agent分布式节点 (缺省端口:50000) 描述: 从前面环境可知,我将Jenkins安装在Kubernetes集群之中了,并且将Pod中的8080端口映射到30001端口,而agent缺省端口为50000,在没有更改的SVC情况下,我们可以使用两种方式一种就是使用kubectl port-forward
转发,另外一种是在Jenkins资源清单中配置 hostNetwork: true
, 此时运行jenkins Pod的节点IP+50000端口便可直接访问。
步骤 01.针对 Jenkins 进行 inbound agents pod 50000 端口转发到192.168.12.107节点的50000端口1 $ kubectl -n devops port-forward --address 127.0.0.1,192.168.12.107 jenkins-7fc6f4fcf6-glqxj 50000:50000
步骤 02.然后在其他有安装Docker的机器节点上运行如下命令进行jenkins jnlp容器的创建,注意此处为了多个agent构建时maven包的数据共享,使用nfs共享磁盘.1 2 3 4 5 6 7 8 9 10 docker run --user jenkins -d --name jnlp \ -e "JAVA_OPTS=-Xms512m -Xmx1g -Xss1m" \ -e "JENKINS_NAME=docker-jenkins-jnlp" \ -e "JENKINS_AGENT_NAME=docker-jenkins-jnlp" \ -e "JENKINS_SECRET=b97b9d1e0cf083f9da5721caa6ebc63f6fe648375bd90cb2c2f484681d887bb7" \ -e "JENKINS_AGENT_WORKDIR=/home/jenkins" \ -e "JENKINS_PURL=http://192.168.12.107:30001" \ -w /home/jenkins \ -v /nfsdisk-31/appstorage/mavenRepo:/home/jenkins/.m2 \ -v /var/run/docker.sock:/var/run/docker.sock weiyigeek/alpine-jenkins-jnlp:latest
命令执行若出现INFO: Connected
结果,则表示连接成功。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Java version: 1.8.0_281, vendor: Oracle Corporation, runtime: /usr/local /jdk8/jre Default locale: en_US, platform encoding: UTF-8 OS name: "linux" , version: "5.4.0-137-generic" , arch: "amd64" , family: "unix" INFO: Scanner configuration file: /usr/local /sonar-scanner/conf/sonar-scanner.properties INFO: Project root configuration file: NONE INFO: SonarScanner 4.5.0.2216 INFO: Java 1.8.0_281 Oracle Corporation (64-bit) INFO: Linux 5.4.0-137-generic amd64 Feb 04, 2023 10:51:19 PM hudson.remoting.jnlp.Main createEngine INFO: Setting up agent: docker-jenkins-jnlp Feb 04, 2023 10:51:19 PM hudson.remoting.jnlp.Main$CuiListener <init> INFO: Jenkins agent is running in headless mode. Feb 04, 2023 10:51:19 PM hudson.remoting.Engine startEngine INFO: Using Remoting version: 4.11.2 Feb 04, 2023 10:51:19 PM org.jenkinsci.remoting.engine.WorkDirManager initializeWorkDir INFO: Using /home/jenkins/remoting as a remoting work directory Feb 04, 2023 10:51:19 PM org.jenkinsci.remoting.engine.WorkDirManager setupLogging INFO: Both error and output logs will be printed to /home/jenkins/remoting Feb 04, 2023 10:51:19 PM hudson.remoting.jnlp.Main$CuiListener status INFO: Locating server among [] Feb 04, 2023 10:51:19 PM hudson.remoting.jnlp.Main$CuiListener status INFO: Agent discovery successful Agent address: 192.168.12.107 Agent port: 50000 Identity: 8e:c7:1e:e1:39:ee:f4:2a:43:f6:aa:d9:0e:b7:b6:62 ..... INFO: Connected
weiyigeek.top-在Docker中运行jenkins-jnlp结果图
步骤 03.当然你也可以通过点击 Jenkins Dashboard -> 节点列表 -> docker-jenkins-jnlp 查看创建的节点已经是运行状态了。
weiyigeek.top-jenkins中jnlp节点agent状态图
温馨提示:此处只是涉及jenkins agent节点的配置连接,若需要进行调用执行某一个项目的CICD,请继续往下看。
2.使用在K8S部署的Jenkins连接Docker容器中运行的自定义Agent端口节点 (直连方式) 描述: 由于我们更改Jenkins中的agent TCP 端口以及在K8S集群中也作出了相应更改,但是连接时需要指定更多的参数,例如(JENKINS_DIRECT_CONNECTION与JENKINS_INSTANCE_IDENTITY),这里面的坑还是很大的,为啥说坑大请看友继续看。
JENKINS_DIRECT_CONNECTION : Connect directly to this TCP agent port, skipping the HTTP(S) connection parameter download. Value: “:“ JENKINS_INSTANCE_IDENTITY : The base64 encoded InstanceIdentity byte array of the Jenkins master. When this is set,the agent skips connecting to an HTTP(S) port for connection info.
步骤 00.前置准备,通过前面所需参数可知,我们需要指定要直连的jenkins agent服务的IP以及端口 (例如: 192.168.12.107:30634),和 jenkins Instance Identity值(此处值得注意)。
最开始,JENKINS_INSTANCE_IDENTITY 其值我认为是 Jenkins 家目录中 secrets 下的 master.key 的 base64 编码,但是怎么连接都是不正确的,随后没得办法只能查询官方文档,功夫不负有心人,在 jenkinsci 的 remoting 项目下找到了一个issue,然后顺腾摸瓜找到了该值。
Issue: https://github.com/jenkinsci/remoting/pull/338/files/07d7fd668b17123afd9ef7ac7a859bdda151f5cf#diff-8f973eec7a7bc04d532ba6b42015c903d7100b09f8ed655367d0fe893a9b6d0a Document: https://wiki.jenkins.io/display/JENKINS/Instance+Identity
weiyigeek.top-JENKINS-53461 Direct inbound TCP agent connection 图
1 2 3 4 5 6 7 Jenkins : Instance Identity Created by Unknown User (kohsuke), last modified by Unknown User (songy) on Mar 26, 2015 Each Jenkins instance maintains an RSA private/public key pair that can be used to uniquely identify Jenkins. This information is called "instance identity" . From outside, the public key can be obtained by sending the GET request to the top page of Jenkins, and look for the "X-Instance-Identity" header in the response. This header is always available, even if the response is 401 access denied (which can happen if Jenkins is protected via security.) The value represents a base64-encoded ASN.1 DER serialization of X.509 SubjectPublicKeyInfo record. Plugins that run inside Jenkins can access this key pair programmatically through the org.jenkinsci.main.modules.instance_identity.InstanceIdentity class (add a provided scope dependency to this module into your plugin)
上述大致意思是,每个Jenkins实例都维护一个RSA私钥/公钥对,可用于唯一标识Jenkins,这就是实例标识(instance identity),该值(公钥)可以通过将GET请求发送到Jenkins的首页来获得,并在响应中查找“X-Instance-Identity”标头。
1 X-Instance-Identity: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB******************1KQ5CLlISSjBaYrGqwsDThdDRbM6CjmP3UJ0NVhsMRJuQyAA2x4XktjEAYO3X0PWQIDAQAB
weiyigeek.top-获取X-Instance-Identity图
步骤 01.获取到了X-Instance-Identity值后,一条Docker命令创建运行 jenkins agent 容器连接到Jenkins之中1 2 3 4 5 6 7 8 9 10 11 docker run --user jenkins -d --name jnlp \ -e "JAVA_OPTS=-Xms512m -Xmx1g -Xss1m" \ -e "JENKINS_NAME=docker-jenkins-jnlp" \ -e "JENKINS_AGENT_NAME=docker-jenkins-jnlp" \ -e "JENKINS_SECRET=b97b9d1e0cf083f9da5721caa6ebc63f6fe648375bd90cb2c2f484681d887bb7" \ -e "JENKINS_AGENT_WORKDIR=/home/jenkins" \ -e "JENKINS_DIRECT_CONNECTION=192.168.12.107:30634" \ -e "JENKINS_INSTANCE_IDENTITY=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsFqtbTp5/xRS85YdURKk6Zc+qfl+RxrtnJ0zUXXLqXIa8S0MVk5U+xhu0Xo6Kz9MN/i7znfKpljk4/6+GphGFJbgGVw/1M2xbZjg7XN8QiXU64rlHC1NaGbKsa6R0PbWZEjbExR+sgTreiKwh08FcQemEDEajN5WihvvC0LmopYoSfHXW0fYMYIvVPO0Kow80MKoXighfhpK9msLWV4ay4ttP9zjBWml2gEeCXNjPQAt+r1l/kDT3c7vaIybzrxgRg2K9IVYmao/wemwDdpEP1KQ5CLlISSjBaYrGqwsDThdDRbM6CjmP3UJ0NVhsMRJuQyAA2x4XktjEAYO3X0PWQIDAQAB" \ -w /home/jenkins \ -v /nfsdisk-31/appstorage/mavenRepo:/home/jenkins/.m2 \ -v /var/run/docker.sock:/var/run/docker.sock weiyigeek/alpine-jenkins-jnlp:latest
步骤 02.查看运行的容器及其结果,我们也可以在jenkins 面板上看到连接的节点,如需删除节点直接选择左边,菜单栏中删除节点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ~/k8s/jenkins/jnlp-slave$ docker ps ~/k8s/jenkins/jnlp-slave$ docker logs -f efb27bd9cb8e
步骤 03.验证连接上Jenkins的agent节点,可以通过左侧的脚本命令行
进行测, 你可以访问 http://你jenkinsIP地址/computer/agent节点名称/script 即可到 脚本命令行页面。
1 2 3 4 5 6 7 println "uname -a" .execute().text println System.getenv("PATH" ) Linux 2736a6240d91 5.4.0-137-generic /usr/local /jdk8/bin:/usr/local /maven/bin:/usr/local /sonar-scanner/bin:/usr/local /sbin:/usr/local /bin:/usr/sbin:/usr/bin:/sbin:/bin
0x03 实践调用Jenkins agent节点 1.牛刀小试 描述: 此处不再累述 Jenkins 项目的创建说明,不会的朋友请参照我的【Jenkins学习之路汇总】( https://blog.weiyigeek.top/2018/1-1-1.html#Jenkins学习之路汇总 ),帮助大家快速入门。
agent 代理语法及使用介绍 我们可以通过下面流水线中可知,其中最主要的就是 agent 代码块包含的,我们设定的 jenkins agent 标签值的机器。 描述: 指定整个Pipeline或特定阶段将在Jenkins环境中执行的位置,具体取决于该agent
部分的放置位置;
语法参数: 1 2 3 4 5 6 7 8 9 10 必须: YES 参数:any / none / label / node / docker / dockerfile / kubernetes - 1.在任何可用的 agent 上执行Pipeline或stage - 2.在pipeline块的顶层应用时,不会为整个 Pipeline运行分配全局代理,并且每个stage部分都需要包含自己的agent部分。 - 3.使用提供的标签在Jenkins环境中可用的代理上执行 Pipeline或阶段, 注意标签条件也可以使用。 - 4.node使用与lable类似 - 5.执行Pipeline或stage时会动态供应一个docker节点去接受Docker-based的Pipelines。 - 6.使用从Dockerfile源存储库中包含的容器构建的容器执行 Pipeline或阶段,Jenkinsfile 必须从多分支 Pipeline或 SCM Pipeline加载。 - 7.在Kubernetes集群上部署的Pod内执行 Pipeline或阶段,同样Jenkinsfile 必须从多分支 Pipeline或 SCM Pipeline加载,Pod模板在kubernetes {} 块内定义。 允许:在顶层pipeline块和每个stage块中。
语法示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 pipeline { agent any agent none agent { label 'my-label1 && my-label2' } agent { node { label 'labelName' } } agent { docker { image 'maven:3-alpine' label 'my-defined-label' args '-v /tmp:/tmp' registryUrl 'https://myregistry.com/' registryCredentialsId 'myPredefinedCredentialsInJenkins' } } agent { dockerfile { filename 'Dockerfile.build' dir 'build' label 'my-defined-label' additionalBuildArgs '--build-arg version=1.0.2' args '-v /tmp:/tmp' registryUrl 'https://myregistry.com/' registryCredentialsId 'myPredefinedCredentialsInJenkins' } } agent { kubernetes { label podlabel yaml """ kind: Pod metadata: name: jenkins-agent spec: containers: - name: kaniko image: gcr.io/kaniko-project/executor:debug imagePullPolicy: Always command: - /busybox/cat tty: true volumeMounts: - name: aws-secret mountPath: /root/.aws/ - name: docker-registry-config mountPath: /kaniko/.docker restartPolicy: Never volumes: - name: aws-secret secret: secretName: aws-secret - name: docker-registry-config configMap: name: docker-registry-config """ } }
常用选项: 描述: 下面可以应用于两个或者多个agent实现的选项即label、customWorkspace、reuseNode;
1.label (参数:字符串): 运行 Pipeline或单个 Pipeline的标签或标签条件stage。 【此选项对node,docker和有效对dockerfile必需 node。】
2.customWorkspace (参数: 字符串) : 运行 Pipeline或个人 stage 这 agent 是这个自定义的工作空间内的应用,而不是默认的, 它可以是相对路径(在这种情况下自定义工作空间将位于节点上的工作空间根目录下
),也可以是绝对路径。【此选项是有效的node,docker和dockerfile。】
3.reuseNode(参数: 布尔值-false): 如果为true在同一工作空间中在 Pipeline顶级指定的节点上运行容器,而不是在整个新节点上运行
4.args (参数: 字符串): 要传递给的运行时参数docker run,此选项对docker和有效dockerfile。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 pipeline { agent { docker 'maven:3-alpine' } stages { stage('Example Build' ) { steps { sh 'mvn -B clean verify' } } } } pipeline { agent none stages { stage('Example Build' ) { agent { docker 'maven:3-alpine' } steps { echo 'Hello, Maven' sh 'mvn --version' } } stage('Example Test' ) { agent { docker 'openjdk:8-jre' } steps { echo 'Hello, JDK' sh 'java -version' } } } }
好了,agent 介绍完毕,我们该回归正题了。
实践流程
步骤 01.此处我创建了一个 Test 项目用于测试调用我们在Docker中运行的jenkins Agent节点。
weiyigeek.top-图
步骤 02.此处是我准备的 jenkins 流水线代码, 在应用保存后即可。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 def JOB_WORKSPACE = "${env.WORKSPACE}" def JOB_NAME = "${env.JOB_NAME}-${env.BUILD_NUMBER}" pipeline { agent { label 'docker-jnlp-1' } environment { SONARQUBE_TIMEOUT = '10' } stages { stage ('Start Test' ) { steps { echo "[Test Jenkins JNLP Agent with docker]!" echo "流水线环境变量输出: ${env.JOB_NAME}-${env.JOB_WORKSPACE}-${env.SONARQUBE_TIMEOUT}" script { sh " echo -e '<name>weiyigeek</name>\n<addr>https://weiyigeek.top</addr>' > demo.xml && cat demo.xml" USERNAME=sh label: 'name' ,returnStdout: true , script: """ awk '/<\\/*name\\/*>/{gsub(/[[:space:]]*<\\/*name\\/*>/,"");print \$0}' demo.xml | head -n 1 """ ADDRESS=sh label: 'name' ,returnStdout: true , script: """ awk '/<\\/*addr\\/*>/{gsub(/[[:space:]]*<\\/*addr\\/*>/,"");print \$0}' demo.xml | head -n 1 """ sh "mkdir -vp test/demo && ls && pwd" } echo "脚本执行返回结果输出 => ${USERNAME} => ${ADDRESS}" } } stage ('END Test' ) { steps { echo "跨阶段变量传递 => ${USERNAME}" sh "ls && pwd" sh "java -version;mvn -version;release-cli -v;sonar-scanner --version" echo "[Test End Stage]!" } } } }
步骤 03.返回到Test项目首页之中,点击立即构建,然后可以在阶段视图中查看到执行结果,我们可以通过Blue Ocean进行更加直观的展示。
weiyigeek.top-Jenkins agent连接运行测试图
2.完整的pipeline流水线企业项目 描述: 上一章节只是简单使用该镜像创建的容器,是否能被Jenkins正常调度,此章节为作者内部实践项目抽取的pipeline流水线,实现了’代码拉取’, ‘代码检测’, ‘项目构建’,’镜像构建’,’部署测试’,’成品归档’等阶段,供大家参考使用。
步骤 01.在登录Jenkins后,创建一个测试任务weiyigeek-oa,此处根据一个已经存在的任务内部OA系统进行复制创建,修改对应的流水线agent代码块为标签选择。
weiyigeek.top-创建weiyigeek-oa任务流水线图
温馨提示:由于 Jenkins Pipeline 流水线代码太长,需要的朋友可以关注【WeiyiGeek】公众号后回复【Jenkins流水线代码】即可下载 Jenkins-Pipeline.groovy
示例文件。
weiyigeek.top-Jenkins流水线代码图
步骤 03.回到项目首页,点击 【build with Parameters】选择构建项目指定参数,点击【开始构建】便可进行构建任务。
1 2 3 4 5 Started by user Jenkins 管理员 [Pipeline] Start of Pipeline [Pipeline] node Running on docker-jenkins-jnlp in /home/jenkins/agent/workspace/weiyigeek-oa
weiyigeek.top-流水线任务构建参数设定与运行图
步骤 04.任务运行完毕后可以通过 Blue Ocean 进行查看各阶段的执行情况,以及查看Jenkins发送在企业微信中构建信息。
1 2 3 4 5 6 7 8 9 10 11 12 Jenkins-消息通知【weiyigeek-oa-1】任务开始 项目信息: overtime-leave-1.5.5.jar 提交信息: 6f335ad 统计查询添加筛选条件 构建版本: master - origin/master 构建操作: None 镜像构建: True 部署环境: Prod 成品归档: False 质量测试: False 镜像仓库1: harbor.weiyigeek.top/weiyigeek/oa:master 镜像仓库2: harbor.weiyigeek.top/weiyigeek/oa:latest 查看当前任务流水线
weiyigeek.top-流水线任务阶段执行情况查看说明图
至此,在 Docker 中运行 Jenkins Agent 实践完毕!