Jenkins基于标签的节点互斥锁配置问题咨询
Let's walk through what's going wrong, why your approach is on the right track, and how to fix it:
Why 方案2 (Lock Wrapping Node) Failed
Your mistake here is misunderstanding how the lock step's label parameter works in the Lockable Resources plugin:
- The
labelinlock(label: 'windows-agent-label')refers to labels assigned to pre-configured lockable resources, not the agent/node labels you use to route jobs to specific nodes. - If you haven't created lockable resources and tagged them with
windows-agent-label, Jenkins can't find any matching resources to lock—even if your agents are online and marked as FREE. That's exactly why you're seeing the "no available resources" error.
Is Your Overall Solution Direction Correct?
Yes! Using a locking mechanism is the right approach here, given your constraints:
- Nodes can't run multiple builds at the same time
- JobA and JobB can't run concurrently
- JobB requires exclusive access to some nodes (for 2 executors) plus additional single-executor nodes
Step-by-Step Fix
1. Configure Lockable Resources First
First, set up lockable resources that map to your Windows agents:
- Go to Jenkins > Manage Jenkins > Configure System > Lockable Resources Manager
- For each Windows agent node, create a lockable resource:
- Set the Resource name to match your node's exact name (e.g.,
win-agent-01,win-agent-02) - Add the label
windows-agent-labelto all these resources (so you can group them) - Check the "Reservable" box to allow jobs to lock the resource
- Set the Resource name to match your node's exact name (e.g.,
2. Fix JobA Pipeline
The key is to lock first, then assign the node—this prevents Jenkins from wasting executor slots on waiting builds. Use the LOCKED_RESOURCES environment variable (auto-set by the lock step) to target the locked node:
// Lock one Windows agent resource first lock(label: 'windows-agent-label', quantity: 1) { // Use the locked resource's name to target the exact node node(env.LOCKED_RESOURCES) { // Your JobA build steps here // Since we locked the resource, no other job can use this node while this runs } }
3. Fix JobB Pipeline
JobB needs to lock multiple resources (1 for the 2-executor node + X for single-executor nodes). We'll split the locked resources and run steps in parallel where needed:
// Lock 1 + X Windows agent resources (adjust X to your actual number) lock(label: 'windows-agent-label', quantity: 1 + 3) { // Example: 1 main node + 3 worker nodes // Split locked resources into main node (for 2 executors) and workers def lockedNodes = env.LOCKED_RESOURCES.split(',') def mainNode = lockedNodes[0] def workerNodes = lockedNodes[1..-1] // Run steps on the main node (uses both executors, no other jobs will run here) node(mainNode) { // JobB steps requiring 2 executors here } // Run parallel steps on worker nodes (each uses 1 executor) parallel workerNodes.collectEntries { nodeName -> ["Worker Job on ${nodeName}": { node(nodeName) { // JobB worker steps here } }] } }
4. Add Global Mutex for JobA/JobB Concurrency
Since JobA and JobB can't run at the same time (regardless of nodes), wrap both job pipelines in a global lock:
// Global lock to prevent JobA and JobB from running concurrently lock('job-ab-global-mutex') { // Put the above lock/node blocks for JobA or JobB here }
Why 方案1 (Lock Inside Node) Was Suboptimal
Putting the lock inside the node block causes Jenkins to first assign a node and executor slot, then wait for the lock. This wastes executor capacity—waiting builds hold onto slots that could be used by other jobs. Locking first avoids this entirely.
内容的提问来源于stack exchange,提问作者Samuel GIFFARD

