传统的主机方式部署的 Jenkins 集群在复杂场景中会经常碰到如下问题,如:
基于k8s编排和Docker容器技术,可以很好的解决上面问题。Jenkins Master 和 Jenkins Slave 以 Docker Container 形式运行在 Kubernetes 集群的 Node 上,Master 运行在其中一个节点,Slave 运行在各个节点上,并且它不是一直处于运行状态,它会按照需求动态的创建并自动删除。最终的方式和传统的是一样的,也是基于jenkins-agent.jar,通过jnlp进行通信,只不过jenkins 的 kubernetes-plugin 插件帮我们把这些操作做完了。通过这样的方式,在需要 Build 的时候创建 Slave Pod 动态伸缩,而且pod可以基于模板定制环境,Build结束后就销毁,合理利用计算资源。
网上很多,可以通过helm或者自己定制配置文件。
Pipeline相关,文档语法:
https://www.jenkins.io/zh/doc/book/pipeline/syntax/
Kubernetes Plugin,主要用于创建Slave Pod 并分配给Slave相关流水线工作内容,相关文档:
https://github.com/jenkinsci/kubernetes-plugin
https://www.jenkins.io/doc/pipeline/steps/kubernetes/
Kubernetes Continuous Deploy Plugin,主要用于容器内发布k8s相关资源,相关文档:
https://www.jenkins.io/doc/pipeline/steps/kubernetes-cd/#kubernetesdeploy-deploy-to-kubernetes
插件安装完毕后,点击 “系统管理” —> “系统设置” —> “Cloud” 进入云集群配置页面 选择 Kubernetes
填写kubernetes 和 Jenkins 配置
需要注意一点:在使用的时候Pipeline的Pod启动的时候会有Node-Selectors: kubernetes.io/os=linux,所以需要在集群node上面添加kubernetes.io/os=linux的label
参数化配置
配置的参数可以在pipeline script 中使用 ${params.key} 来使用,如上面就是 ${params.APP_NAME}
流水线脚本,可以参考上面提供的插件文档
def label = "test-pipline"
def HARBOR_HOST = "test.harbor.com"
podTemplate(label: label, cloud: 'kubernetes', imagePullSecrets: ['test-harbor'],
containers: [
containerTemplate(name: 'node', image: 'node:14.16.0-alpine3.10', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'maven', image: 'test.harbor.com/maven:3.6.3-jdk-8', ttyEnabled: true, command: 'cat'),
containerTemplate(name: 'docker', image: 'docker:20.10.5-git', , ttyEnabled: true, command: 'cat'),
], volumes: [
hostPathVolume(hostPath: '/var/run/docker.sock', mountPath:'/var/run/docker.sock'),
persistentVolumeClaim(claimName: 'jenkins-build-pvc', mountPath: '/root/repo')
], workspaceVolume: persistentVolumeClaimWorkspaceVolume(claimName: 'jenkins-workspace-pvc')
) {
node(label) {
stage('Git Clone') {
git branch: 'master', credentialsId: 'gitlab', url: 'https://test.gitlab.com/devil/test.git'
}
stage('Node Build') {
container('node'){
sh """
cd vue
npm install
npm run build
"""
}
}
stage('Maven Build') {
container('maven'){
sh "mvn package -Dmaven.test.skip=true"
}
}
stage('Docker Build') {
container('docker'){
withCredentials([usernamePassword(credentialsId: "harbor", passwordVariable: 'HARBOR_PWD', usernameVariable: 'HARBOR_USERNAME')]) {
sh "docker login " + HARBOR_HOST + " -u ${HARBOR_USERNAME} -p ${HARBOR_PWD}"
sh "docker build -t " + HARBOR_HOST + "/${params.IMAGE_NAME}:${params.IMAGE_TAG} ."
sh "docker push " + HARBOR_HOST + "/${params.IMAGE_NAME}:${params.IMAGE_TAG}"
}
}
}
stage('Deploy') {
sh "sed -e 's#{IMAGE_URL}#" + HARBOR_HOST + "/${params.IMAGE_NAME}#g;s#{IMAGE_TAG}#${params.IMAGE_TAG}#g;s#{APP_NAME}#${params.APP_NAME}#g;s#{REPLICAS_NUM}#${params.REPLICAS_NUM}#g;s#{HEAP_SIZE}#${params.HEAP_SIZE}#g;s#{DIRECT_MEMORY_SIZE}#${params.DIRECT_MEMORY_SIZE}#g' k8s-deployment-tpl.yaml > k8s-deployment.yml"
sh "cat k8s-deployment.yml"
kubernetesDeploy(configs: 'k8s-deployment.yml', kubeconfigId: "k8s-client")
}
}
}
容器模板相关
kubectl create secret docker-registry -n jenkins harbor --docker-username=*** --docker-password=**** [email protected] --docker-server=host
数据挂载相关
kubeconfig类型凭证,系统管理-> manager Credentials 创建凭证,credentialsId同理,基于需要用Username/Password或者其它类型
上面pipeline最后Deploy指定了项目根目录下k8s-deployment-tpl.yaml,用自定义的构建参数进行文本替换,生成k8s-deployment.yml用于k8s发布插件发布。k8s-deployment-tpl.yaml 模板内容如下:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: {APP_NAME}
spec:
replicas: {REPLICAS_NUM}
template:
metadata:
name: {APP_NAME}
labels:
app: {APP_NAME}
spec:
containers:
- image: {IMAGE_URL}:{IMAGE_TAG}
name: {APP_NAME}
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /root/config.yaml
subPath: config.yaml
volumes:
- name: config
configMap:
name: test-config
items:
- key: config.yaml
path: config.yaml
---
apiVersion: v1
kind: Service
metadata:
name: {APP_NAME}
spec:
ports:
- port: 80
targetPort: 80
selector:
app: {APP_NAME}
创建 pod 模板
这里的配置其实和上面pipeline中podTemplate相似,创建完pod模板后,构建一个自由风格的软件项目,在标签中选择刚刚创建的模板,这样就会自动按模板要求进行操作。