如何在 Kubernetes Pod 上设置 Jenkins 构建代理

 

 

 

目录

Jenkins Kubernetes Pod 代理如何工作?

在 Kubernetes 上设置 Jenkins 构建 Pod

设置 Kubernetes 命名空间和服务帐户

Kubernetes 中的 Jenkins 主设置

Jenkins Kubernetes 插件配置

第 1 步:安装 Jenkins Kubernetes 插件

第 2 步:创建 Kubernetes 云配置

第 3 步:配置 Jenkins Kubernetes 云

Jenkinsfile 和 Pod 模板

将共享持久卷与 Jenkins Docker 代理 Pod 一起使用

在 Kubernetes 集群上构建 Docker 镜像


在本 Jenkins 教程中,我解释了使用 Jenkins kubernetes 插件在 Kubernetes pod 上设置 Jenkins master 和扩展 Jenkins 构建代理的详细步骤

在另一篇文章中,我解释了如何设置基于 Docker 的 Jenkins 代理

如果您的环境中有Kubernetes 集群,则在 Kubernetes pod 上运行 Jenkins 代理将为您提供针对不同应用程序版本的良好构建隔离。

此外,基于 Kubernetes pod 的临时 Jenkins 代理是降低 CI 环境成本的好方法,因为 Jenkins 代理只有在有构建请求时才会启动。

Jenkins Kubernetes Pod 代理如何工作?

在进入实现之前,让我们了解一下这个设置是如何工作的。 

  1. 每当您触发Jenkins作业时,Jenkins Kubernetes 插件都会进行 API 调用以创建 Kubernetes 代理 pod。
  2. 然后,Jenkins 代理 pod 被部署在 kubernetes 中,其中包含一些包含 Jenkins 服务器详细信息和机密的环境变量。
  3. 当代理 pod 出现时,它会使用其环境变量中的详细信息并使用 JNLP 方法与 Jenkins 对话。下图显示了代理 pod 的环境变量。

Jenkinsfile 中的所有构建步骤都在该 pod 上运行。构建完成后,pod 将自动终止。还有一些选项可以保留构建 pod。

Jenkins Kubernetes 插件负责从 Jenkins 到 Kubernetes 集群的所有通信。

此外,只要您的 Kubernetes 集群可扩展,您就可以毫无问题地扩展您的 Jenkins 构建代理。

在 Kubernetes 上设置 Jenkins 构建 Pod

要进行此设置,我们需要以下内容。

  1. 一个工作的 Kubernetes 集群。
  2. 用于创建 Kubernetes 部署和服务帐户的 Kubernetes 管理员用户
  3. 一个正在运行的 Jenkins 大师

另外,我在这里考虑两种情况。

  1. Jenkins master 在 Kubernetes 集群中运行。
  2. Jenkins master 在 Kubernetes 集群外运行。

我们将研究这两种情况及其配置。

Overfall,这就是我们要做的。

  1. 创建命名空间devops-tools
  2. 创建一个 Kubernetes 服务帐户,该帐户jenkins-admin具有在命名空间中管理 pod 的权限devops-tools。Jenkins 将使用此服务帐户来部署代理 pod。(内部和外部 Jenkins)
  3. 使用服务帐户在devops-tools 命名空间中部署 Jenkins 。jenkins-admin(如果您没有现有的 Jenkins)
  4. 为 Jenkins 配置 Kubernetes Jenkins 插件以与 Kubernetes 集群交互并部署构建代理。

设置 Kubernetes 命名空间和服务帐户

让我们开始设置。

第 1 步:创建一个名为devops-tools

kubectl create namespace devops-tools

第 2 步:将以下清单另存为service-account.yaml. 它包含服务帐户的角色和角色绑定,具有在命名空间中管理 pod 的所有权限devops-tools

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-admin
  namespace: devops-tools
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: jenkins
  namespace: default
  labels:
    "app.kubernetes.io/name": 'jenkins'
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get","list","watch"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-role-binding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins
subjects:
- kind: ServiceAccount
  name: jenkins-admin
  namespace: default

创建服务帐户。

kubectl apply -f service-account.yaml

 

 

Kubernetes 中的 Jenkins 主设置

在此设置中,我们将 Jenkins 主服务器和代理程序部署在同一个 Kubernetes 集群中。

我们将在 Kubernetes 集群上设置 Jenkins 主服务器。

注意:如果您有现有的设置,也可以使用它。确保它具有有权在部署 Jenkins 的命名空间中部署 pod 的服务帐户。

将以下清单另存为deployment.yaml. 此清单包含持久卷、部署和服务定义。

# Persistent Volume Claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pv-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Gi

# Deployment Config
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      serviceAccountName: jenkins-admin
      securityContext:
            fsGroup: 1000 
            runAsUser: 1000
      containers:
        - name: jenkins
          image: jenkins/jenkins:lts
          resources:
            limits:
              memory: "2Gi"
              cpu: "1000m"
            requests:
              memory: "500Mi"
              cpu: "500m"
          ports:
            - name: httpport
              containerPort: 8080
            - name: jnlpport
              containerPort: 50000
          livenessProbe:
            httpGet:
              path: "/login"
              port: 8080
            initialDelaySeconds: 90
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 5
          readinessProbe:
            httpGet:
              path: "/login"
              port: 8080
            initialDelaySeconds: 60
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 3
          volumeMounts:
            - name: jenkins-data
              mountPath: /var/jenkins_home         
      volumes:
        - name: jenkins-data
          persistentVolumeClaim:
              claimName: jenkins-pv-claim

# Service Config
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins-service
  annotations:
      prometheus.io/scrape: 'true'
      prometheus.io/path:   /
      prometheus.io/port:   '8080'
spec:
  selector: 
    app: jenkins
  type: NodePort  
  ports:
    - name: httpport
      port: 8080
      targetPort: 8080
      nodePort: 32000
    - name: jnlpport
      port: 50000
      targetPort: 50000

 

 

创建部署。

kubectl apply -f deployment.yaml

几分钟后,Jenkins 部署将启动,您将能够通过端口上的任何 Kubernetes 节点进行访问32000

第 4 步:通过节点端口访问 Jenkins 仪表板并使用 pod 日志中的密码将其解锁。安装建议的插件并创建一个 Jenkins 用户。

Jenkins Kubernetes 插件配置

需要Jenkins Kubernetes 插件来设置基于 Kubernetes 的构建代理。让我们配置插件。

第 1 步:安装 Jenkins Kubernetes 插件

转到Manage Jenkins –> Manage Plugins,在可用选项卡中搜索 Kubernetes Plugin 并安装它。以下 Gif 视频显示了插件安装过程。

第 2 步:创建 Kubernetes 云配置

安装后,转到 Manage Jenkins->Manage Node & Clouds4

 

单击配置云

 

“添加新云”选择 Kubernetes。

选择 Kubernetes 云详细信息

第 3 步:配置 Jenkins Kubernetes 云

这里我们有两个场景。

  1. Jenkins 服务器在同一个 Kubernetes 集群中运行
  2. Jenkins 服务器运行 Kubernetes 集群。

让我们看看这两种情况的配置。

Jenkins 服务器在同一个 Kubernetes 集群中运行

由于我们在 Kubernetes 集群中有 Jenkins 并使用服务帐户来部署代理 pod,因此我们不必提及 Kubernetes URL 或证书密钥。

但是,要使用服务帐户验证连接,请使用测试连接按钮,如下所示。如果 Jenkins pod 可以连接到 Kubernetes 主 API,它应该显示一条连接消息

 

运行在 Kubernetes 集群外的 Jenkins 服务器

如果您的 Jenkins 服务器在 Kubernetes 集群之外运行,您需要指定以下内容。

  1. Kubernetes URL:这是 Kubernetes 主 API 端点。如果启用了 https,请使用 https 网址。
  2. Kubernetes 服务器证书密钥:如果您有 Kubernetes 集群 CA 证书,您可以添加它以实现安全连接。您可以从 pod 位置获取证书/var/run/secrets/kubernetes.io/serviceaccount/ca.crt。如果您没有证书,您可以启用“ disable https certificate check”选项。
  3. 凭证:为了让 Jenkins 与 Kubernetes 集群通信,我们需要一个服务帐户令牌,该令牌具有在devops-tools命名空间中部署 pod 的权限。

注意:如果您使用GKE 集群等托管服务,则可以从 GKE 仪表板获取所有集群详细信息。

我们已经在devops-tools命名空间中创建了服务帐户。我们需要从服务帐户中获取令牌。

执行以下命令以从服务帐户中检索密钥名称。

SECRET_NAME=$(kubectl get serviceaccount jenkins-admin  -o=jsonpath='{.secrets[0].name}' -n devops-tools)

现在,我们将使用 SECRET_NAME 获取 base64 编码的服务帐户令牌,然后对其进行解码。您将获得令牌作为输出。 

kubectl get secrets $SECRET_NAME  -o=jsonpath='{.data.token}' -n devops-tools | base64 -D

 

现在单击Add凭据下的按钮并创建凭据类型“ Secret text”。在密码框中输入服务帐户令牌并添加其他详细信息,如下所示。最后,保存凭证。

Kubernetes 云配置如下所示。

填写完所有详细信息后,您可以测试连接以验证 Kubernetes 集群的连接性。

第 4 步:配置 Jenkins URL 详细信息

对于在集群内部运行的 Jenkins master,您可以使用 Kubernetes 集群的 Service 端点作为 Jenkins URL,因为代理 pod 可以通过内部服务 DNS 连接到集群。

URL 是使用以下语法派生的。

 

http://<service-name>.<namespace>.svc.cluster.local:8080

在我们的例子中,服务 DNS 将是,

 

http://jenkins-service.devops-tools.svc.cluster.local:8080

 

 

此外,如果需要,可以添加可用于对容器进行分组的 POD 标签,以便根据bulling 或自定义构建仪表板进行分组。

注意:如果 Jenkins master 在 Kubernetes 集群之外,请在 Jenkins URL 配置中使用Jenkins IP 或 DNS 。

第 5 步:创建 POD 和容器模板

接下来,您需要添加带有详细信息的 POD 模板,如下图所示。该标签kubeagent将在作业中用作标识符,以选择此 pod 作为构建代理。接下来,我们需要添加一个包含 Docker 映像详细信息的容器模板。

 

下一个配置是容器模板。如果您不添加容器模板,Jenkins Kubernetes 插件将使用来自 Docker 中心的默认 JNLP 映像来启动代理。即,詹金斯/入站代​​理

如果您在公司网络上并且无权访问 Docker 集线器,则必须构建自己的jnlp映像并使用相同的名称覆盖默认值,如下所示,假设jenkins/inbound-agent:latest是自定义 jnlp 映像。

确保从容器模板中删除sleep和default 参数。9999999

我们可以将多个容器模板添加到 POD 模板中,并在管道中使用它们。我已经在下一节中通过Jenkinsfile示例解释了这一点。

这是代理工作所需的基本最低配置。稍后我将在管道示例中解释一些卷和其他选项的用例。

现在保存所有配置,让我们测试是否可以使用 pod 代理构建作业。

第 6 步:转到 Jenkins 主页 -> 新建项目并创建一个自由式项目。

在职位描述中,添加kubeagent如下所示的标签。它是我们分配给 pod 模板的标签。这样,Jenkins 就知道代理容器使用哪个 pod 模板。

添加带有 echo 命令的 shell 构建步骤以验证作业,如下所示。

现在,保存作业配置并单击“立即构建”

您应该在作业构建历史记录中看到一个待处理的代理,如下所示。

 

几分钟后,您将看到一个成功的构建。如果您检查日志,它将向您显示已执行的 shell。

Jenkinsfile 和 Pod 模板

到目前为止,我们所看到的都是理解和验证 Kubernetes Jenkins 插件设置。

当涉及到实际的项目流水线时,最好将 POD 模板放在Jenkinsfile

这是您应该了解的有关 POD 模板的内容。

  1. 默认情况下,插件使用 JNLP 容器映像连接到 Jenkins 服务器。如果您jnlp在容器模板中提供名称,则可以使用自定义 JNLP 图像覆盖。
  2. 您可以在一个 pod 模板中包含多个容器模板。然后,每个容器都可以用于不同的流水线阶段。
  3. POD_LABEL触发构建时,将为 pod 分配一个随机构建标签。您不能提供除POD_LABEL

这是一个Jenkinsfile带有 POD 模板的示例。

podTemplate {
    node(POD_LABEL) {
        stage('Run shell') {
            sh 'echo hello world'
        }
    }
}

如果您在管道作业中构建上述 Jenkinsfile,它将使用默认的 JNLP 映像并在“运行 Shell”阶段执行命令。当我说默认时,如果您未指定任何内容,插件将使用来自 docker hub 的 JNLP 图像。

现在,您可以使用带有所有必要构建工具的自己的jnlp图像containerTemplate,并在管道中使用它们,如下所示。

在这里,jenkins/inbound-agent:latest您将拥有自己的图像,而不是 。

podTemplate(containers: [
    containerTemplate(
        name: 'jnlp', 
        image: 'jenkins/inbound-agent:latest'
        )
  ]) {

    node(POD_LABEL) {
        stage('Get a Maven project') {
            container('jnlp') {
                stage('Shell Execution') {
                    sh '''
                    echo "Hello! I am executing shell"
                    '''
                }
            }
        }

    }
}

 

 

您可以在单个 POD 模板中使用多个容器模板。

这是此设置的一个用例。

假设您要设置一个构建管道来构建 java 和 python 项目。在这种情况下,您可以使用两个容器模板并在构建阶段使用它。

在以下示例中,在两个单独的阶段中,我们调用 pod 模板中指定的两个不同容器。

一个容器包含 java 构建的所有 maven 依赖项,另一个容器包含 python 构建依赖项。

podTemplate(containers: [
    containerTemplate(
        name: 'maven', 
        image: 'maven:3.8.1-jdk-8', 
        command: 'sleep', 
        args: '30d'
        ),
    containerTemplate(
        name: 'python', 
        image: 'python:latest', 
        command: 'sleep', 
        args: '30d')
  ]) {

    node(POD_LABEL) {
        stage('Get a Maven project') {
            git 'https://github.com/spring-projects/spring-petclinic.git'
            container('maven') {
                stage('Build a Maven project') {
                    sh '''
                    echo "maven build"
                    '''
                }
            }
        }

        stage('Get a Python Project') {
            git url: 'https://github.com/hashicorp/terraform.git', branch: 'main'
            container('python') {
                stage('Build a Go project') {
                    sh '''
                    echo "Go Build"
                    '''
                }
            }
        }

    }
}

您可以尝试使用管道作业构建上述 Jenkinsfile。

在构建上述管道时,如果您检查 kubernetes pod,您将在构建代理 pod 中看到三个容器,如下所示。

注意:由于实际项目中的安全合规性问题,您不能直接使用 Docker hub 镜像。所以你必须构建自己的 Docker 镜像并将它们托管在组织批准的容器注册表中。

将共享持久卷与 Jenkins Docker 代理 Pod 一起使用

为了加快构建过程,最好将共享持久卷附加到构建容器。

例如,如果您使用 Java 应用程序,它有许多 maven 包依赖项。

当您构建 java 应用程序pom.xml 时,它会第一次从远程 maven 存储库中下载添加的依赖项,并创建一个本地 .m2 缓存目录,其中缓存依赖包。

.m2缓存在基于 Docker 代理的构建中是不可能的,因为它在构建后被销毁。

我们可以为 maven 缓存创建一个持久化卷,并通过容器模板将其附加到代理 pod 以解决此问题。

为了演示这一点,首先,让我们创建一个 PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: maven-repo-storage
  namespace: devops-tools
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Gi

 

 这是一个Jenkinsfile使用maven-repo-storage持久卷的 POD 模板示例。

podTemplate(containers: [
  containerTemplate(
      name: 'maven', 
      image: 'maven:latest', 
      command: 'sleep', 
      args: '99d'
      )
  ], 
  
  volumes: [
  persistentVolumeClaim(
      mountPath: '/root/.m2/repository', 
      claimName: 'maven-repo-storage', 
      readOnly: false
      )
  ]) 

{
  node(POD_LABEL) {
    stage('Build Petclinic Java App') {
      git url: 'https://github.com/spring-projects/spring-petclinic.git', branch: 'main'
      container('maven') {
        sh 'mvn -B -ntp clean package -DskipTests'
      }
    }
  }
}

 

在 Kubernetes 集群上构建 Docker 镜像

如果您使用 Docker 部署应用程序,您可以在 Kubernetes 代理上集成您的 CI Docker 构建管道。

有几种方法可以在 docker 上运行 docker 以用于构建用例。但是,由于 Kubernetes 删除了 docker 运行时,因此最好使用替代解决方案。

目前,在 Kubernetes 集群上构建 docker 镜像的最佳方式是使用Kaniko


如果您使用 Jenkins 和 kubernetes,您绝对应该尝试基于容器的代理。

在 Kubernetes 上扩展您的 Jenkins 代理可以帮助您摆脱使用静态构建 VM 获得的大量管理开销。尽管有可用的动态 VM 构建选项,但与动态容器代理相比,每个构建都可能需要很长时间。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Meta.Qing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值