我们有一个主要的构建管道,它使用工作流cps并行步骤同时运行大约50个容器,并且它严重依赖于sh。 随着更多代理添加到并行步骤中,如果 sh 命令包含在 groovy 脚本中,则需要更长的时间才能完成。 (这对于常规 Linux 静态节点和 k8s pod 来说是正确的)
我简化了管道,因此更容易重现:
pipeline {
agent none
stages {
stage('Build and Test') {
parallel {
stage('Stage1') {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-build
image: ubuntu
resources:
requests:
memory: 4000Mi
cpu: 4
limits:
memory: 4000Mi
cpu: 4
command: ['sleep']
args: ['6h']
tty: true
"""
}
}
steps {
container('test-build') {
script{
for (int i = 0; i < 30; i++) {
sh 'cat /etc/hosts'
}
}
}
}
}
stage('Stage2') {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- name: test-build
image: ubuntu
resources:
requests:
memory: 4000Mi
cpu: 4
limits:
memory: 4000Mi
cpu: 4
command: ['sleep']
args: ['6h']
tty: true
"""
}
}
steps {
container('test-build') {
script{
for (int i = 0; i < 30; i++) {
sh 'cat /etc/hosts'
}
}
}
}
}
// ...
// ....
// in here you can keep pasting duplicates of stages
}
}
}
}
对每个阶段的硬编码表示歉意,但我无法想出一个可以做得更好的循环。
我的结果如下:
7 个阶段:每个代理大约需要 50 秒完成
17 个阶段:每个代理完成约 120 秒
35 个阶段:每个特工完成约 270 个阶段
如果我在并行部分只留下一个阶段,然后同时运行相同的构建 X50 次,每个构建完成得非常快(大约 15 秒) 所以我不认为这是一个一般的负载问题,而是并行步骤可能以某种方式限制 sh 响应,使它们挂起。 (也许是 CpsFlowExecution 线程?)
请您提出建议。
sh 命令周围使用 Groovy 脚本包装器时。这可能是由于 Jenkins 如何处理和安排这些并行执行,特别是在 Jenkins 用于管道脚本的 CPS(连续传递风格)执行模型下。
以下是缓解此问题的一些策略:
1。减少 Groovy 脚本包装器的数量
Groovy 脚本包装器围绕sh 命令增加了开销。减少script块的使用可以帮助最大限度地减少这种情况。
2。直接使用sh命令
如果可能,请避免在 Groovy 脚本中包装sh 命令,除非绝对必要。
steps {
container('test-build') {
for (int i = 0; i < 30; i++) {
sh 'cat /etc/hosts'
}
}
}
3.优化 Pod 规格
确保您的 Kubernetes Pod 规格尽可能优化。减少 pod 的初始化时间。
4。更少阶段的并行执行
不要并行运行多个阶段,而是考虑在可行的情况下将任务合并为更少的阶段。
5。使用声明性语法进行并行执行
确保您使用声明性语法进行并行执行,因为它通常比脚本语法更高效且更易于管理。
6。研究 Jenkins 系统配置
检查您的 Jenkins 系统配置,确保其针对并行执行进行了优化。这包括:
7。动态舞台创作
考虑以更有效的方式动态创建阶段。这是一个例子:
pipeline {
agent none
stages {
stage('Build and Test') {
parallel {
script {
def stages = [:]
for (int i = 1; i <= 50; i++) {
stages["Stage${i}"] = {
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
metadata:
name: test-pod-${i}
spec:
containers:
- name: test-build
image: ubuntu
resources:
requests:
memory: 4000Mi
cpu: 4
limits:
memory: 4000Mi
cpu: 4
command: ['sleep']
args: ['6h']
tty: true
"""
}
}
steps {
container('test-build') {
for (int j = 0; j < 30; j++) {
sh 'cat /etc/hosts'
}
}
}
}
}
parallel stages
}
}
}
}
}
这会动态创建 50 个阶段,减少手动编写每个阶段的开销,并可能提高性能。
8。研究 CPS 模型开销
如果 CPS 模型造成大量开销,请考虑使用管道:Groovy 插件的非 CPS 步骤,尽管它可能会使管道复杂化。
9。查看 Jenkins 版本和插件
确保您正在运行最新稳定版本的 Jenkins 和相关插件,因为性能改进和错误修复会不断发布。
10。监控和分析管道执行
使用 Jenkins 监控插件来分析管道执行情况并识别瓶颈。 Performance 和 Pipeline Profiler 等插件可以提供帮助。实施这些策略应该有助于缓解问题并提高 Jenkins 管道中并行步骤的性能。
如有其他问题请告知。