{"id":147,"date":"2025-11-30T10:44:59","date_gmt":"2025-11-30T18:44:59","guid":{"rendered":"https:\/\/rainier-it.com\/blog\/?p=147"},"modified":"2025-11-30T10:53:11","modified_gmt":"2025-11-30T18:53:11","slug":"using-ansible-and-jenkins-to-automate-infra-tasks","status":"publish","type":"post","link":"https:\/\/rainier-it.com\/blog\/using-ansible-and-jenkins-to-automate-infra-tasks\/","title":{"rendered":"Using Ansible and Jenkins to Automate Infra Tasks"},"content":{"rendered":"\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">From Chaos to Consistency: Automating Linux Maintenance with Ansible and Jenkins<\/h3>\n\n\n\n<p>If you are running an internal IT team, or you are a business owner relying on a fleet of Linux servers, you know the dread of &#8220;Patch Tuesday&#8221; (or whatever day you choose to roll out updates).<\/p>\n\n\n\n<p>Manual server maintenance is a silent killer of productivity. It\u2019s repetitive, prone to human error, and often requires late nights for your admins.<\/p>\n\n\n\n<p>At <strong>Rainier IT<\/strong>, we believe in <strong>Infrastructure as Code (IaC)<\/strong>. By treating your server configurations like software code, we can automate the boring stuff, eliminate &#8220;configuration drift,&#8221; and ensure 100% uptime.<\/p>\n\n\n\n<p>Today, we\u2019re going to get technical. We are pulling back the curtain to show you how we utilize <strong>Jenkins<\/strong> and <strong>Ansible<\/strong> to orchestrate complex maintenance tasks\u2014specifically handling smart updates, conditional reboots, and automated reporting.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"387\" src=\"https:\/\/encrypted-tbn3.gstatic.com\/licensed-image?q=tbn:ANd9GcTAF7cHLzeCQqjHS6EY82-EdLib8uP0myRdblT--cTEWqQ2MIm7fxkZYUOIRzz09IDOxqa8SLrrZH4RN-xlatZU6pqlirdcPOyL66IZJjY1RW_FOHE\" alt=\"Image of DevOps pipeline diagram\"><\/p>\n\n\n\n<p class=\"has-text-align-center\">Shutterstock<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Power Duo: Jenkins and Ansible<\/h2>\n\n\n\n<p>Think of <strong>Jenkins<\/strong> as the project manager and <strong>Ansible<\/strong> as the skilled workforce.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Jenkins<\/strong> handles the scheduling, the &#8220;when,&#8221; and the reporting.<\/li>\n\n\n\n<li><strong>Ansible<\/strong> handles the &#8220;how,&#8221; logging into your servers via SSH and executing tasks without needing agents installed on the target machines.<\/li>\n<\/ul>\n\n\n\n<p>Here is what a robust, automated maintenance workflow looks like for a Linux environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Smart System Updates (Handling the &#8220;Reboot&#8221; Question)<\/h2>\n\n\n\n<p>The biggest fear in automation is an uncontrolled reboot. You don&#8217;t want a server restarting in the middle of the workday just because it installed a minor kernel patch.<\/p>\n\n\n\n<p>We script our Ansible playbooks to be &#8220;state-aware.&#8221; We don&#8217;t just tell the server to update; we tell it to update, check if a reboot is <em>actually<\/em> required, and then handle it according to your business rules.<\/p>\n\n\n\n<p>The Technical Logic:<\/p>\n\n\n\n<p>In a Debian\/Ubuntu environment, for example, we check for the existence of a specific file (\/var\/run\/reboot-required).<\/p>\n\n\n\n<p>Here is a snippet of what that logic looks like in our Ansible playbooks:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#d8dee9ff;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>- name: Update all packages to the latest version\n  apt:\n    update_cache: yes\n    upgrade: dist\n\n- name: Check if a reboot is required\n  stat:\n    path: \/var\/run\/reboot-required\n  register: reboot_required_file\n\n- name: Reboot server only if required and authorized\n  reboot:\n    msg: \"Reboot initiated by Ansible for system updates\"\n    connect_timeout: 5\n    reboot_timeout: 600\n    pre_reboot_delay: 0\n    post_reboot_delay: 30\n    test_command: whoami\n  when: reboot_required_file.stat.exists and allow_automatic_reboots | bool\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki nord\" style=\"background-color: #2e3440ff\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #ECEFF4\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">name<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">Update all packages to the latest version<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #8FBCBB\">apt<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">update_cache<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #81A1C1\">yes<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">upgrade<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">dist<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">name<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">Check if a reboot is required<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #8FBCBB\">stat<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">path<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">\/var\/run\/reboot-required<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #8FBCBB\">register<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">reboot_required_file<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #ECEFF4\">-<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #8FBCBB\">name<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">Reboot server only if required and authorized<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #8FBCBB\">reboot<\/span><span style=\"color: #ECEFF4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">msg<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #ECEFF4\">&quot;<\/span><span style=\"color: #A3BE8C\">Reboot initiated by Ansible for system updates<\/span><span style=\"color: #ECEFF4\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">connect_timeout<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">5<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">reboot_timeout<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">600<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">pre_reboot_delay<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">post_reboot_delay<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #B48EAD\">30<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">    <\/span><span style=\"color: #8FBCBB\">test_command<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">whoami<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D8DEE9FF\">  <\/span><span style=\"color: #8FBCBB\">when<\/span><span style=\"color: #ECEFF4\">:<\/span><span style=\"color: #D8DEE9FF\"> <\/span><span style=\"color: #A3BE8C\">reboot_required_file.stat.exists and allow_automatic_reboots | bool<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Why this matters:<\/strong> This ensures that if an update <em>doesn&#8217;t<\/em> require a restart, your services stay live without interruption. If it <em>does<\/em>, we can schedule that specific task for a 2:00 AM maintenance window automatically.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Enforcing Baselines and Cleanup<\/h2>\n\n\n\n<p>Over time, servers accumulate &#8220;junk&#8221;\u2014old kernels, orphaned packages, and massive log files. This is called &#8220;Configuration Drift.&#8221;<\/p>\n\n\n\n<p>We use Jenkins to run a &#8220;Baseline &amp; Cleanup&#8221; pipeline weekly. This ensures every server in your infrastructure matches the &#8220;Golden Image&#8221; standard.<\/p>\n\n\n\n<p><strong>The Cleanup Tasks:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Orphaned Packages:<\/strong> Removing dependencies that are no longer needed (e.g., <code>apt-get autoremove<\/code>).<\/li>\n\n\n\n<li><strong>Log Rotation:<\/strong> Ensuring <code>logrotate<\/code> is configured correctly so disk drives don&#8217;t fill up.<\/li>\n\n\n\n<li><strong>User Account Audit:<\/strong> Ensuring only active employees have SSH access (removing ex-employees automatically).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">3. Reporting and Visibility<\/h2>\n\n\n\n<p>Automation is scary if it\u2019s invisible. You need to know what changed.<\/p>\n\n\n\n<p>Because Jenkins is orchestrating the job, we can utilize its robust plugin ecosystem to generate reports. After the Ansible playbook finishes, Jenkins parses the output.<\/p>\n\n\n\n<p>What the Admin Sees:<\/p>\n\n\n\n<p>Instead of logging into 20 different servers to check their status, the Admin receives a single HTML email or a Slack notification containing:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Success\/Fail Status:<\/strong> Did any server fail to update?<\/li>\n\n\n\n<li><strong>Changes Made:<\/strong> A list of packages that were upgraded.<\/li>\n\n\n\n<li><strong>Disk Usage Stats:<\/strong> A warning if any drive is above 80% capacity.<\/li>\n\n\n\n<li><strong>Reboot Status:<\/strong> Which servers rebooted and confirmed they are back online.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">The Rainier IT Advantage<\/h2>\n\n\n\n<p>Whether you need us to manage this for you, or you need consulting to help your internal team set this up, we are here to help. We bring enterprise-level automation to SMBs in Orting, Puyallup, and Pierce County.<\/p>\n\n\n\n<p>Our approach is built on our proven <strong>4-Step Process<\/strong>:<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>Free Assessment:<\/strong> We audit your current infrastructure and update procedures.<\/li>\n\n\n\n<li><strong>Custom Proposal:<\/strong> We design an automation strategy using tools like Ansible and Jenkins.<\/li>\n\n\n\n<li><strong>Seamless Onboarding:<\/strong> We implement the code, test the backups, and go live.<\/li>\n\n\n\n<li><strong>Proactive Support:<\/strong> We monitor the pipelines 24\/7 to ensure they run flawlessly.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Stop Patching Manually. Start Automating.<\/h2>\n\n\n\n<p>Don&#8217;t let manual maintenance slow down your growth or put your security at risk. Let\u2019s modernize your infrastructure.<\/p>\n\n\n\n<p>Ready to streamline your IT?<\/p>\n\n\n\n<p>Call us at (206) 593-8072 or click below to schedule your consultation.<\/p>\n\n\n\n<p><a href=\"\/contact.html\" data-type=\"link\" data-id=\"\/contact.html\">[<strong>Schedule Your Free Assessment<\/strong>]<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>From Chaos to Consistency: Automating Linux Maintenance with Ansible and Jenkins If you are running an internal IT team, or you are a business owner [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":149,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,10,8],"tags":[28,27,12],"class_list":["post-147","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices","category-linux","category-managed-it-services","tag-ansible","tag-jenkins","tag-linux-2"],"_links":{"self":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts\/147","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/comments?post=147"}],"version-history":[{"count":8,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts\/147\/revisions"}],"predecessor-version":[{"id":158,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/posts\/147\/revisions\/158"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/media\/149"}],"wp:attachment":[{"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/media?parent=147"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/categories?post=147"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rainier-it.com\/blog\/wp-json\/wp\/v2\/tags?post=147"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}