Jenkins 基于 Kubernetes 的动态和静态节点

WilliamGates
发布于 2023-11-23 14:33
浏览
0收藏

Agent 节点

虽然我们上面提到了动态节点的好处,但是还是会有一部分人比较喜欢坚持静态节点的方式,选择静态或者动态的 Jenkins Agent 节点都是可以的。接下来我们就分别来介绍下如何在 Kubernetes 集群中为 Jenkins 提供动静态 Agent 节点。

静态节点

首先在 Jenkins 页面 http://jenkins.k8s.local/computer/new 新建一个节点:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

点击创建后配置节点信息,然后点击保存:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

保存后我们可以看到节点已经创建成功了:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

然后点击列表中的 ​agent1​ 名称,进入节点详情页面,在详情页面我们将获取到运行该节点的一些密钥信息,

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

然后创建一个如下所示的资源清单文件:

# jenkins-agent.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-agent
  namespace: kube-ops
spec:
  selector:
    matchLabels:
      app: jenkins-agent
  template:
    metadata:
      labels:
        app: jenkins-agent
    spec:
      containers:
        - name: agent
          image: jenkins/inbound-agent
          securityContext:
            privileged: true
          imagePullPolicy: IfNotPresent
          env:
            - name: JENKINS_URL
              value: http://jenkins.k8s.local
            - name: JENKINS_SECRET
              value: 9c4c5159b111083705eed5802ceb021cfad002a18dd59c692aa59a9616e6285a
            - name: JENKINS_AGENT_NAME
              value: agent1
            - name: JENKINS_AGENT_WORKDIR
              value: /home/jenkins/workspace

上面的清单文件中的 ​​JENKINS_URL​​​、​​JENKINS_SECRET​​​ 和 ​​JENKINS_AGENT_WORKDIR​​ 这些环境变量的值就是上面我们在节点详情页面获取到的信息,然后我们将这个文件应用到集群中:

$ kubectl apply -f jenkins-agent.yaml

创建后正常该 agent 的 Pod 会启动报错,错误日志如下所示:

INFO: Locating server among [http://jenkins.k8s.local/]
Sep 07, 2023 7:55:51 AM hudson.remoting.jnlp.Main$CuiListener error
SEVERE: Failed to connect to http://jenkins.k8s.local/tcpSlaveAgentListener/: jenkins.k8s.local
java.io.IOException: Failed to connect to http://jenkins.k8s.local/tcpSlaveAgentListener/: jenkins.k8s.local
        at org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.resolve(JnlpAgentEndpointResolver.java:216)
        at hudson.remoting.Engine.innerRun(Engine.java:760)
        at hudson.remoting.Engine.run(Engine.java:543)
Caused by: java.net.UnknownHostException: jenkins.k8s.local
        at java.base/java.net.AbstractPlainSocketImpl.connect(Unknown Source)
        at java.base/java.net.Socket.connect(Unknown Source)
        at java.base/sun.net.NetworkClient.doConnect(Unknown Source)
        at java.base/sun.net.www.http.HttpClient.openServer(Unknown Source)
        at java.base/sun.net.www.http.HttpClient.openServer(Unknown Source)
        at java.base/sun.net.www.http.HttpClient.<init>(Unknown Source)
        at java.base/sun.net.www.http.HttpClient.New(Unknown Source)
        at java.base/sun.net.www.http.HttpClient.New(Unknown Source)
        at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
        at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(Unknown Source)
        at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
        at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
        at org.jenkinsci.remoting.engine.JnlpAgentEndpointResolver.resolve(JnlpAgentEndpointResolver.java:213)
        ... 2 more

这其实是因为我们配置的 ​​jenkins.k8s.local​​ 域名是一个自定义的域名,需要在 K8s 集群中解析的话,我们还需要在 CoreDNS 中去添加一条 hosts 映射:

$ kubectl edit cm coredns -n kube-system

# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  Corefile: |
    .:53 {
        errors
        health {
           lameduck 5s
        }
        hosts {
          10.206.16.10 jenkins.k8s.local
          fallthrough
        }
#  ......
kind: ConfigMap

但其实还有更简单的方式,那就是直接将 ​​JENKINS_URL​​​ 值替换为 Jenkins 的 Service 地址 ​​http://jenkins.kube-ops.svc.cluster.local:8080​​ 即可,这样就不需要在 CoreDNS 中添加 hosts 映射了。

正常现在的 Jenkins Agent Pod 应该是正常运行的,我们可以通过下面的命令查看:

$ kubectl get pods -n kube-ops -l app=jenkins-agent
NAME                             READY   STATUS    RESTARTS   AGE
jenkins-agent-76884cd44c-dd9ds   1/1     Running   0          2m32s

再次查看节点列表,我们可以看到节点已经在线了:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

接下来我们再创建一个 Pipeline 类型的作业,然后在 Pipeline 脚本中添加下面的内容:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

这里我们定义的流水线脚本中,我们使用到了 ​​agent​​​ 关键字,这个关键字的作用就是指定这个流水线的运行环境,这里我们指定的是 ​​build​​ 这个标签,也就是我们上面创建的 agent1 这个节点,这样这个流水线就会在这个节点上运行。

点击保存后,我们可以点击立即构建来执行这个流水线,然后我们可以查看这个流水线的执行结果:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

这样我们就可以在 Jenkins 中使用这个静态节点来构建任务了。

动态节点

除了静态节点之外,我们还可以使用动态节点的方式来构建任务,这样可以更好的利用资源,我们这里使用的是 Kubernetes 的方式来创建动态节点,这样我们就可以在 Jenkins 中使用动态节点来构建任务了。

第 1 步. 首先需要安装 kubernetes 插件。

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

第 2 步. 安装完毕后,进入 ​http://jenkins.k8s.local/manage/cloud/​ 页面:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

在该页面点击 ​New cloud​ 新建一个 Cloud 服务:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

这里注意一定要选择上 ​Kubernetes​ 这个 Type,然后点击 ​Create​ 按钮,然后我们就可以看到下面的配置页面了:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

首先配置连接 Kubernetes APIServer 的地址,由于我们的 Jenkins 运行在 Kubernetes 集群中,所以可以使用 Service 的 DNS 形式进行连接 ​https://kubernetes.default.svc.cluster.local​

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

命名空间这里填 ​​kube-ops​​​,然后点击 ​​连接测试​​​,如果出现 ​​Connected to Kubernetes v1.26.2​​ 这样的提示信息证明 Jenkins 已经可以和 Kubernetes 系统正常通信了。

然后下方的 Jenkins URL 地址为 ​​http://jenkins.kube-ops.svc.cluster.local:8080​​,根据上面创建的 jenkins 的服务名填写,包括下面的 Jenkins 通道,默认是 50000 端口(要注意是 TCP,所以不要填写 http):

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

然后点击最后的 ​​save​​ 按钮保存配置。到这里我们的 Kubernetes 插件就算配置完成了。

测试

Kubernetes 插件的配置工作完成了,接下来我们就来添加一个 Job 任务,看是否能够在 Slave Pod 中执行,任务执行完成后看 Pod 是否会被销毁。

在 Jenkins 首页点击 ​​新建任务​​​,创建一个测试的任务,同样还是选择 ​​Pipeline​​ 类型的任务,这次我们需要使用的流水线脚本就更复杂了,如下所示:

pipeline{
    agent{
        kubernetes{
            label "test01"
            cloud 'Kubernetes'
            yaml '''
---
kind: Pod
apiVersion: v1
metadata:
  labels:
    k8s-app: jenkins-agent
  name: jenkins-agent
  namespace: kube-ops
spec:
containers:
  - name: jenkinsagent
    image: jenkins/inbound-agent
    imagePullPolicy: IfNotPresent
'''
        }
    }

    stages{
        stage("Hello"){
          steps{
            script{
              echo "Hello Slave Pod on Kubernetes!"
            }
          }
        }
    }
}

这次的脚本中定义的执行 agent 就比较复杂了,通过一个 ​​kubernetes​​​ 属性来指定这个流水线的运行环境,然后通过 ​​yaml​​​ 属性来定义这个运行 Pod 的清单文件,这里我们定义的是一个简单的 Pod,然后我们将这个 Pod 部署到 ​​kube-ops​​​ 这个命名空间中,这样我们就可以在这个 Pod 中运行我们的 Jenkins Slave 了,需要注意 ​​cloud​​ 后面的值需要和前面我们定义的 Cloud 服务名称一致。

最后点击保存,同样我们可以点击左侧的 ​​立即构建​​ 来执行这个任务,然后我们可以查看这个任务的执行结果:

Jenkins 基于 Kubernetes 的动态和静态节点-鸿蒙开发者社区

虽然我们在这里的脚本中定义的 Pod 非常简单,但可以看到 Jenkins 会帮我们配置一些默认的环境变量。当任务执行的过程中我们也可以观察 Kubernetes 集群中的 Pod 变化:

$ kubectl get pods -n kube-ops -w
NAME                              READY   STATUS        RESTARTS      AGE
jenkins-55c4676f4d-fhmw2          1/1     Running       3 (12m ago)   91m
jenkins-agent-76884cd44c-dd9ds    1/1     Running       0             22m
test01-jnzmb-ht0n7                0/1     Pending       0             0s
test01-jnzmb-ht0n7                0/1     Pending       0             0s
test01-jnzmb-ht0n7                0/1     ContainerCreating   0             0s
test01-jnzmb-ht0n7                1/1     Running             0             1s
test01-jnzmb-ht0n7                1/1     Terminating         0             3s
test01-jnzmb-ht0n7                0/1     Terminating         0             4s
test01-jnzmb-ht0n7                0/1     Terminating         0             4s
test01-jnzmb-ht0n7                0/1     Terminating         0             4s

我们可以看到在我们点击立刻构建的时候可以看到一个新的 Pod:​​test01-jnzmb-ht0n7​​ 被创建了,这就是我们的 Jenkins Slave。当任务构建完抽这个 Slave Pod 也会自动删除。

到这里我们就完成了使用 Kubernetes 动态生成 Jenkins Slave 的方法。


文章转载自公众号:k8s技术圈

分类
标签
已于2023-11-23 14:33:29修改
收藏
回复
举报
回复
    相关推荐