當前位置: 妍妍網 > 碼農

【運維幹貨分享】如何在 Kubernetes Pod 上設定 Jenkins 構建代理

2024-09-24碼農


在此 Jenkins 教程中,我介紹了使用 Jenkins Kubernetes 外掛程式在 Kubernetes Pod 上設定 Jenkins 控制器和擴充套件 Jenkins 構建代理的詳細步驟

在另一篇文章中,我解釋了如何設定基於 Docker 的 Jenkins 代理。

如果你的環境中有 Kubernetes 集群,則在 Kubernetes Pod 上執行 Jenkins 代理將為不同的應用程式版本提供良好的構建隔離。

此外,基於 Kubernetes Pod 的臨時 Jenkins 代理是降低 CI 環境成本的好方法,因為只有在有構建請求時,才會啟動 Jenkins 代理。

Jenkins Kubernetes Pod 代理如何工作?

在開始實施之前,讓我們了解一下此設定的工作原理。

下圖顯示了高級工作流。

  • 每當你觸發 Jenkins 作業時,Jenkins Kubernetes 外掛程式都會進行 API 呼叫以建立 Kubernetes 代理 Pod。

  • 然後,在 Kubernetes 中部署 Jenkins 代理 Pod,其中包含一些包含 Jenkins 伺服器詳細資訊和金鑰的環境變量。

  • 當代理 Pod 啟動時,它會使用其環境變量中的詳細資訊,並使用 JNLP 方法與 Jenkins 進行對話。下圖顯示了代理 Pod 的環境變量。

  • Jenkinsfile 中的所有構建步驟都在該 Pod 上執行。構建完成後,Pod 將自動終止。但是,也有一些選項可以保留 build Pod。

    Jenkins Kubernetes 外掛程式處理從 Jenkins 到 Kubernetes 集群的所有通訊。

    此外,只要你的 Kubernetes 集群可以擴充套件,你就可以毫無問題地擴充套件 Jenkins 構建代理。

    在 Kubernetes 上設定 Jenkins 構建 Pod

    要進行此設定,我們需要以下內容。

  • 一個正在執行的 Kubernetes 集群。

  • 用於建立 Kubernetes 部署和服務帳戶的 Kubernetes 管理員使用者

  • 正在執行的 Jenkins 控制器

  • 此外,我在這裏考慮了兩種情況。

  • 在 Kubernetes 集群內執行的 Jenkins 控制器。

  • 在 Kubernetes 集群外部執行的 Jenkins 控制器。我們將研究這兩種情況及其配置。

  • Overfall,這就是我們要做的事情。

  • 建立名稱空間devops-tools

  • 建立一個 Kubernetes 服務帳戶,該帳戶具有管理名稱空間中 Pod 的許可權。Jenkins 將使用此服務帳戶來部署代理 Pod。(內部和外部Jenkins均可)jenkins-admindevops-tools

  • 使用服務帳戶在名稱空間中部署 Jenkins。(如果你沒有現有的 Jenkins)devops-tools jenkins-admin

  • 配置 Kubernetes Jenkins 外掛程式,以便 Jenkins 可以與 Kubernetes 集互並部署構建代理。

  • 設定 Kubernetes Namespace & Service Account

    讓我們開始設定。

    步驟1:建立一個名為devops-tools

    kubectl create namespace devops-tools

    步驟2:將以下清單另存為 .它包含服務帳戶的角色和角色繫結,該帳戶具有管理名稱空間中 Pod 的所有許可權。service-account.yamldevops-tools

    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: jenkins-admin
    namespace: devops-tools
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    name: jenkins
    namespace: devops-tools
    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: devops-tools
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: jenkins
    subjects:
    - kind: ServiceAccount
    name: jenkins-admin
    namespace: devops-tools

    建立服務帳戶。

    kubectl apply -f service-account.yaml

    下一步是建立一個 Secret,這將為服務帳戶建立一個令牌。

    建立一個 YAML 檔 secret.yaml 並將以下內容復制到其中

    apiVersion: v1
    kind: Secret
    metadata:
    name: sa-token-secret
    namespace: devops-tools
    annotations:
    kubernetes.io/service-account.name: jenkins-admin
    type: kubernetes.io/service-account-token

    建立金鑰

    kubectl apply -f secret.yaml

    這將建立一個金鑰,並使用註釋將其與服務帳戶連結。

    Kubernetes 中的 Jenkins 控制器設定

    在此設定中,我們將 Jenkins 控制器和代理部署在同一個 Kubernetes 集群中。

    我們將在 Kubernetes 集群上設定 Jenkins 控制器伺服器。

    註意:如果你有現有設定,也可以使用該設定。確保它有一個服務帳戶,該帳戶有權在部署 Jenkins 的名稱空間中部署 Pod。

    將以下清單另存為 .此清單包含永續性卷、部署和服務定義。deployment.yaml

    註意:確保你的 Kubernetes 集群設定支持永續性卷。如果你在沒有持久卷的情況下部署 Jenkins,則每次重新開機或刪除 Pod 時都會遺失 Jenkins 數據。

    # 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 使用者。

    如果你有任何疑問,請關註 Kubernetes 上的 Jenkins 部落格。

    Jenkins Kubernetes 外掛程式配置

    需要 Jenkins Kubernetes 外掛程式才能設定基於 Kubernetes 的構建代理。讓我們配置外掛程式。

    第 1 步:安裝 Jenkins Kubernetes 外掛程式 轉到 –> ,在可用索引標籤中搜尋 Kubernetes 外掛程式,然後安裝它。以下 Gif 視訊顯示了外掛程式安裝過程。Manage Jenkins Manage Plugins

    步驟2:建立 Kubernetes 雲配置 安裝後,轉到 –> Manage JenkinsClouds

    單擊 New Cloud

    命名並選擇 Kubernetes。

    建立 Jenkins 雲 單擊 Create 並繼續下一步

    第 3 步:配置 Jenkins Kubernetes Cloud 這裏我們有兩個場景。

  • 在同一 Kubernetes 集群中執行的 Jenkins 伺服器

  • Jenkins 伺服器在 Kubernetes 集群外部執行。讓我們看看這兩種情況的配置。

  • 在同一 Kubernetes 集群中執行的 Jenkins 伺服器

    由於我們在 Kubernetes 集群中有 Jenkins,並且有一個服務帳戶來部署代理 Pod,因此我們不必提及 Kubernetes URL 或證書金鑰。

    但是,要使用服務帳戶驗證連線,請使用 Test Connection (測試連線) 按鈕,如下所示。如果 Jenkins Pod 可以連線到 Kubernetes API Server,它應該會顯示一條 connected 訊息。

    在 Kubernetes 集群外部執行的 Jenkins 伺服器

    如果你的 Jenkins 伺服器在 Kubernetes 集群外部執行,則需要指定以下內容。

  • Kubernetes 網址:這是 Kubernetes API 伺服器終端節點。如果啟用了 https,請使用 https URL。

  • Kubernetes (簡體中文)伺服器證書金鑰:如果你有 Kubernetes 集群 CA 證書,則可以添加該證書以實作安全連線。你可以從 pod 位置獲取證書。如果你沒有證書,則可以啟用 「」 選項。/var/run/secrets/kubernetes.io/serviceaccount/ca.crtdisable https certificate check

  • 憑據:為了讓 Jenkins 與 Kubernetes 集群通訊,我們需要一個有權在名稱空間中部署 Pod 的服務帳戶令牌。devops-tools

  • 我們已經建立了服務帳戶並為名稱空間分配了一個 secret 令牌。我們需要從 secret 中獲取 token。devops-tools

    執行以下命令以從服務帳戶中檢索金鑰名稱。

    kubectl get secret sa-token-secret -n devops-tools -o jsonpath='{.data.token}' | base64 --decode

    現在單擊 credentials 下的按鈕並建立憑證型別 「」。在金鑰框中輸入服務帳戶令牌並添加其他詳細資訊,如下所示。最後,保存憑證。AddSecret text

    Kubernetes 雲配置將如下所示。

    填寫所有詳細資訊後,你可以測試連線以驗證 Kubernetes 集群連線。

    第 4 步:配置 Jenkins URL 詳細資訊 對於在集群內執行的 Jenkins Controller,你可以使用 Kubernetes 集群的服務終端節點作為 Jenkins URL,因為代理 Pod 可以透過內部服務 DNS 連線到集群。

    URL 是使用以下語法衍生的。

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

    在我們的例子中,服務 DNS 將是

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

    此外,添加 POD 標簽,該標簽可用於對可用於計費或自訂構建控制台的容器進行分組。

    註意:如果 Jenkins 控制器位於 Kubernetes 集群之外,請在 Jenkins URL 配置中使用 Jenkins IP 或 DNS。

    第 5 步:建立 POD 和容器樣版 接下來,你必須添加包含詳細資訊的 POD 樣版,如下圖所示。標簽 kubeagent 將用作識別元,以選擇此 pod 作為構建代理。接下來,我們必須添加包含 Docker 映像詳細資訊的容器樣版。

    下一個配置是容器樣版。如果你不添加容器樣版,Jenkins Kubernetes 外掛程式將使用 Docker Hub 中的預設 JNLP 映像來啟動代理。即 jenkins/inbound-agent

    如果你在公司網路上並且無法存取 Docker Hub,則必須構建自己的映像,並使用如下所示的相同名稱覆蓋預設映像,假設是自訂 jnlp 映像。jnlpjenkins/inbound-agent:latest

    確保從容器樣版中刪除 and default 參數。sleep9999999

    我們可以將多個容器樣版添加到 POD 樣版中,並在管道中使用它們。我已經在下一節中透過範例解釋了這一點。Jenkinsfile

    這是代理工作所需的基本最低配置。在管道範例的後面部份,我將解釋卷和其他選項的一些使用案例。

    現在保存所有配置,讓我們測試一下是否可以使用 Pod 代理構建作業。

    步驟6:轉到 Jenkins 主頁 – > New Item 並建立一個 free style 計畫。

    在任務描述中,添加標簽 kubeagent,如下所示。這是我們分配給 Pod 樣版的標簽。這樣,Jenkins 就知道要為代理容器使用哪個 Pod 樣版。

    使用 Kubernetes Jenkins 外掛程式驗證 Docker 代理構建 添加帶有 echo 命令的 shell 構建步驟以驗證作業,如下所示。

    現在,保存作業配置並單擊 「Build Now」

    你應該會在下面的作業構建歷史記錄中看到一個待處理的代理。

    你將在幾分鐘內看到成功的構建。如果檢查日誌,將顯示執行的 shell。

    帶有 Pod 樣版的 Jenkinsfile

    到目前為止,我們所看到的都是理解和驗證 Kubernetes Jenkins 外掛程式設定。

    當涉及到實際的計畫管道時,最好將 POD 樣版放在Jenkinsfile

    以下是你應該了解的有關 POD 樣版的資訊。

  • 預設情況下,該外掛程式使用 JNLP 容器映像連線到 Jenkins 伺服器。你可以使用自訂 JNLP 映像進行覆蓋,前提是你在容器樣版中提供名稱。jnlp

  • 你可以在單個 Pod 樣版中包含多個容器樣版。然後,每個容器都可以在不同的管道階段使用。

  • POD_LABEL將在觸發 build 時為 pod 分配一個隨機的 build 標簽。你不能給出任何其他名稱,只能POD_LABEL

  • 以下是 POD 樣版的範例。Jenkinsfile

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

    在管道作業中構建上述 Jenkinsfile 將使用預設的 JNLP 映像,並執行「Run Shell」階段的命令。當我說 default 時,如果你未指定任何 JNLP 映像,外掛程式將使用來自 docker hub 的 JNLP 映像。

    現在,你可以透過 containerTemplate 和所有必要的構建工具使用自己的 jnlp 映像,並在管道中使用它們,如下所示。

    在這裏,你將擁有自己的影像,而不是 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 樣版

    你可以在單個 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"
    '
    ''
    }
    }
    }
    }
    }

    你可以嘗試使用 pipeline job 構建上述 Jenkinsfile。

    在構建上述管道時,如果檢查 Kubernetes Pod,你將在構建代理 Pod 中看到三個容器,如下所示。

    註意:由於實際計畫中的安全合規性問題,你不能直接使用 Docker Hub 映像。因此,你必須構建自己的 Docker 映像,並將其托管在組織批準的容器登錄檔中。

    將共享持久卷與 Jenkins Docker 代理 Pod 結合使用

    最好將共享的持久卷附加到構建容器,以加快構建過程。

    例如,如果你以 Java 應用程式為例,它具有許多 Maven 包依賴項。

    當你構建 Java 應用程式時,它會首次從遠端 maven 儲存庫下載pom.xml中添加的依賴項,並建立一個本地 .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

    以下是使用持久卷的 POD 樣版的範例。Jenkinsfilemaven-repo-storage

    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 部署應用程式,則可以將 CI Docker 構建管道與 Kubernetes 代理整合。

    有幾種方法可以在 Docker 上執行 Docker 以用於構建用例。但是,由於 Kubernetes 刪除了 Docker 執行時,因此最好使用替代解決方案。

    目前,在 Kubernetes 集群上構建 docker 映像的最佳方法是使用 Kaniko

    請參閱使用 kaniko 構建 docker 映像,了解有關使用 Jenkins 管道構建 kaniko 構建管道的更多資訊。

    結論

    如果你正在使用Jenkins和Kubernetes,你絕對應該嘗試一下基於容器的代理。

    在 Kubernetes 上擴充套件 Jenkins 代理有助於避免與靜態構建 VM 相關的管理開銷。即使動態 VM 構建選項可用,與動態容器代理相比,每次構建也可能需要很長時間。

    你不必擔心 Jenkins 構建的資源會用完。