在 k8s中使用Jenkins构建发布项目
Jenkins官方安装参考。
Jenkins官方安装参考
https://www.jenkins.io/doc/book/installing/kubernetes/
安装Jenkins
编写资源清单文件
jekins.yaml
# 创建命名空间
apiVersion: v1
kind: Namespace
metadata:
name: jenkins
---
# 创建pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pv
namespace: jenkins
spec:
capacity:
storage: 10Gi
# 卷的访问模式
accessModes:
# ReadWritteMany 多个节点可以同时读写
- ReadWriteMany
nfs:
path: /data/jenkins
server: 198.19.249.80
---
# 创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
namespace: jenkins
spec:
resources:
requests:
storage: 10Gi
accessModes:
- ReadWriteMany
---
# 创建sa
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-sa
namespace: jenkins
---
# 创建clusterRoleBingding 将 cluster-admin 绑定sa
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jenkins-clusterrolebinding
namespace: jenkins
subjects:
- kind: ServiceAccount
name: jenkins-sa
namespace: jenkins
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
---
# 创建service 提供外部访问
apiVersion: v1
kind: Service
metadata:
name: jenkins-service
namespace: jenkins
spec:
# 标签选择器,选择具有相同标签的pod
selector:
app: jenkins-pod
type: NodePort
ports:
# 内部暴露的端口
- port: 8080
# 要绑定的端口
targetPort: httpport
# 当 type=NodePort 或 LoadBalancer 时,公开此服务的每个节点上的端口
nodePort: 30080
# service端口名称
name: httpport
# 内部暴露的端口
- port: 50000
# 要绑定的端口
targetPort: jnlpport
# 当 type=NodePort 或 LoadBalancer 时,公开此服务的每个节点上的端口
nodePort: 30050
# service端口名称
name: jnlpport
---
# 创建jenkins deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins-deployment
namespace: jenkins
spec:
# 副本数
replicas: 1
selector:
# 选择器,管理具有相同标签的pod
matchLabels:
app: jenkins-pod
template:
metadata:
# 标签
labels:
app: jenkins-pod
spec:
# 服务账号
serviceAccount: jenkins-sa
# 容器
containers:
- name: jenkins
image: jenkins/jenkins:lts
imagePullPolicy: IfNotPresent
# 端口,需要暴露的端口,需要暴露 8080 与 50000
ports:
# 端口的名称
- name: httpport
# pod暴露的端口
containerPort: 8080
- name: jnlpport
containerPort: 50000
# 资源限额
resources:
# 最大资源限制
limits:
memory: "2Gi"
cpu: "1000m"
# 最小资源限制
requests:
memory: "500Mi"
cpu: "500m"
# 存活性探针
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:
# 卷的名称,与下方volumes的名称对应
- name: jenkins-volume
mountPath: /var/jenkins_home
# 定义卷的挂载列表
volumes:
- name: jenkins-volume
# 绑定PVC卷的管理
persistentVolumeClaim:
# PVC名称
claimName: jenkins-pvc
分段分析:
-
创建命名空间
创建名称为jenkins的命名空间,将所有的jenkins相关的都放到这个命名空间中
# 创建命名空间 apiVersion: v1 kind: Namespace metadata: name: jenkins
-
创建pv与pvc
创建PV绑定,绑定NFS网络存储,使用PVC管理PV
# 创建pv apiVersion: v1 kind: PersistentVolume metadata: name: jenkins-pv namespace: jenkins spec: capacity: storage: 10Gi # 卷的访问模式 accessModes: # ReadWritteMany 多个节点可以同时读写 - ReadWriteMany nfs: path: /data/jenkins server: 198.19.249.80 --- # 创建pvc apiVersion: v1 kind: PersistentVolumeClaim metadata: name: jenkins-pvc namespace: jenkins spec: resources: requests: storage: 10Gi accessModes: - ReadWriteMany
-
创建ServiceAccount,绑定cluster-admin
创建用于Jenkins pod容器中使用的SA账号,绑定管理员权限 cluster-admin
# 创建sa apiVersion: v1 kind: ServiceAccount metadata: name: jenkins-sa namespace: jenkins --- # 创建clusterRoleBingding 将 cluster-admin 绑定sa apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: jenkins-clusterrolebinding namespace: jenkins subjects: - kind: ServiceAccount name: jenkins-sa namespace: jenkins roleRef: kind: ClusterRole name: cluster-admin apiGroup: rbac.authorization.k8s.io
-
创建Service,代理Pod,提供外部访问
创建Service,代理Jenkins Pod,暴露对应端口号
# 创建service 提供外部访问 apiVersion: v1 kind: Service metadata: name: jenkins-service namespace: jenkins spec: # 标签选择器,选择具有相同标签的pod selector: app: jenkins-pod type: NodePort ports: # 内部暴露的端口 - port: 8080 # 要绑定的端口 targetPort: httpport # 当 type=NodePort 或 LoadBalancer 时,公开此服务的每个节点上的端口 nodePort: 30080 # service端口名称 name: httpport # 内部暴露的端口 - port: 50000 # 要绑定的端口 targetPort: jnlpport # 当 type=NodePort 或 LoadBalancer 时,公开此服务的每个节点上的端口 nodePort: 30050 # service端口名称 name: jnlpport
-
创建Deployment管理Pod
-
创建Deployment管理Pod,使用上方绑定管理员账号的SA
# 创建jenkins deployment apiVersion: apps/v1 kind: Deployment metadata: name: jenkins-deployment namespace: jenkins spec: # 副本数 replicas: 1 selector: # 选择器,管理具有相同标签的pod matchLabels: app: jenkins-pod template: metadata: # 标签 labels: app: jenkins-pod spec: # 服务账号 serviceAccount: jenkins-sa # 容器 containers: - name: jenkins image: jenkins/jenkins:lts imagePullPolicy: IfNotPresent # 端口,需要暴露的端口,需要暴露 8080 与 50000 ports: # 端口的名称 - name: httpport # pod暴露的端口 containerPort: 8080 - name: jnlpport containerPort: 50000 # 资源限额 resources: # 最大资源限制 limits: memory: "2Gi" cpu: "1000m" # 最小资源限制 requests: memory: "500Mi" cpu: "500m"
-
构建存活性探测与就绪性探测
# 存活性探针 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
-
创建存储卷,绑定PVC
# 挂载卷 volumeMounts: # 卷的名称,与下方volumes的名称对应 - name: jenkins-volume mountPath: /var/jenkins_home # 定义卷的挂载列表 volumes: - name: jenkins-volume # 绑定PVC卷的管理 persistentVolumeClaim: # PVC名称 claimName: jenkins-pvc
-
更新资源清单文件
kubectl apply -f jekins.yaml
查看资源部署情况
查看Pod
kubectl get pods -n jenkins
结果:
NAME READY STATUS RESTARTS AGE
jenkins-deployment-6f9788f748-sx8bm 1/1 Running 1 (51m ago) 15h
查看Service
kubectl get service -n jenkins
结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-service NodePort 10.100.143.208 <none> 8080:30080/TCP,50000:30370/TCP 15h
查看pvc与pv
pvc
kubectl get pvc -n jenkins
结果:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
jenkins-pvc Bound jenkins-pv 10Gi RWX <unset> 15h
pv
kubectl get pv -n jenkins
结果:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
jenkins-pv 10Gi RWX Retain Bound jenkins/jenkins-pvc <unset> 15h
网页访问Jenkins
http://<服务器ip>:30080
查看日志,获取密钥
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
2b0ad0adc63b410bb2762819816671f8
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************
https://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@github.com/630133069/k8s-test.git
安装k8s插件
配置Jenkins代理
添加云服务商
Dashboard-系统管理-Clouds
创建名称
连接k8s集群
-
查看k8s访问进群访问地址,因为Jenkins 部署在 k8s中,所以可以通过内部代理service进行访问
-
查看Service
kubectl get svc
结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 42d
-
完整的容器间访问地址就是:
https://kubernetes.default.svc.cluster.local
这里可以省略后缀
Kubernetes地址填写上方内部Service访问地址
配置Jenkins访问地址
因为代理内部需要访问Jenkins 所以需要配置Jenkins内部访问地址,地址是k8s中service代理的容期间访问地址
-
获取Jenkins访问地址
kubectl get svc -n jenkins
结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE jenkins-service NodePort 10.100.143.208 <none> 8080:30080/TCP,50000:30370/TCP 5d2h
-
完整的容器访问地址就是
http://jenkins-service.jenkins.svc.cluster.local:8080
完整的云服务商代理配置
配置Jenkins Pod模板
添加容器
配置容器基本参数
解释:
- 名称和标签列表 需要在后面声明的代理模板中使用
- 命名空间表明 Pod需要运行在那个命名空间
配置pod容器
此容器为代理空壳容器,表明这是一个 Jenkins的k8s代理
- 名称
jnlp
需要固定- 镜像
docker.io/jenkins/inbound-agent:jdk17
根据自己的项目使用- 删掉运行的命令与命令参数
- 选中分配伪终端
配置卷
配置卷使得可以访问外部kebectl 命令,构建镜像
- 使用主机目录挂载卷
- 挂载 kubectl 命令
使用Jenkins 代理
创建流水线任务
创建名称
编辑流水线脚本
pipeline {
agent {
// 使用 k8s 代理,以便于执行kubectl命令
kubernetes {
// 这是你在 Pod 模板中配置的标签
label 'k2-pod-template'
// cloud kubernetes 配置名称
cloud 'MyKubernetes2'
}
}
stages {
// 项目部署
stage('Deploy to k8s') {
steps {
// 检查 kubectl 是否已安装
sh 'kubectl version --client'
}
}
}
}
流水线脚本解释
- agent中
- kubernetes 表示使用的是kubernetes的代理
- label 绑定的要使用的pod模板中的标签(或名称)
- cloud 表示要使用的云k8s 名称
- stage 中 打印 kubectl version 判断 kubectl 命令是否可以正常使用
测试构建流水线任务
完整输出
查看k8s中代理Pod
kubectl get pods -n jenkins -w
结果:
NAME READY STATUS RESTARTS AGE
jenkins-deployment-6f9788f748-b7lhr 1/1 Running 1 (8h ago) 3d4h
k8s-springboot-deployment-577f9d95f5-5r2hb 1/1 Running 0 30m
k2-pod-template-wn8gq 0/1 Pending 0 0s
k2-pod-template-wn8gq 0/1 Pending 0 1s
k2-pod-template-wn8gq 0/1 ContainerCreating 0 1s
k2-pod-template-wn8gq 1/1 Running 0 2s
k2-pod-template-wn8gq 1/1 Terminating 0 3s
k2-pod-template-wn8gq 0/1 Terminating 0 3s
k2-pod-template-wn8gq 0/1 Terminating 0 3s
k2-pod-template-wn8gq 0/1 Terminating 0 4s
k2-pod-template-wn8gq 0/1 Terminating 0 4s
k2-pod-template-wn8gq 0/1 Terminating 0 4s
会创建一个 命名的Pod模板名称 开头的pod
使用maven
在特定节点中使用maven 推荐安装 Pipeline Maven Integration Plugin 插件
商店 搜索 Pipeline Maven Integration Plugin 进行安装
流水线语句
// maven
stage("maven"){
steps{
withMaven(maven: 'maven') {
sh 'mvn -v'
}
}
}
增加maven流水线步骤
- 使用
withMaven(maven: 'maven')
指定使用 Jenkins 中配置的 Maven 名称maven
。
项目构建实战
项目配置编写
项目目录
Maven配置文件
增加docker构建插件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.qsl</groupId>
<artifactId>k8s-test</artifactId>
<version>1.3</version>
<name>k8s</name>
<description>k8s</description>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.0.2</spring-boot.version>
<!-- docker链接地址 -->
<docker.host>tcp://k8s-docker.orb.local</docker.host>
<!-- docker链接端口号 -->
<docker.port>2375</docker.port>
<!-- 私有仓库地址 -->
<docker.push.registry>k8s-master.orb.local:30002</docker.push.registry>
<!-- 私有仓库命名空间 -->
<docker.push.namespace>test</docker.push.namespace>
<!-- 用户名 -->
<docker.push.username>admin</docker.push.username>
<!-- 密码 -->
<docker.push.password>Harbor12345</docker.push.password>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.qsl.k8s.K8sApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.44.0</version>
<configuration>
<!-- docker构建地址 -->
<dockerHost>${docker.host}:${docker.port}</dockerHost>
<!-- 配置全局推送镜像仓库地址,若<images>中<image>指定了该配置则按<image>的配置生效 -->
<pushRegistry>${docker.push.registry}</pushRegistry>
<images>
<image>
<!-- 镜像名称 -->
<!-- qiu_test/docker_app_jar:[镜像版本号] -->
<name>${docker.push.namespace}/${project.artifactId}:${project.version}</name>
<build>
<!-- 指定Dockerfile位置,让插件以Dockerfile模式运行 -->
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
</build>
</image>
<!-- latest 版本号镜像 -->
<image>
<!-- 镜像名称 -->
<!-- qiu_test/docker_app_jar:[镜像版本号] -->
<name>${docker.push.namespace}/${project.artifactId}:latest</name>
<build>
<!-- 指定Dockerfile位置,让插件以Dockerfile模式运行 -->
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
<!-- 指定环境变量 -->
<args>
<PROJECT_FILENAME>${project.build.finalName}.jar</PROJECT_FILENAME>
</args>
</build>
</image>
</images>
<!-- registry服务的认证 -->
<authConfig>
<push>
<!-- 推送服务认证 -->
<username>${docker.push.username}</username>
<password>${docker.push.password}</password>
</push>
</authConfig>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 插件配置
- 连接docker私有镜像仓库 Harbor
- 构建镜像
- 向私有仓库中推送镜像
构建docker镜像配置文件
Dockerfile
FROM openjdk:17
LABEL appname="k8s"
ARG PROJECT_FILENAME
COPY target/${PROJECT_FILENAME} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
EXPOSE 8081
Jenkins配置文件
Jenkins
pipeline {
agent {
// 使用 k8s 代理,以便于执行kubectl命令
kubernetes {
// 这是你在 Pod 模板中配置的标签
label 'my-pod-template'
// cloud kubernetes 配置名称
cloud 'MyKubernetes'
}
}
stages {
// 项目拉取代码
stage('git -pull') {
steps {
git branch: 'main', url: 'https://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@github.com/630133069/k8s-test.git'
echo 'Pulling the code from git'
}
}
// 项目打包
stage('package') {
steps {
// 使用maven插件打包
withMaven(maven: 'maven') {
sh 'mvn -f k8s clean package -DskipTests'
}
}
}
// 项目构建镜像
stage('image build') {
steps {
// 使用maven插件构建镜像
withMaven(maven: 'maven') {
sh 'mvn -f k8s docker:build'
}
}
}
// 项目推送镜像
stage('image push') {
steps {
// 使用maven插件推送镜像
withMaven(maven: 'maven') {
sh 'mvn -f k8s docker:push'
}
}
}
// 推送私有仓库完成删除构建的镜像
stage('image remove') {
steps {
// 使用maven插件删除构建的镜像
withMaven(maven: 'maven') {
sh 'mvn -f k8s docker:remove'
}
}
}
// 项目部署
stage('Deploy to k8s') {
steps {
// 应用 Kubernetes 配置文件
sh 'kubectl apply -f k8s/k8s-springboot.yaml'
}
}
}
}
注解
agent
标签
- 配置kubernetes代理
- Pod 模板中配置的标签
- cloud kubernetes 配置名称
withMaven
标签
使用安装的maven插件,这里可以查看
k8s清单文件
k8s-springboot.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-springboot-deployment
namespace: jenkins
# Deployment的标签
labels:
app: k8s-springboot-deployment
spec:
# 副本数
replicas: 1
# 选择器
selector:
# 选择要管理的Pod的标签
matchLabels:
app: k8s-springboot-pod
template:
metadata:
name: k8s-springboot-pod
labels:
app: k8s-springboot-pod
spec:
containers:
- name: k8s-springboot
image: k8s-master.orb.local:30002/test/k8s-test:latest
imagePullPolicy: Always
- 容器
- 镜像地址从 内部配置的Harbor拉取
- 拉取策略为 一直拉取
配置Containerd
配置Containerd可以拉取私有仓库配置,具体参考
Jenkins配置
Jenkins流水线任务配置
在流水线定义中
- 连接git项目
- 指定脚本路径,用于执行定义的Jenkins流水线任务
安装k8s插件
Jenkins配置代理
添加云服务商
Dashboard-系统管理-Clouds
-
创建名称
-
连接k8s集群
-
查看k8s访问进群访问地址,因为Jenkins 部署在 k8s中,所以可以通过内部代理service进行访问
-
查看Service
kubectl get svc
结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 42d
-
完整的容器间访问地址就是:
https://kubernetes.default.svc.cluster.local
这里可以省略后缀
Kubernetes地址填写上方内部Service访问地址
-
-
配置Jenkins访问地址
因为代理内部需要访问Jenkins 所以需要配置Jenkins内部访问地址,地址是k8s中service代理的容期间访问地址
-
获取Jenkins访问地址
kubectl get svc -n jenkins
结果:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE jenkins-service NodePort 10.100.143.208 <none> 8080:30080/TCP,50000:30370/TCP 5d2h
-
完整的容器访问地址就是
http://jenkins-service.jenkins.svc.cluster.local:8080
-
完整的云服务商代理配置
配置Jenkins Pod模板
-
添加容器
-
配置容器基本参数
解释:
- 名称和标签列表 需要在后面声明的代理模板中使用
- 命名空间表明 Pod需要运行在那个命名空间
-
配置pod容器
此容器为代理空壳容器,表明这是一个 Jenkins的k8s代理
- 名称
jnlp
需要固定 - 镜像
docker.io/jenkins/inbound-agent:jdk17
根据自己的项目使用 - 删掉运行的命令与命令参数
- 选中分配伪终端
- 名称
-
配置卷
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
配置卷使得可以访问外部kebectl 命令,构建镜像
- 使用主机目录挂载卷
- 挂载 kubectl 命令
更多推荐
所有评论(0)