本文是基于云原生概念使用jenkins **Pipeline流水线 **项目声明式脚本形式进行SpringBoot项目持续构建和发布的实战教程.
项目需要环境 Gitlab、Kubernetes集群、Jenkins
k8s集群和Gitlab 搭建将在后续整理,本次只介绍Jenkins的安装配置以及Pipeline的使用
GitHub jenkinsci kubernetes-plugin 官网提供的 jenkins.yaml 和 service-account.yaml 文件,这里官网使用的是比较规范的 StatefulSet(有状态集群服务)方式进行部署,并配置了 Ingress 和 RBAC 账户权限信息。
创建jenkins-1-namespace.yaml 创建新的命名空间
apiVersion: v1
kind: Namespace
metadata:
name: jenkins
创建jenkins-2-rbac.yaml RBAC账户权限信息
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-sa
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jenkins-cr
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["services"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- 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: ClusterRoleBinding
metadata:
name: jenkins-crd
roleRef:
kind: ClusterRole
name: jenkins-cr
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: jenkins-sa
namespace: jenkins
创建jenkins-3-storage.yaml pvc
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-pv
labels:
app: jenkins
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
glusterfs:
endpoints: glusterfs-cluster
path: k8s-jenkins
readOnly: false
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
namespace: jenkins
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
selector:
matchLabels:
app: jenkins
创建jenkins-4-deploy.yaml jenkins服务
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
terminationGracePeriodSeconds: 10
serviceAccount: jenkins-sa
containers:
- name: jenkins
image: 192.168.*.*/dev/jenkins:jdk8
imagePullPolicy: IfNotPresent
command: [ "/bin/bash", "-ce", "/usr/local/bin/jenkins.sh" ]
env:
- name: JAVA_OPTS
value: -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 -Duser.timezone=Asia/Shanghai
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
#resources:
# limits:
# cpu: 1000m
# memory: 1Gi
# requests:
# cpu: 500m
# memory: 512Mi
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
#readinessProbe:
# httpGet:
# path: /login
# port: 8080
# initialDelaySeconds: 60
# timeoutSeconds: 5
# failureThreshold: 12
volumeMounts:
- name: jenkinshome
mountPath: /var/jenkins_home
securityContext:
fsGroup: 1000
volumes:
- name: jenkinshome
persistentVolumeClaim:
claimName: jenkins-pvc
---
apiVersion: v1
kind: Service
metadata:
name: jenkins
namespace: jenkins
labels:
app: jenkins
spec:
selector:
app: jenkins
type: NodePort
ports:
- name: web
port: 8080
targetPort: web
nodePort: 32000
- name: agent
port: 50000
targetPort: agent
创建jenkins-5-ingress.yaml Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins-ingress
namespace: jenkins
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: "jenkins.hifun.prod"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins
port:
number: 8080
** 创建jenkins-6-maven-pvc.yaml** maven挂载pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-maven-pvc
namespace: jenkins
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 10Gi
切换新的命名空间, 创建jenkins服务
kubectl create -f jenkins-1-namespace.yaml
kubectl config set-context $(kubectl config current-context) --namespace=jenkins
kubectl create -f jenkins-2-rbac.yaml
kubectl create -f jenkins-3-storage.yaml
kubectl create -f jenkins-4-deploy.yaml
kubectl create -f jenkins-5-ingress.yaml
kubectl create -f jenkins-6-maven-pvc.yaml
运行命令查看服务
kubectl get pod,service,pvc,deployment -n jenkins
NAME READY STATUS RESTARTS AGE
pod/jenkins-65fd8c5cd6-sp82c 1/1 Running 0 24h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/jenkins NodePort 0.0.0.0 8080:32000/TCP,50000:30573/TCP 36d
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/jenkins-maven-pvc Bound pvc-67d7cc98-315e-45fb-9b63-93df3a45768e 10Gi RWO longhorn 154m
persistentvolumeclaim/jenkins-pvc Bound jenkins-pv 10Gi RWX 43d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/jenkins 1/1 1 1 36d
通过浏览器打开 http://:32000
初始化过程中,让输入 /var/jenkins_home/secret/initialAdminPassword 初始密码, 执行
$ kubectl exec -it jenkins-65fd8c5cd6-sp82c cat /var/jenkins_home/secrets/initialAdminPassword
获取密码后下一步, 开始初始化插件安装, 等安装完成后(如部分插件安装失败可以先跳过, 之后在系统设置>插件管理 继续安装)
登录后, 查看插件
新建任务, 选择流水线项目
在流水线定义栏选择 Pipeline script ,输入以下内容, 点击应用>保存.(其他忽略)
pipeline{
agent any
stages{
stage("demo"){
steps{
echo "hello pipeline"
}
}
}
}
创建完成后, 点击立即构建, 可以看到输出以下内容
至此jenkins安装, 测试Pipeline结束
在jenkins控台搜索kubernetes插件并下载,安装成功后重启jenkins
然后进入系统管理>节点管理>配置集群
添加一个新的集群
配置集群, 应用并保存,证书详见下方生成说明
点击连接测试, 出现k8s信息则表示成功
在Kubernetes Master
cat /root/.kube/config
# 复制client-certificate-data的内容,运行以下命令生成client.crt
echo "" | base64 -d > client.crt
# 复制client-key-data的内容,运行以下命令生成client.key
echo "" | base64 -d > client.key
# 复制certificate-authority-data的内容,运行以下命令生成ca.crt
echo "" | base64 -d > ca.crt
# 根据前面步骤生成的ca.crt, client.crt和client.key来生成PKCS12格式的cert.pf
# 运行以下命令
openssl pkcs12 -export -out cert.pfx -inkey client.key -in client.crt -certfile ca.crt
#输入证书密码
将生成的Kubernetes Client P12 Certificate cert.pfx 证书下载到本地, 在集群配置选择添加jenkins凭据
将ca.crt内容填充到 Kubernetes 服务证书 key
cat ca.crt
为了能够完成项目构建, 我们需要 jenkins-slave子节点、maven环境、docker环境,为了第一次方便一步步尝试, 我们需要创建三个 Pod Template
jenkins-slave
我们最先需要的是一个jenkins的构建节点,配置如下
此时我们可以新建一个pipeline项目demo2, 来测试jenkins-slave,这个容器中会有一个jdk环境,可以进行如下测试, kubernetes为集群, inheritfrom指定我们构建使用的pod标签, 在容器内运行 java -version
pipeline{
agent {
kubernetes{
inheritFrom 'jenkins-slave'
}
}
stages {
stage ("dierci") {
steps {
sh 'java -version'
}
}
}
}
maven pod
创建构建需要的maven环境, 配置如下
maven每次构建项目都要去拉取jar包,重复构建肯定会浪费很多时间, 因此我们为pod添加一个pvc, 此处的 jenkins-maven-pvc就是上面jenkins-6-maven-pvc.yaml创建的pvc
创建新的pipeline工程进行测试, 这里注意我们用的就是集群里我们刚刚创建的maven-3.6 pod了,可以看下mvn 的版本
pipeline{
agent {
kubernetes{
inheritFrom 'maven-3.6'
}
}
stages{
stage("maventest"){
steps{
container('maven'){
sh 'mvn -version'
}
}
}
}
}
docker pod
在jenkins管理中心安装插件 docker 和 docker pipeline
配置docker pod
此处我们还要配置一个特殊的卷,使得我们的容器内的docker能够访问到宿主机上面的docker.sock文件
在集群主节点运行命令获取文件目录, 获取到的路径直接添加到pod模板新增卷 Host Path Volume下
find / -iname "*docker.sock"
我们在准备好的springboot项目文件夹根目录创建DockerFile文件
FROM java:8
EXPOSE 8080
VOLUME /slm
ADD boot-docker-0.0.1-SNAPSHOT.jar boot-docker.jar
RUN sh -c 'touch /boot-docker.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /boot-docker.jar" ]
创建新的jenkins工程boot-docker流水线任务
环境变量environment
agent使用kubernetes集群下我们刚建的pod模板docker-and-maven
此处为了方便, 我们没有配置git凭据, 而是采用了http方式使用gitlab账户的token进行代码拉取
编译项目
创建docker镜像, 登录docker, 推送镜像
构建完成后,就可以登录Harbor查看自己的镜像了, 后续还会持续构建, 并在pipeline中完成项目的启动与健康检查
此博文部分参考自b站马哥教育基于Kubernetes和Jenkins的GitOps实战