手把手教你用 Jenkins + K8S 打造流水線環(huán)境

朋友的真實操作流程,使用 Jenkins 和 Kubernetes 完成持續(xù)集成和持續(xù)部署,有搭建,有入門,手把手教學文檔,干得擰不出水來,分享一波。

本文作者:孫丹丹,,單身 ,DevOps 運維工程師,CKA 認證。就職于某容器云平臺服務公司,負責國內多家知名企業(yè) DevOps 運維交付。

安裝 Jenkins

啟動 Jenkins 容器

docker run -d -u root -v /workspace/jenkins-home/var/jenkins_home  -v /var/run/docker.sock:/var/run/docker.sock -v "$HOME":/home -p 8080:8080 -p 50000:50000 jenkinsci/blueocean
參數(shù) 說明
-d d 指 daemon,后臺啟動
-u 指定運行用戶
-v -v /workspace/jenkins-home:/var/jenkins_home
hostDir:containerDir
表示將容器中 jenkins_home 映射到宿主機 jenkins-home 目錄
-p -p 8080:8080
hostPort:containerPort

檢查 Jenkins 服務狀態(tài)

docker ps | grep jenkins

啟動成功后,就可以通過 ip:port 在瀏覽器上訪問了。ip 為 docker 所在機器的 ip, port 為 Jenkins 容器映射的宿主機端口。

配置 Jenkins

Jenkins 啟動成功后,需要執(zhí)行一些快速的 "一次性" 步驟。當你第一次訪問一個新的 Jenkins 實例時, 要求你使用自動生成的密碼對其進行解鎖。密碼為 Jenkins 所在容器的 /var/jenkins_home/secrets/initialAdminPassword 的內容:

docker exec -it <jenkins_container> bash -c "cat /var/jenkins_home/secrets/initialAdminPassword"

或者用 K8S 命令 kubectl

kubectl exec -it <jenkins_container> bash -c "cat /var/jenkins_home/secrets/initialAdminPassword"

在 Unlock Jenkins 頁面, 粘貼該密碼到 Administrator password 字段并點擊 Continue。解鎖 Jenkins 后,插件安裝頁面出現(xiàn),點擊 Install suggested plugins 即可。

這個過程會耗時一段時間。

創(chuàng)建第一個管理員用戶,可以填寫,也可以跳過,直接使用 admin 賬戶繼續(xù)。

這邊我選擇了跳過,點擊開始使用 Jenkins,就可以使用 Jenkins 了。

實現(xiàn) Java 應用持續(xù)集成和持續(xù)發(fā)布

Fork 和 Clone GitHub 示例倉庫

  1. 登錄 GitHub 賬號:https://github.com
  2. 上傳代碼到 GitHub 代碼倉庫中,或 Fork 到你的 GitHub 倉庫中,演示代碼 prometheus-test-demo,地址為 https://github.com/0820sdd/prometheus-test-demo
  3. 將你的 GitHub 賬戶中的 prometheus-test-demo 倉庫 Clone 到本地機器:
    a. 打開一個終端/命令提示符,并且進入正確的目錄路徑: Mac OS 系統(tǒng)路徑為 /Users/<your-username>/Documents/GitHub/ Linux 系統(tǒng)路徑為/home/<your-username>/GitHub/ Windows 系統(tǒng)路徑為 C:\Users\<your-username>\Documents\GitHub\ (推薦使用 Git bash 命令行,而不是通常的 Microsoft 命令提示符)
    b. 運行以下命令完成倉庫的 clone:git clone https://github.com/YOUR-GITHUB-ACCOUNT-NAME/simple-java-maven-app 其中 YOUR-GITHUB-ACCOUNT-NAME 是你的 GitHub 賬戶的名稱。

在 Jenkins 中創(chuàng)建流水線

登錄 Jenkins,點擊頁面創(chuàng)建一個新任務。若是你無法看見該內容,點擊左上方的新建 item。

為新建的流水線項目指定名稱(例如 prometheus-test-demo),選擇流水線,點擊確定。

安裝 K8S 插件

登錄 Jenkins,系統(tǒng)管理→ 插件管理 → 搜索 kubernetes,選擇第二個 Kubernetes,點擊 安裝,安裝完成后重啟 Jenkins 。

對接 K8S 集群

申請 K8S 憑據(jù)

因為 Jenkins 服務器在 kubernetes 集群之外,所以我們準備以下文件才能從外面連接到 kubernetes 集群。

登錄 Jenkins,點擊右上角「用戶」 → 左下角「憑據(jù)」:

然后點擊 Jenkins,選擇全局憑據(jù)(Unrestricted)

添加憑據(jù),類型選擇 X.509 Client Certificate

  • Client Key: .kube/config文件中 client-key 對應的 key 文件
  • Client Certificate: .kube/config文件中 client-certificate 對應的 crt 或是 pem 文件
  • Server CA Certificate:.kube/config 文件中 certificate-authority 對應的 crt 或是 pem 文件,K8S 的最高權限證書
  • ID:可不填寫,默認會自動生成一串字符串,也可以自行設置
  • 描述:描述下這個憑據(jù)的作用,比如這個可以寫 對接 K8S 集群憑據(jù)

填寫完畢,點擊確定。

配置 K8S 集群的對接

登錄 Jenkins,點擊 系統(tǒng)管理 → 系統(tǒng)配置 → 滑動到頁面最下面

點擊 a separate configuration page:

  • Kubernetes 地址:kubernetes服務地址,也就是 apiserver 的地址,一般是master 節(jié)點 NodeIP+6443 端口
  • Kubernetes 服務證書 key:kube-ca.crt 文件的內容
  • 憑據(jù):剛才創(chuàng)建的 certificate 憑據(jù)
  • Jenkins 地址:Agent 連接 Jenkins Master 的地址

其他都使用默認配置,點擊連接測試,連接測試成功,點擊 Save 存儲。

K8S pod template 配置

Jenkins 的 kubernetes-plugin 在執(zhí)行構建時會在 kubernetes 集群中自動創(chuàng)建一個 Pod,并在 Pod 內部創(chuàng)建一個名為 jnlp 的容器,該容器會連接 Jenkins 并運行 Agent 程序,形成一個 Jenkins 的 Master 和 Slave 架構,然后 Slave 會執(zhí)行構建腳本進行構建,但如果構建內容是要創(chuàng)建 Docker Image 就要實現(xiàn) Docker In Docker 方案(在 Docker 里運行 Docker),如果要在集群集群內部進行部署操作可以使用 kubectl 執(zhí)行命令,要解決 kubectl 的安裝和權限分配問題。

為了方便配置一個 Pod Templates,在配置 kubernetes 連接內容的下面,這里的模板只是模板(與類一樣使用時還要實例化過程),名稱和標簽列表不要以為是 Pod 的 name 和 label,這里的名稱和標簽列表只是 Jenkins 查找選擇模板時使用的,Jenkins 自動創(chuàng)建 Pod 的 name 是項目名稱+隨機字母的組合,所以我們填寫 jenkins-slave,命名空間填寫對應的 namespace。

這邊要注意,添加 2 個 container,第一個,Pod 內添加一個容器名稱是 jnlp,Docker 鏡像填寫:jenkins/jnlp-slave:4.3-7,后面的使用默認的即可,然后在添加一個 container,容器名稱是 jnlp-kubectl,是這個容器里面有 kubectl 的命令,鏡像名稱填寫 harbor.edu.cn/library/centos-docker-kubectl:v1.0,下面增加了 Host Path Volume:/var/run/docker.sock、/root/.kube/、/etc/kubernetes/pki,這邊便是為了 jenkins-slave 下有足夠的權限可以執(zhí)行 docker 及 kubectl 部署到 k8s 集群的權限,因為 jenkins-slave pod 有可能會被調度到任一 worker 節(jié)點,所以所有的 worker 節(jié)點上都必須有 /root/.kube/、/etc/kubernetes/pki,配置好之后點擊保存。

Jenkins pipeline 說明

Pipeline,簡單來說,就是一套運行在 Jenkins 上的工作流框架,將原來獨立運行于單個或者多個節(jié)點的任務連接起來,實現(xiàn)單個任務難以完成的復雜流程編排和可視化的工作。

Jenkins Pipeline 有幾個核心概念:

  • Node:節(jié)點,一個 Node 就是一個 Jenkins 節(jié)點,Master 或者 Agent,是執(zhí)行 Step 的具體運行環(huán)境,比如我們之前動態(tài)運行的 Jenkins Slave 就是一個 Node 節(jié)點
  • Stage:階段,一個 Pipeline 可以劃分為若干個 Stage,每個 Stage 代表一組操作,比如:Build、Test、Deploy,Stage 是一個邏輯分組的概念,可以跨多個 Node
  • Step:步驟,Step 是最基本的操作單元,可以是打印一句話,也可以是構建一個 Docker 鏡像,由各類 Jenkins 插件提供,比如命令:sh 'make',就相當于我們平時 shell 終端中執(zhí)行 make 命令一樣。

Pipeline的使用:

  • Pipeline 腳本是由 Groovy 語言實現(xiàn)的
  • Pipeline 支持兩種語法:Declarative(聲明式)和 Scripted Pipeline(腳本式)語法
  • Pipeline 也有兩種創(chuàng)建方法:可以直接在 Jenkins 的 Web UI 界面中輸入腳本;也可以通過創(chuàng)建一個 Jenkinsfile 腳本文件放入項目源碼庫中
  • 一般我們都推薦在 Jenkins 中直接從源代碼控制(SCMD)中直接載入 Jenkinsfile Pipeline 這種方法,但是本次為了更直觀的展示,我們在 Web UI 界面中輸入腳本

Jenkins pipeline 入門

創(chuàng)建并運行 pipeline
  • 進入到 Jenkins 首頁,點擊項目 prometheus-test-demo,點擊左側 配置
  • 點擊頁面頂部的 Pipeline 選項卡,向下滾動到 Pipeline 部分
  • 定義 域中,選擇 Pipeline script 選項
node {
  stage('Clone') {
    echo "1.Clone Stage"
  }
  stage('Test') {
    echo "2.Test Stage"
  }
  stage('Build') {
    echo "3.Build Stage"
  }
  stage('Deploy') {
    echo "4. Deploy Stage"
  }
}

點擊保存,切換到 Jenkins 頁面,點擊左側的 打開 Blue Ocean 進入Jenkins的Blue Ocean界面,進入到 相應的項目下,點擊 運行 。

也可以在 Jenkins prometheus-test-demo 項目下,點擊左側菜單 立即構建,然后點擊正在構建的任務,就可以看到 Console Output:

在 Slave 中運行 Pipeline

上面對 Jenkins 的 Pipeline 做了簡單的測試,但是其并未在我們的 Slave中運行,如果要在 Slave 中運行,其就要使用我們在對接 K8S 集群時 Pod Template 指定的標簽列表 ,點擊進 prometheus-test-demo 項目,點擊左側菜單 配置,進入到 pipeline scripts 部分,修改 pipeline scripts 如下:

node('slave') {
  stage('Clone') {
    echo "1.Clone Stage"
  }
  stage('Test') {
    echo "2.Test Stage"
  }
  stage('Build') {
    echo "3.Build Stage"
  }
  stage('Deploy') {
    echo "4. Deploy Stage"
  }
}

點擊 立即構建,同時可以登錄到k8s集群,使用 kubectl get po -w 可以看到 jenkins-slave pod 的生命周期,就是我們開始構建這個任務,選擇了使用 jenkins slave,所以在執(zhí)行過程中jenkins-slave就會自動創(chuàng)建,任務執(zhí)行完成,jenkins-slave 對應的pod會自動回收:

在構建日志里我們也可以看到 jenkins 啟動了 jenkins-slave-dj3vc pod 進行這個任務的執(zhí)行,也和上面的 pod 名稱對應起來了。

完整 pipeline 示例

部署應用的流程如下:

  • 拉取 Github 代碼
  • maven 打包
  • 編寫 Dockerfile
  • 構建打包 Docker 鏡像
  • 推送 Docker 鏡像到倉庫
  • 編寫 Kubernetes YAML 文件
  • 更改 YAML 文件中 Docker 鏡像 TAG
  • 利用 kubectl 工具部署應用

最終的 Pipeline 腳本如下:

pipeline {
    agent none
    stages {
        stage('Clone Code') {
            agent {
                label 'master'
            }
            steps {
                echo "1.Git Clone Code"
                git url: "https://github.com/0820sdd/prometheus-test-demo.git"
            }
        }
        stage('Maven Build') {
            agent {
                docker {
                    image 'maven:latest'
                    args '-v /root/.m2:/root/.m2'
                }
            }
            steps {
                echo "2.Maven Build Stage"
                sh 'mvn -B clean package -Dmaven.test.skip=true'
            }
        }
        stage('Image Build') {
            agent {
                label 'master'
            }
            steps {
            echo "3.Image Build Stage"
            sh 'docker build -f Dockerfile --build-arg jar_name=target/prometheus-test-demo-0.0.1-SNAPSHOT.jar -t prometheus-test-demo:${BUILD_ID} . '
            sh 'docker tag  prometheus-test-demo:${BUILD_ID}  harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}'
            }
        }
        stage('Push') {
            agent {
                label 'master'
            }
            steps {
            echo "4.Push Docker Image Stage"
            sh "docker login --username=admin harbor.edu.cn -p Harbor12345"
            sh "docker push harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}"
            }
        }
    }
}
 
node('slave') {
    container('jnlp-kubectl') {
        
        stage('Clone YAML') {
        echo "5. Git Clone YAML To Slave"
        git url: "https://github.com/0820sdd/prometheus-test-demo.git"
        }
        
        stage('YAML') {
        echo "6. Change YAML File Stage"
        sh 'sed -i "s#{VERSION}#${BUILD_ID}#g" ./jenkins/scripts/prometheus-test-demo.yaml'
        }
    
        stage('Deploy') {
        echo "7. Deploy To K8s Stage"
        sh 'kubectl apply -f ./jenkins/scripts/prometheus-test-demo.yaml'
        }
    }
}

注意,prometheus-test-demo.yaml 可放在 GitHub 的 prometheus-test-demo 倉庫里,也可以另外新建一個倉庫專門放 YAML 文件。

下面我們分解講下上面過程的具體含義:

克隆代碼
        stage('Clone to master') {
            agent {
                label 'master'
            }
            steps {
                echo "1.Git Clone Stage"
                git url: "https://github.com/0820sdd/prometheus-test-demo.git"
            }
        }

這步就是從 GitHub 上拉取代碼,注意這邊的 GitHub 倉庫倉庫比如是 公開的,因為 private 的需要各種權限配置,Jenkins 必須有一個公網(wǎng) IP 或者是公網(wǎng)域名,但因資源問題,這部分暫時沒有辦法實現(xiàn)。注意,這邊 agent 里面指定運行環(huán)境,選擇了 master,即是這個步驟在 Jenkins master節(jié)點執(zhí)行。

maven 打包
        stage('Maven Build') {
            agent {
                docker {
                    image 'maven:latest'
                    args '-v /root/.m2:/root/.m2'
                }
            }
            steps {
                echo "2.Maven Build Stage"
                sh 'mvn -B clean package -Dmaven.test.skip=true'
            }
        }

maven 構建,我們指定了 maven 打包的 agent 是在 Jenkins 所在節(jié)點另起一個 docker 容器,容器的 image 為 maven:latest,并且使用 -v 參數(shù)把本地的 /root/.m2 掛載到 容器的 /root/.m2 目錄下,下面 steps 的步驟即是在這個 maven 容器里面的具體操作:mvn -B clean package -Dmaven.test.skip=true。

構建鏡像
        stage('Image Build') {
            agent {
                label 'master'
            }
            steps {
            echo "3.Image Build Stage"
            sh 'docker build -f Dockerfile --build-arg jar_name=target/prometheus-test-demo-0.0.1-SNAPSHOT.jar -t prometheus-test-demo:${BUILD_ID} . '
            sh 'docker tag  prometheus-test-demo:${BUILD_ID}  harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}'
            }
        }

maven 構建成功,下一步就是使用 maven build 生成的 prometheus-test-demo-0.0.1-SNAPSHOT.jar 包進行 docker build,docker build 的具體命令有2條 bash 命令 組成,第一步 docker build 使用 -f 指定了 Dockerfile 的文件,使用--build-arg 參數(shù)指定了一些參數(shù),比如上面指定了 jar_name 是 target/prometheus-test-demo-0.0.1-SNAPSHOT.jar,最后使用 -t 參數(shù)指定了 docker build 的 image 的名稱及版本號。第二步就是 使用 docker tag 命令把上一步 docker build 完成的鏡像 打 tag 為 harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID},這步打 tag 的步驟是為了上傳到 harbor 鏡像倉庫,可以隨時使用。

推送鏡像
        stage('Push') {
            agent {
                label 'master'
            }
            steps {
            echo "4.Push Docker Image Stage"
            sh "docker login --username=admin harbor.edu.cn -p Harbor12345"
            sh "docker push harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}"
            }
        }

鏡像 build 完成,就可以使用 docker push 命令推送到 harbor.edu.cn 鏡像倉庫。

拉取鏡像
 node('slave') {
    container('jnlp-kubectl') {
        
        stage('Clone YAML') {
        echo "5. Git Clone YAML To Slave"
        git url: "https://github.com/0820sdd/prometheus-test-demo.git"
        }
     }
  }

現(xiàn)在鏡像已經(jīng)打包完成,并推送到了鏡像倉庫,后面我們所要做的就是拉取 k8s 編排文件,這一步和第一步的 拉取代碼實際是一樣的,只不過上面的拉取代碼是為了 build image,這一步是為了進行部署到 K8S。
注意:這邊指定了運行此步驟的節(jié)點是在 Jenkins 的 slave 節(jié)點下的 jnlp-kubectl container 下,這個 slave 是指在配置 對接 K8S 集群時,在 Pod Template 下指定的 標簽列表的名稱,必須與這個名稱一致,不然 jenkins 執(zhí)行過程中就會報找不到對應的 label 。還有這邊指定了 jnlp-kubectl container ,這是因為 jnlp-kubectl container下有 kubectl 命令,且配置 對接 K8S 集群時,指定了把宿主機的 /root/.kube /etc/kubernetes/pki 目錄分別掛載到 container 的 /root/.kube /etc/kubernetes/pki目錄下,這邊就是 jnlp-kubectl container 可以訪問 K8S 集群的原因。

替換 YAML 文件變量
        stage('YAML') {
        echo "6. Change YAML File Stage"
        sh 'sed -i "s#{VERSION}#${BUILD_ID}#g" ./jenkins/scripts/prometheus-test-demo.yaml'
        }

yaml文件拉取完畢,替換其中的變量。

部署
        stage('Deploy') {
            echo "5. Deploy To K8s Stage"
            sh 'kubectl apply -f ./jenkins/scripts/prometheus-test-demo.yaml -n default'
        }

使用 kubectl 命令部署 prometheus-test-demo 應用到 K8S 集群。

最終執(zhí)行效果如下:
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容