小言_互联网的博客

Jenkins 基于Kubernetes 弹性构建池

479人阅读  评论(0)

流程:

  • 获取Jenkins Agent的参数;

  • 渲染yaml模板;

  • 调用K8s API在固定的NS中创建一个Pod;

创建Agent


   
  1. import hudson.model.Node.Mode
  2. import hudson.slaves.*
  3. import jenkins.model.Jenkins
  4. // 创建agent 下面是执行器数量的定义和label
  5. String agentName = "__AGENT_NAME__"
  6. String executorNum = "1"
  7. String agentLabel = "JenkinsPod"
  8. agent_node = new DumbSlave(agentName, "Jenkins pod", "/opt/jenkins", executorNum,
  9. Mode.EXCLUSIVE,
  10. agentLabel,
  11. new JNLPLauncher(),
  12. RetentionStrategy.INSTANCE)
  13. Jenkins.instance.addNode(agent_node)
  14. //获取agent的配置
  15. node = Jenkins.instance.getNode(agentName)
  16. computer = node.computer
  17. jenkinsUrl = Jenkins.instance.rootUrl.trim().replaceAll( '/$', '')
  18. return "" "{
  19. \"jenkinsUrl\" : \"${jenkinsUrl}\",
  20. \"jenkinsHome\": \"${node.remoteFS.trim()}\",
  21. \"computerUrl\": \"${computer.url.trim().replaceAll('/$', '') as String}\",
  22. \"computerSecret\": \"${computer.jnlpMac.trim()}\"
  23. }" ""

这里返回的是json类型的字符串,这样在调试的时候非常的方便。

这些信息最后在k8s里面需要以环境变量的方式指定出来。

其实手动创建好,然后将这串密钥拿下来,然后去启动他。但是现在自动化的去创建了。并且还将认证信息拿出来了。

后面在添加动态节点的时候先添加agent,然后拿到它的参数,最后渲染为pod的yaml,再去创建pod。

删除Agent

当资源不再使用了,就可以将节点删除。


   
  1. import jenkins.model.Jenkins
  2. String agentName = "__AGENT_NAME__"
  3. Jenkins.instance.nodes.each { node ->
  4. String nodeName = node.name
  5. if (nodeName.equals(agentName)) {
  6. Jenkins.instance.removeNode(node)
  7. }
  8. }

ScriptConsole


   
  1. // ScriptConsole运行脚本
  2. def RunScriptConsole(scriptContent, crumb){
  3. response = sh returnStdout: true,
  4. script: "" "
  5. curl -s -d "script=\$( cat ${scriptContent}) " \
  6. --header "Jenkins-Crumb: ${crumb} " \
  7. -X POST http://admin:112374bd5c557010386b55bb85a777aded@192.168.1.200:8080/scriptText
  8. " ""
  9. try {
  10. response = readJSON text: response - "Result: "
  11. } catch(e){
  12. println(e)
  13. }
  14. return response
  15. }
  16. // 获取Crumb值
  17. def GetCrumb(){
  18. response = sh returnStdout: true,
  19. script: "" " curl -s -u admin:admin \
  20. --location \
  21. --request GET 'http://192.168.1.200:8080/crumbIssuer/api/json' " ""
  22. response = readJSON text: response
  23. return response.crumb
  24. }

   
  1. http://192.168.11.128:8080/crumbIssuer/api/json
  2. { "_class": "hudson.security.csrf.DefaultCrumbIssuer", "crumb": "f72990e2bc09a468effa69ec41f1432844bc709ca5ad6130d600da24ad16672a", "crumbRequestField": "Jenkins-Crumb"}

   
  1. curl -s -d "script=$(cat create_agent.groovy)" \
  2. --header "Jenkins-Crumb:f72990e2bc09a468effa69ec41f1432844bc709ca5ad6130d600da24ad16672a" \
  3. -X POST http://admin:115fcd2e2d30505df7a18f23763c1332a0@192.168.11.128:8080/scriptText

   
  1. [root@jenkins ~] # curl -s -d "script=$(cat create_agent.groovy)" --header "Jenkins-Crumb:f72990e2bc09a468effa69ec41f1432844bc709ca5ad6130d600da24ad16672a" -X POST http://admin:115fcd2e2d30505df7a18f23763c1332a0@192.168.11.128:8080/scriptText
  2. Result: {
  3. "jenkinsUrl" : "http://192.168.11.128:8080",
  4. "jenkinsHome": "/opt/jenkins",
  5. "computerUrl": "computer/%5F%5FAGENT%5FNAME%5F%5F",
  6. "computerSecret": "6473dea92efa350d744450b91f010cd01880e0686597b8d33ef0876e698127c7"
  7. }

Pod Yaml模板


   
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. labels:
  5. app: __AGENT_NAME__
  6. name: __AGENT_NAME__
  7. namespace: __NAMESPACE__
  8. spec:
  9. containers:
  10. - name: dind
  11. image: 'docker:stable-dind'
  12. command:
  13. - dockerd
  14. - --host=unix:///var/run/docker.sock
  15. - --host=tcp://0.0.0.0:8000
  16. - --insecure-registry=192.168.1.200:8088
  17. securityContext:
  18. privileged: true
  19. volumeMounts:
  20. - mountPath: /var/run
  21. name: docker-dir
  22. - image: agenttest:6 #jenkins/inbound-agent:4.10-3-jdk8
  23. name: __AGENT_NAME__
  24. imagePullPolicy: IfNotPresent
  25. resources:
  26. limits:
  27. cpu: 1000m
  28. memory: 8Gi
  29. requests:
  30. cpu: 500m
  31. memory: 2Gi
  32. env:
  33. - name: JENKINS_URL
  34. value: __JENKINS_URL__
  35. - name: JENKINS_SECRET
  36. value: __JENKINS_SECRET__
  37. - name: JENKINS_AGENT_NAME
  38. value: __AGENT_NAME__
  39. - name: JENKINS_AGENT_WORKDIR
  40. value: /home/jenkins/workspace
  41. volumeMounts:
  42. - mountPath: /var/run
  43. name: docker-dir
  44. dnsPolicy: ClusterFirst
  45. restartPolicy: Always
  46. volumes:
  47. - name: docker-dir
  48. emptyDir: {}

这里有两个容器,一个是docker in docker,因为containerd里面没有这个文件了。

因为docker共享了目录,在另外一个容器目录里面也可以看到,那么在另外的容器里面就可以运行docker命令了。

Kubernetes API准备工作

  1. 创建一个NS名称空间, 专用于运行Pod;

kubectl create ns jenkins
  1. 创建一个secret关联serviceaccount和role,操作K8s API;


   
  1. # 创建role
  2. kubectl -n jenkins create role jenkinsadmin \
  3. --verb=create,delete,update,list,get,patch \
  4. --resource=pods
  5. # 创建服务账户
  6. kubectl -n jenkins create serviceaccount jenkinsadmin
  7. # 创建角色绑定
  8. kubectl -n jenkins create rolebinding jenkinsadmin --role=jenkinsadmin --serviceaccount=jenkins:jenkinsadmin
  9. # 创建secret
  10. kubectl apply -f - << EOF
  11. apiVersion: v1
  12. kind: Secret
  13. metadata:
  14. name: jenkinsadmin-token
  15. namespace: jenkins
  16. annotations:
  17. kubernetes.io/service-account.name: jenkinsadmin
  18. type: kubernetes.io/service-account-token
  19. EOF
  20. while ! kubectl -n jenkins describe secret jenkinsadmin-token | grep -E '^token' >/dev/null; do
  21. echo "waiting for token..." >&2
  22. sleep 1
  23. done
  24. # 获取令牌
  25. TOKEN=$(kubectl -n jenkins get secret jenkinsadmin-token -o jsonpath= '{.data.token}' | base64 --decode)
  26. echo $TOKEN
  27. # 获取API
  28. kubectl config view -o jsonpath= '{"Cluster name\tServer\n"}{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}'
  29. # 使用令牌玩转 API
  30. curl -X GET https://127.0.0.1:35659/api --header "Authorization: Bearer $TOKEN" --insecure

   
  1. [root@192 ~] # curl -X GET https://127.0.0.1:6443/api --header "Authorization: Bearer $TOKEN" --insecure
  2. {
  3. "kind": "APIVersions",
  4. "versions": [
  5. "v1"
  6. ],
  7. "serverAddressByClientCIDRs": [
  8. {
  9. "clientCIDR": "0.0.0.0/0",
  10. "serverAddress": "192.168.11.134:6443"
  11. }
  12. ]
  13. }

将token 以secret text类型存储到Jenkins

POD API


   
  1. //删除POD
  2. def DeletePod(namespace, podName){
  3. withCredentials([string(credentialsId: 'f66733bf-ef35-402d-87d1-a79510387d2b', variable: 'CICDTOKEN')]) {
  4. sh "" "
  5. curl --location --request DELETE "https://192.168.1.200:6443/api/v1/namespaces/ ${namespace}/pods/ ${podName} " \
  6. --header "Authorization: Bearer ${CICDTOKEN} " \
  7. --insecure >/dev/null
  8. " ""
  9. }
  10. }
  11. // 创建POD
  12. def CreatePod(namespace, podYaml){
  13. withCredentials([string(credentialsId: 'f66733bf-ef35-402d-87d1-a79510387d2b', variable: 'CICDTOKEN')]) {
  14. sh "" "
  15. curl --location --request POST "https://192.168.1.200:6443/api/v1/namespaces/ ${namespace}/pods " \
  16. --header 'Content-Type: application/yaml' \
  17. --header "Authorization: Bearer ${CICDTOKEN} " \
  18. --data " ${podYaml} " --insecure >/dev/null
  19. " ""
  20. }
  21. }

   
  1. curl --location --request POST "https://192.168.11.134:6443/api/v1/namespaces/jenkins/pods" \
  2. --header 'Content-Type: application/yaml' \
  3. --header "Authorization: Bearer ${TOKEN}" \
  4. --data "${podYaml}" --insecure >/dev/null
  5. curl --location --request DELETE "https://192.168.11.134:6443/api/v1/namespaces/jenkins/pods/nginx" \
  6. --header "Authorization: Bearer ${TOKEN}" \
  7. --insecure >/dev/null

   
  1. curl --location --request GET 'https://192.168.11.134:6443/api/v1/namespaces/jenkins/pods' \
  2. --header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjBqSWxfOExtSW1pVmpKVkFUVGFQbHp1ZE5TcFo0SjlmOUtjMWFveWtrZGMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJqZW5raW5zIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImplbmtpbnNhZG1pbi10b2tlbi1jbTRsNyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJqZW5raW5zYWRtaW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJjMDAwZTVhMC00Yzg0LTQyZWEtYmJiNy1mZmM5MDBhYzUyMjIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6amVua2luczpqZW5raW5zYWRtaW4ifQ.A-InywzLZZfwx_4-Na9iDDRGsIH0Bjm9Xk92VxKsnP7hflEbOU631EU0eHnewgg0UqAD1kkhW39XupN13oTXrOjHrzWdm_UUMe2cBIYCZD19VIpNnRZ6bBLZ3LFHA2F0gXO14HaVZiUvSYBXgIfyHydetIFQFBPWFtU7091u5iB4pcw_gE-VzGjX6NDHj-81j6Ap2Qr0gIrNvrPVAOpPO9uCSg3PNCgvQMq2ZNrY2te1w7QxmeFPEpOIPiK6VbUkRjhQlHmawULZFol2k5Wwv9z0m1hPQcc2Nten1f1__GR39hUjryWXfltJ8OLpbKWK-AtfBkHx8VqbiKH1vQOrRg' \
  3. --header 'Content-Type: text/plain' \
  4. --data-raw 'abc'

这里请求方法由get换成了delete

自定义构建镜像


   
  1. FROM centos:7
  2. USER root
  3. ADD tools/jdk-8u201-linux-x64.tar.gz /usr/local
  4. ENV JAVA_HOME=/usr/local/jdk1.8.0_201
  5. ENV M2_HOME=/usr/local/apache-maven-3.8.1
  6. COPY tools/agent.jar /usr/share/jenkins/agent.jar
  7. COPY tools/jenkins-agent /usr/local/bin/jenkins-agent
  8. COPY tools/apache-maven-3.8.1 /usr/local/apache-maven-3.8.1
  9. COPY tools/helm /usr/bin/helm
  10. COPY tools/kubectl /usr/bin/kubectl
  11. RUN echo "export PATH=$PATH:$JAVA_HOME/bin:$M2_HOME/bin" >> /etc/profile && \
  12. source /etc/profile && \
  13. java -version && \
  14. chmod +x /usr/local/bin/jenkins-agent && \
  15. ln -s /usr/local/bin/jenkins-agent /usr/local/bin/jenkins-slave && \
  16. yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo && \
  17. yum -y install docker-ce && \
  18. mkdir -p /home/jenkins/workspace && chmod 777 /home/jenkins/workspace && \
  19. yum -y install git && \
  20. chmod +x /usr/bin/helm && helm version && chmod +x /usr/bin/kubectl
  21. COPY tools/daemon.json /etc/docker/daemon.json
  22. ENTRYPOINT [ "/usr/local/bin/jenkins-agent"]

上面就是整个流程,k8s动态创建 销毁pod,在pod上面创建构建任务,构建完任务就将这个pod给删除了。


转载:https://blog.csdn.net/qq_34556414/article/details/129055666
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场