关于搭建Kubernetes环境可以参考我前面的公众号文章:Centos7下使用kubeadm搭建Kubernetes-v1.14.2,本篇文章主要实现Jenkins在k8s集群的安装、slave节点在k8s内自动创建销毁,通过pipeline实现java项目的持续集成发布。
安装Jenkins服务到K8S集群
使用Dockerfile制作Jenkins镜像
下载war包进行的安装,Dockerfile如下,war包下载地址:https://jenkins.io/zh/download
FROM java:8
RUN echo 'hello docker, start build image'
RUN mkdir -p /app
WORKDIR /app
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" > /etc/timezone
COPY jenkins.war .
CMD ["java" ,"-Xms1024m","-Xmx1024m", "-jar","/app/jenkins.war"]
制作镜像
docker build -t registry.cn-hangzhou.aliyuncs.com/hiningmeng/jenkins:2.176.2 .
docker push registry.cn-hangzhou.aliyuncs.com/hiningmeng/jenkins:2.176.2
K8S安装Jenkins应用
在k8s集群内创建Jenkins工作的namespace,我这边统一放在devops这个ns底下;
kubectl create ns devops
我这里把Jenkins工作目录单独挂载到PVC,需要先创建pv-pvc,挂载点是使用的nfs服务,请先创建好服务,jenkins-pv-pvc.yaml如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: jenkins-home-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.100
path: "/data/jenkins_home"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-home-pvc
namespace: devops
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 100Gi
为Jenkins创建单独的ServiceAccount,这里的ClusterRole直接使用的cluster-admin,jenkins-serveraccount.yaml如下;
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: jenkins
name: jenkins-admin
namespace: devops
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: jenkins-admin
labels:
app: jenkins
subjects:
- kind: ServiceAccount
name: jenkins-admin
namespace: devops
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
编写Deployment文件,我使用到了node标签apps.k8s.icjl/devops,打标签的命令如下:
kubectl label node your-node-name apps.k8s.icjl/devops=
jenkins-deployment.yaml如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: jenkins
namespace: devops
labels:
app: jenkins
spec:
replicas: 1
template:
metadata:
labels:
app: jenkins
spec:
serviceAccountName: jenkins-admin
imagePullSecrets:
- name: ram-secret
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: apps.k8s.icjl/devops
operator: Exists
containers:
- name: jenkins
image: registry.cn-hangzhou.aliyuncs.com/hiningmeng/jenkins:2.176.2
imagePullPolicy: IfNotPresent
volumeMounts:
- name: jenkins-home
mountPath: /root/.jenkins
readOnly: false
ports:
- containerPort: 8080
- containerPort: 50000
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-home-pvc
创建service,这边使用了NodePort,jenkins-service.yaml如下;
apiVersion: v1
kind: Service
metadata:
labels:
app: jenkins
name: jenkins
namespace: devops
annotations:
prometheus.io/scrape: 'true'
spec:
type: NodePort
ports:
- name: jenkins-web
port: 8080
targetPort: 8080
nodePort: 31442
- name: jenkins-agent
port: 50000
targetPort: 50000
nodePort: 30005
selector:
app: jenkins
也可以使用ingress暴露的方式,jenkins-ingress.yaml如下:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: jenkins
labels:
name: jenkins
namespace: devops
spec:
rules:
- host: jenkins.hiningmeng.cn
http:
paths:
- path: /
backend:
serviceName: jenkins
servicePort: 8080
执行
kubectl apply -f jenkins-pv-pvc.yaml
kubectl apply -f jenkins-serveraccount.yaml
kubectl apply -f jenkins-deployment.yaml
kubectl apply -f jenkins-service.yaml
kubectl apply -f jenkins-ingress.yaml
Jenkins配置
系统管理 --> 插件管理 --> available,安装需要的插件,有的插件下载不下来可以去官网下载之后上传安装。
- Kubernetes
- pipeline
- Git Parameter
配置Kubernetes云信息
在系统管理 --> 系统设置 ,最后面有个Cloud设置,Add a new cloud
添加具体的Kubernetes信息,K8S服务器可以是Jenkins本身所在的服务器,也可以是其他集群(需要配置证书),这里以本身所在集群为例。
- 名称 :用于pipeline调用云名称
- Kubernetes地址:可以通过kubectl cluster-info命令获取
- Kubernetes 服务证书 key:本身所在的集群因为我们通过sa所以不需要
- Kubernetes 命名空间:Jenkins的nodePod节点启动的namespace
- Jenkins 地址:主节点8080端口通过nodeport暴露出来的,地址:端口
- Jenkins 通道:主节点50000端口通过nodeport暴露出来的,地址:端口
创建pipeline任务
选择新建任务,构建流水线。
安装了Git Parameter插件之后,可以进行分支的选择,需要进行参数化构建,这个可以在页面设置,也可以放到pipeline里面,这边直接在页面配置参数。
其中Use repository如果不设置,后面的Pipeline from SCRM的时候,就会取不到分支;
指定pipeline地址,可以直接在页面写,做好是通过Git的方式管理。
Git管理Pipeline的Jenkinsfile文件,需要提供证书拉取
编写Jenkinsfile文件
#定义参数label,K8S启动的pod名称通过这个来制定
def label = "JenkinsPOD-${UUID.randomUUID().toString()}"
#定义jenkins的工作目录
def jenworkspace="/home/jenkins/workspace/${params.PROJECT}"
#maven项目缓存,提供编译速度
def mvnrepo="/tmp/repository"
#kubectl和docker执行文件,这个可以打到镜像里面,这边直接共享的方式提供
def sharefile="/tmp/sharefile"
#deployment等K8S的yaml文件目录
def k8srepo='/tmp/k8s_repos'
#cloud为我们前面提供的云名称,nodeSelector是K8S运行pod的节点选择
podTemplate(label: label, cloud: 'kubernetes-hiningmeng',nodeSelector: 'devops.k8s.icjl/jenkins=jnlp',
containers: [
containerTemplate(
name: 'jnlp',
image: 'registry-vpc.cn-hangzhou.aliyuncs.com/hiningmeng/jnlp:v1',
ttyEnabled: true,
alwaysPullImage: false),
containerTemplate(
name: 'jnlp-maven',
image: 'jenkins/jnlp-agent-maven',
//image:'ungerts/jnlp-agent-maven',
ttyEnabled: true,
alwaysPullImage: false,
command: 'cat')
],
volumes: [
hostPathVolume(hostPath: '/var/run/docker.sock', mountPath:'/var/run/docker.sock'),
persistentVolumeClaim(mountPath: "$mvnrepo", claimName: 'maven-repo-pvc', readOnly: false),
persistentVolumeClaim(mountPath: "$sharefile", claimName: 'sharefile-repo-pvc', readOnly: false),
]
)
{
node (label) {
stage('Hello World'){
container('jnlp'){
echo "hello, world"
sh "ln -s $sharefile/kubectl /usr/bin/kubectl"
sh "ln -s $sharefile/docker /usr/bin/docker"
}
}
stage('Git Pull'){
dir("$jenworkspace"){
git branch: "${params.BRANCH}", changelog: false, credentialsId: 'jenkins-pull-key', poll: false, url: "${params.CODE_URL}"
}
}
stage('Mvn Package'){
container('jnlp-maven'){
dir("$jenworkspace"){
sh "mvn clean install -Dmaven.test.skip=true -U -s $sharefile/settings.xml"
}
}
}
stage('Docker build'){
...
}
stage('K8S Deploy'){
...
}
}
}
具体的脚本还是自己摸索一下,不同的项目定制即可,大体的架子如上面的实例
构建项目
任务一次都没构建的时候会出现报错,构建一次就没问题了;
如果一切正常的话,在K8S的devops命名空间会创建出新的POD
至此,简单的可伸缩的基于K8S的Jenkins就完成了,如有问题欢迎交流。