DevOps Day 80: Chained Builds and Downstream Jobs¶
Today's task was an advanced automation scenario involving Build Chaining. The goal was to create a deployment pipeline where one job deploys code, and if (and only if) it succeeds, it triggers a second "downstream" job to restart the application services.
This ensures that we don't restart services if the code deployment failed, preventing downtime. I used the Publish Over SSH plugin to manage connections to multiple servers and configured a parameterized downstream job to handle service restarts securely.
Table of Contents¶
- DevOps Day 80: Chained Builds and Downstream Jobs
- Table of Contents
- The Task
- My Step-by-Step Solution
- Phase 1: Configuring "Publish Over SSH"
- Phase 2: Creating the Deployment Job (Upstream)
- Phase 3: Creating the Service Management Job (Downstream)
- Phase 4: Verification
- Why Did I Do This? (The "What \& Why")
- Deep Dive: Upstream vs. Downstream Jobs
- Common Pitfalls
- Exploring the UI Used
The Task¶
My objective was to configure two linked Jenkins jobs:
1. nautilus-app-deployment (Upstream): Pulls code from the web repository to the shared storage /var/www/html on the Storage Server.
2. manage-services (Downstream): Restarts the httpd service on all three App Servers (stapp01, stapp02, stapp03), but only if the deployment job is stable.
My Step-by-Step Solution¶
The solution involved configuring the global SSH plugin settings and then setting up the two interdependent jobs.
Phase 1: Configuring "Publish Over SSH"¶
Before creating jobs, I needed to teach Jenkins how to talk to all four servers (Storage + 3 App Servers).
1. Install Plugin: I went to Manage Jenkins > Plugins and installed "Publish Over SSH". I restarted Jenkins.
2. Configure Servers: I went to Manage Jenkins > System.
3. I scrolled down to the Publish over SSH section.
4. Storage Server:
- Name: ststor01
- Hostname: ststor01.stratos.xfusioncorp.com
- Username: natasha
- Remote Directory: /
- Advanced > Check Use password authentication.
- Password: Bl@kW
- Clicked Test Configuration -> Success.
5. App Servers: I clicked "Add" and repeated the process for all three app servers:
- stapp01: User tony (Ir0nM@n).
- stapp02: User steve (Am3ric@).
- stapp03: User banner (BigGr33n).
6. I clicked Save.
Phase 2: Creating the Deployment Job (Upstream)¶
- New Item: Created a Freestyle project named
nautilus-app-deployment. - Build Steps: Added "Send files or execute commands over SSH".
- Name:
ststor01(Selected from the dropdown). - Exec command:
cd /var/www/html # The repo is already there, just need to update it git pull origin master
- Name:
- Post-build Actions: Added "Build other projects".
- Projects to build:
manage-services. - Trigger only if build is stable: Checked.
- Projects to build:
- I clicked Save.
Phase 3: Creating the Service Management Job (Downstream)¶
- New Item: Created a Freestyle project named
manage-services. - Parameters: I checked "This project is parameterized" to securely handle sudo passwords.
- Added Password Parameter:
STAPP01_PASS(Default:Ir0nM@n). - Added Password Parameter:
STAPP02_PASS(Default:Am3ric@). - Added Password Parameter:
STAPP03_PASS(Default:BigGr33n).
- Added Password Parameter:
- Build Steps: Added "Send files or execute commands over SSH".
- Server 1:
stapp01. - Command:
echo $STAPP01_PASS | sudo -S systemctl restart httpd - Server 2:
stapp02(Added another "Transfer Set"). - Command:
echo $STAPP02_PASS | sudo -S systemctl restart httpd - Server 3:
stapp03(Added another "Transfer Set"). - Command:
echo $STAPP03_PASS | sudo -S systemctl restart httpd
- Server 1:
- I clicked Save.
Phase 4: Verification¶
- I manually triggered
nautilus-app-deployment. - I watched it complete successfully.
- I verified that
manage-servicesstarted automatically right after. - I checked the console output of
manage-servicesto confirm the restart commands were sent successfully. - I refreshed the main website URL (
https://<LBR-URL>) to confirm the app was live.
Why Did I Do This? (The "What & Why")¶
- Chained Builds: In complex systems, you rarely want one giant job that does everything. By splitting "Deployment" and "Restart" into two jobs, I kept them modular. If I just want to restart services without deploying code, I can run manage-services independently.
- Downstream Triggers: This ensures order and safety. We never want to restart the web server if the code deployment failed (leaving the site in a broken state). The "Trigger only if stable" condition acts as a safety gate.
- sudo -S: SSH commands run non-interactively. sudo usually asks for a password from the keyboard. The -S flag tells sudo to read the password from Standard Input (stdin), which allowed me to pipe the password (echo $PASS | ...) securely into the command.
Deep Dive: Upstream vs. Downstream Jobs¶
This relationship creates a dependency pipeline.
[Image of Jenkins Upstream Downstream flow]
- Upstream (
nautilus-app-deployment): The parent job. It initiates the process. It has no idea how to restart services; it just knows who to call when it's done. - Downstream (
manage-services): The child job. It waits for a signal. It doesn't care where the code came from; its only job is to ensure the services pick up the changes.
This separation of concerns makes debugging easier. If the code didn't update, I check the Upstream logs. If the server didn't restart, I check the Downstream logs.
Common Pitfalls¶
- Parameter Names: When using echo $VAR, the variable name in the shell command MUST match the Parameter Name defined in the job exactly. Case matters.
- Hidden Spaces: Copy-pasting passwords into the "Default Value" field can sometimes include a trailing space, which causes sudo to reject the password.
- SSH Exec Timeout: If systemctl restart takes too long, the SSH command might timeout. Increasing the timeout in the "Publish Over SSH" global settings prevents this.
Exploring the UI Used¶
- Manage Jenkins > System: The location for configuring global tools like the "Publish Over SSH" servers.
- Post-build Actions: The section in a Job configuration where you define what happens after the main work is done (e.g., triggering another job).
- Send files or execute commands over SSH: A build step provided by the plugin that allows running shell commands on remote servers without needing a full Jenkins agent setup on them.