一、部署jenkins
pv/pvc
touch pv_jenkins.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs-jenkins
nfs:
path: /data/jenkins/
server: 10.61.150.21
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-jenkins
namespace: servers
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: nfs-jenkins
創建jenkins的serviceaccount
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: jenkins
name: service-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["services"]
verbs: ["get", "watch", "list"]
- 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"]
#在jenkins命名空間下創建一個服務賬號jenkins
#kubectl create serviceaccount jenkins -n jenkins -o yaml
kubectl create serviceaccount jenkins -n servers
#創建一個名為“service-reader-pod”的集群角色綁定,它的“clusterrole”是“service-reader”,它的名字是“default:default”,其中第一個“default”是名空間(namespace),第二個“default”是服務賬戶名字
kubectl create clusterrolebinding service-reader-pod --clusterrole=service-reader --serviceaccount=servers:jenkins
修改jenkins鏡像
注意:
- 創建dockerfile,使用root權限,否則會報錯無權限
- 最新的jenkins版本是jenkins/jenkins 別用錯
FROM hub.ict.ac.cn/jenkins/jenkins:latest
USER root
svr
apiVersion: v1
kind: Service
metadata:
name: k8sdemo-jenkins-service
namespace: servers
labels:
app: k8sdemo-jenkins
spec:
type: NodePort
selector:
app: k8sdemo-jenkins
ports:
- port: 8080
name: http
protocol : TCP
nodePort: 30080
targetPort: 8080
- port: 50000
name: agent
protocol: TCP
targetPort: 50000
訪問
可以用“http://IP:30080/” 訪問Jenkins。

配置插件安裝代理
方案1.配置插件代理

升級站點的地址改為:
這個 URL 改成
http://mirror.xmission.com/jenkins/updates/update-center.json 或
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
方案2.使用反向代理連接網絡:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
方案3.下載插件后離線安裝:http://updates.jenkins-ci.org/download/plugins/
需要下載插件列表:
| 插件名 | 功能 |
|---|---|
| docker | docker |
| Localization: Chinese | 漢化 |
| thinbackup | 備份 |
| Kubernetes | K8S插件 |
| Blue Ocean | 新款UI |
二、配置Kubernetes Plugin

-
name使用默認的'Kubernetes'就可以,配置Pipelines時會用到。
-
Kubernetes URL,是要K8S集群的地址,我們的jenkins在K8S集群里部署的,所以直接用 “https://kubernetes.default” 就可以了。設置之后點擊“Test Connection”,見到“
Connected to Kubernetes 1.16”就成功了。

-
Jenkins URL就是Jenkins的訪問地址,用http://jenkins.default就可以了。可能是沒在jenkins上設置的緣故,這個地址集群沒有解析成功,導致在測試節點的時候JNLP一直ERROR。我修改成jenkins的訪問地址就可以了(就是打開jenkins界面的地址別想多了,有反向代理的就填VIP)


- Jenkins tunnel”,這個參數是Jenkins Master和Jenkins Slave之間通信必須配置的。很多文章都沒有說要配這個,但是很明確的告訴你,不配置不行(我把這個寫上,絕對良心帖)地址也很簡單,使用你jenkins的service的集群地址+50000就可以了。


三、測試
有幾個需要說明的地方:
- pipeline有兩種語法大家都是知道的,所以呢在K8S插件使用上也支持兩種語法的設置。具體的格式參照K8S插件的官方
- 新版的K8S插件不需要設置label,jenkins會自動生成一個,節點使用POD_LABEL環境變量引用就可以了。
- 在pipeline中先定義podTemplate,在podTemplate中定義containerTemplate,分別有很多可設置的參數,也參照官方設定(用於腳本式)。以下例子中由於我的集群大部分服務器是離線的,為了下載鏡像方便使用nodeSelector把節點固定調度到一個可連網的K8S-NODE上。
測試master
podTemplate(nodeSelector: 'kubernetes.io/hostname=ict-94',cloud: "kubernetes"){
node(POD_LABEL){
stage('Run shell'){
sh 'echo hello world'
}
}
}

測試節點
這個測試節點的自動創建、銷毀、伸縮、分組。是我們最主要的目標
腳本式pipeline編寫
#maven-jlnp:latest是我自己制作的鏡像,下一節會說怎么制作。
podTemplate(nodeSelector: 'kubernetes.io/hostname=ict-94',cloud: 'kubernetes',containers: [
containerTemplate(
name: 'jnlp',
image: 'hub.ict.ac.cn/jenkins/maven-jlnp:latest',
alwaysPullImage: false,
args: '${computer.jnlpmac} ${computer.name}'),
]) {
node(POD_LABEL) {
stage('stage1') {
stage('Show Maven version') {
sh 'mvn -version'
sh 'sleep 60s'
}
}
}
}

聲明式pipeline編寫
#yaml對POD的定義和K8S的一樣,例如imagePullPolicy
#在使用自定義鏡像的時候,name只能使用jnlp。這個有待考證
pipeline {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
metadata:
labels:
agent: test
spec:
containers:
- name: jnlp
image: hub.ict.ac.cn/jenkins/maven-jlnp:latest
imagePullPolicy: IfNotPresent
tty: true
"""
}
}
stages {
stage('Run maven') {
steps {
container('jnlp') {
sh 'mvn -version'
}
}
}
}
}
測試群組
- 查看pod可以發現同時運行了包括jnlp在內的3個pod
- 也就是說一個任務如果需要分別編譯前端的代碼和后端的代碼的時候,就可以分別使用兩個容器編譯
podTemplate(nodeSelector: 'kubernetes.io/hostname=ict-94',containers: [
containerTemplate(name: 'maven', image: 'maven:3.3.9-jdk-8-alpine', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'golang', image: 'golang:1.8.0', ttyEnabled: true, command: 'cat')
]) {
node(POD_LABEL) {
stage('Get a Maven project') {
git 'https://github.com/jenkinsci/kubernetes-plugin.git'
container('maven') {
stage('Build a Maven project') {
sh 'mvn -B clean install'
}
}
}
stage('Get a Golang project') {
git url: 'https://github.com/hashicorp/terraform.git'
container('golang') {
stage('Build a Go project') {
sh """
mkdir -p /go/src/github.com/hashicorp
ln -s `pwd` /go/src/github.com/hashicorp/terraform
cd /go/src/github.com/hashicorp/terraform && make core-dev
"""
}
}
}
}
}
pipeline {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
metadata:
labels:
some-label: some-label-value
spec:
containers:
- name: maven
image: maven:alpine
command:
- cat
tty: true
- name: busybox
image: busybox
command:
- cat
tty: true
"""
}
}
stages {
stage('Run maven') {
steps {
container('maven') {
sh 'mvn -version'
}
container('busybox') {
sh '/bin/busybox'
}
}
}
}
}
在jenkins中配置podTemplate
如果我們使用非Pipeline的方式運行任務, 比如自由風格的,就需要在K8S插件下繼續配置POD模板。
- Labels 配置pod的標簽,在新建任務的時候會調用
- Name 指定運行pod的名稱,要注意的是,如果 Name 配置為 jnlp,那么 Kubernetes 會用下邊指定的 Docker Image 代替默認的 jenkinsci/jnlp-slave 鏡像,否則,Kubernetes plugin 還是會用默認的 jenkinsci/jnlp-sla ve 鏡像與 Jenkins Server 建立連接,即使我們指定其他 Docker Image。這里我隨便配置為 jnlp-slave,意思就是使用默認的 jenkinsci/jnlp-slave 鏡像來運行,因為我們暫時還沒制作可以替代默認鏡像的鏡像。
“系統管理” —> “系統設置” —> “雲” —> “Kubernetes” —> “Add Pod Template”

新建一個自由風格的任務
指定label,需要和上述配置pod模板的label一致,和k8S的節點沒有關系。我這里的label值就是一個k8s節點的label,測試和K8S節點無關,需要和上述的label一致。

構建

輸出

四、制作自己的slave節點
通過 kubernetest plugin 默認提供的鏡像 jenkinsci/jnlp-slave 可以完成一些基本的操作,它是基於 openjdk:8-jdk 鏡像來擴展的,但是對於我們來說這個鏡像功能過於簡單,比如我們想執行 Maven 編譯或者其他命令時,就有問題了,那么可以通過制作自己的鏡像來預安裝一些軟件,既能實現 jenkins-slave 功能,又可以完成自己個性化需求,那就比較不錯了。如果我們從頭開始制作鏡像的話,會稍微麻煩些,不過可以參考 jenkinsci/jnlp-slave 和 jenkinsci/docker-slave 這兩個官方鏡像來做,注意:jenkinsci/jnlp-slave 鏡像是基於 jenkinsci/docker-slave 來做的。這里我簡單演示下,基於 jenkinsci/jnlp-slave:latest 鏡像,在其基礎上做擴展,安裝 Maven 到鏡像內,然后運行驗證是否可行吧。
maven
#制作鏡像
FROM jenkins/jnlp-slave:latest
MAINTAINER huwanyang168@163.com
LABEL Description="This is a extend image base from jenkins/jnlp-slave which install maven in it."
# 切換到 root 賬戶進行操作
USER root
# 安裝 maven-3.3.9
RUN wget http://mirrors.sonic.net/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz && \
tar -zxf apache-maven-3.3.9-bin.tar.gz && \
mv apache-maven-3.3.9 /usr/local && \
rm -f apache-maven-3.3.9-bin.tar.gz && \
ln -s /usr/local/apache-maven-3.3.9/bin/mvn /usr/bin/mvn && \
ln -s /usr/local/apache-maven-3.3.9 /usr/local/apache-maven
USER jenkins
~~~
`docker build -t maven-jlnp:latest .`
kubectl create secret docker-registry secret-harbor --namespace=my-docs
--docker-server=http://harbor.shanhy.com:81 --docker-username=admin
--docker-password=harbor123456789
測試
def label = "mypod-${UUID.randomUUID().toString()}"
podTemplate(label: label, cloud: 'kubernetes',containers: [
containerTemplate(
name: 'jnlp',
image: 'hub.ict.ac.cn/jenkins/maven-jlnp:latest',
alwaysPullImage: false,
args: '${computer.jnlpmac} ${computer.name}'),
]) {
node(label) {
stage('stage1') {
stage('Show Maven version') {
sh 'mvn -version'
sh 'sleep 60s'
}
}
}
}
npm
#dockerfile
FROM jenkins/jnlp-slave:latest
USER root
RUN wget https://nodejs.org/dist/v12.18.4/node-v12.18.4-linux-x64.tar.gz && \
tar -zxvf node-v12.18.4-linux-x64.tar.gz && \
mv node-v12.18.4-linux-x64 nodejs && \
rm -f apache-maven-3.3.9-bin.tar.gz && \
ln -s /home/jenkins/nodejs/bin/npm /usr/bin/npm && \
ln -s /home/jenkins/nodejs/bin/node /usr/bin/node
USER jenkins
#pipeline
pipeline {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
metadata:
labels:
agent: jlnp_npm
spec:
containers:
- name: jnlp
image: hub.ict.ac.cn/jenkins/jlnp-nmp:v1
imagePullPolicy: IfNotPresent
imagePullSecrets:
- name: harbor31
tty: true
"""
}
}
stages {
stage('Run npm') {
steps {
container('jnlp') {
sh 'npm -v'
}
}
}
}
}
參考文章:
https://blog.csdn.net/aixiaoyang168/article/details/79767649
https://plugins.jenkins.io/kubernetes/
https://www.cnblogs.com/shawhe/p/11313633.html
https://blog.csdn.net/weixin_38748858/article/details/102898043
http://updates.jenkins-ci.org/download/plugins/
