优化jenkins on kubernetes构建性能慢问题
现在大多数公司,都开始使用kubernetes开启云原生时代了,传统的jenkins在物理机构建场景已经越来越少见了,取而代之的是用jekins在kubernetes pod中动态构建我们的任务
前言
现在大多数公司,都开始使用kubernetes开启云原生时代了,传统的jenkins在物理机构建场景已经越来越少见了,取而代之的是用jekins在kubernetes pod中动态构建我们的任务(Kubernetes plugin for Jenkins:Kubernetes | Jenkins plugin),充分利用了kubernetes集群弹性资源的能力,在这个场景下,我们可能会碰到一些构建性能慢的问题,下面来综合分析一下
项目编译慢
以maven为例,编译大型开源项目动辄几十分钟是很正常的,因为编译工程过要大量下载项目依赖,如果没有配置依赖缓存,那么每次构建耗时都会很久是非常影响开发迭代效率的。
针对这个问题,我们可以加入依赖缓存,以maven为例:我们需要提供一个持久的.m2目录存储,在kubernetes里面实现这一点并不难,如果有ceph就可以直接挂PVC,如果没有ceph挂主机共享的卷也可以:
#!groovy
podTemplate(cloud: 'cloud-build', label: 'jenkins',
containers: [
containerTemplate(resourceRequestCpu: '1', resourceLimitCpu: '4', resourceRequestMemory: '4Gi', resourceLimitMemory: '8Gi', name: 'docker', image: 'xxxx.com/library/docker:17.05.0-ce', ttyEnabled: true, privileged: true, instanceCap: 1, command: 'cat', arg: "", alwaysPullImage: false),
containerTemplate(resourceRequestCpu: '1', resourceLimitCpu: '4', resourceRequestMemory: '4Gi', resourceLimitMemory: '8Gi', name: 'maven', image: 'xxx.com/library/maven:3.8.3-adoptopenjdk-8', ttyEnabled: true, command: 'cat', arg: "", alwaysPullImage: false),
],
volumes: [
hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock'), //docker in docker
hostPathVolume(hostPath: '/opt/maven/m2', mountPath: '/root/.m2') //持久化maven cache
]) {
node('jenkins') {
stage('Check code') {
echo("gitCommitId value is: ${gitCommitId}")
checkout([$class: 'GitSCM', branches: [[name: "${gitCommitId}"]], userRemoteConfigs: [[credentialsId: "${gitlabCredential}" , url: "${gitlabURL}"]]])
}
stage('Maven package') {
container('maven') {
sh "mvn clean package -DskipTests -Dmaven.test.skip"
}
}
stage('Build Image') {
container('docker') {
// 此处尽量避免使用--pull,每次强制拉取镜像
sh "docker build -t myproject:${env.BUILD_NUMBER} -f dockefile_dev ."
}
}
}
}
这里面有一点需要注意,如果要使用maven的依赖cache,就必须把打包编译语句放在docker build镜像的外层,如果你放在build的dockfile内,虽然能保持编译和运行环境一致,但无法使用volume挂载,从而无法使用挂载的持久.m2 cache,这是docker的机制决定的。
拉推镜像慢
这里面分三部分:
- 在网络带宽有限情况下,每次都去强拉镜像
在kubernetes中运行的项目,都需要一个基础镜像,如果每次都去拉取镜像势必会影响构建效率,默认情况下就会使用缓存的,我们避免配置强制拉取就可以了,注意:alwaysPullImage: false
containerTemplate(name: 'hdfs-client', image: 'harbor.xxxx/maven:latest', ttyEnabled: true, command: 'cat', arg: "", alwaysPullImage: false),
- 构建镜像体积大:
选用from镜像更小的镜像 + 自行构建控制新加入的依赖项,这个其实比较容易优化,尽量删除无用的包及cache
- 重复推镜像
很多公司都有习惯,在jenkins构建镜像完成后,除了有一个带版本号的镜像,还喜欢在打个tag:latest,
例如:spark-3.1.0:44 和 spark-3.1.0:latest,其实完全没必要在打个latest的镜像,因为在kubernetes运行的Deployment中的镜像使用latest这种镜像是非常不推荐的,因为其废掉了项目发布版本概念,极端情况下会导致多个版本不同的副本同时存在,从而带来不稳定因素,所以最好避免使用这种方式,这样我们也不用重复推镜像,影响构建效率
Pod调度慢
在jenkins-slave运行在kubernetes上,每次发起的构建任务,都会拉起一个jnlp-agent POD来执行构建任务,但某些情况下,可能会出现:调度2分钟,构建30秒的情况。这种情况下是因为kube-scheduler这个集群的默认调度器,在经过过滤,打分计算后,评估出来集群中暂时没有存在多余资源的Node节点用来运行这个Agent,默认的调度器的资源评估具有滞后性,所以可能存在调度资源不均衡,或者调度分配不准确的问题。
优化方法:
1,调参数:调度器性能调优 | Kubernetes
2,使用 实时资源打分插件 Trimaran scheduler-plugins/pkg/trimaran at master · kubernetes-sigs/scheduler-plugins · GitHub
3,尽量减小Agent Pod里面容器使用的资源(jnlp是默认的容器,我们可能还会增加maven,docker等新的容器),以便于调度器更容易找到运行节点
4,如果kubernetes集群经常出现调度延迟大,那么有可能是资源确实紧张,这个时候该考虑给集群扩容新的节点了
总结
优化的整体原则就是,能用cache的都用cache,能节省网络带宽的就节省网络带宽,如果集群资源紧张,那么就需要合理设置构建Pod的资源限制,方便kubernetes集群调度器,能够尽快的让我们的构建任务运行起来。
更多推荐
所有评论(0)