What is the difference between a node, stage, and step in Jenkins pipelines?
I'm trying to understand how to structure my Jenkins 2.7 pipeline groovy script. I've read through the pipeline tutorial, but feel that it could expand more on these topics.
I can understand that a pipeline can have many stage
s and each stage
can have many step
s. But what is the difference between a step();
and a method call inside a stage
, say sh([script: "echo hello"]);
. Should node
s be inside or outside of stage
s? Should the overall properties of a job be inside or outside a node
?
Here is my current structure on an ubuntu master node:
#!/usr/bin/env groovy
node('master') {
properties([
[$class: 'BuildDiscarderProperty', strategy: [$class: 'LogRotator', numToKeepStr: '10']]
]);
stage 'Checkout'
checkout scm
stage 'Build'
sh([script: "make build"]);
archive("bin/*");
}
The concepts of node
, stage
and step
are different:
node
specifies where something shall happen. You give a name or a label, and Jenkins runs the block there.stage
structures your script into a high-level sequence. Stages show up as columns in the Pipeline Stage view with average stage times and colours for the stage result.step
is one way to specify what shall happen.sh
is of a similar quality, it is a different kind of action. (You can also usebuild
for things that are already specified as projects.)
So step
s can reside within node
s, (if they don't, they are executed on the master), and node
s and step
s can be structured into an overall sequence with stage
s.
It depends. Any node
declaration allocates an executor (on Jenkins master or slave). This requires that you stash
and unstash
the workspace, as another executor does not have the checked out sources available.
Several steps of the Pipeline DSL run in a flyweight executor and thus do not require to be inside a node
block.
This might be helpful for an example such as the following, where you need to allocate multiple nodes anyway:
stage("Checkout") {
checkout scm
}
stage("Build") {
node('linux') {
sh "make"
}
node('windows') {
bat "whatever"
}
}
stage("Upload") {
...
Another (maybe more realistic example) would be to allocate multiple nodes in parallel
. Then there's no need to let the stage
call be executed in another allocated executor (aka within node
).
Your example looks good to me. There's no need to allocate multiple node
s within the single stage
s, as this would be only additional overhead.