{"id":880,"date":"2024-07-17T01:41:00","date_gmt":"2024-07-17T01:41:00","guid":{"rendered":"https:\/\/blog.ngocha.biz\/?p=880"},"modified":"2024-07-17T01:41:00","modified_gmt":"2024-07-17T01:41:00","slug":"setup-highly-available-jenkins","status":"publish","type":"post","link":"https:\/\/blog.ngocha.biz\/?p=880","title":{"rendered":"How To Setup Highly Available Jenkins"},"content":{"rendered":"<p>This blog will discuss setting up a <strong>Highly available Jenkins<\/strong> using the open-source version.<\/p>\n<p>Before getting into the high availability discussion, you first need to understand how Jenkins manages its data and the high-level architecture.<\/p>\n<p>If you are not aware of the architecture, I highly suggest reading <a href=\"https:\/\/devopscube.com\/jenkins-architecture-explained\/\" rel=\"noreferrer noopener\">Jenkins architecture <\/a>post.<\/p>\n<h2 id=\"types-of-jenkins-ha-setup\">Types of Jenkins HA Setup<\/h2>\n<p>There is no direct way of setting up Jenkins in High availability mode due to how Jenkins manages its data.<\/p>\n<p>Jenkins manages its <strong>data in a flat-file (xml)<\/strong>, and you can have only one instance of the master node that can read the Jenkins data.<\/p>\n<p>Because of which, running multiple replicas of the <strong>Jenkins master in an active-active<\/strong> configuration (where all replicas are actively processing jobs) is not officially supported<\/p>\n<p>For example, if you try to configure multiple master nodes with a shared volume, you will have inconsistent reads and writes that lead to unstable Jenkins.<\/p>\n<p>There are two ways you can have Jenkins in HA mode.<\/p>\n<ol>\n<li><strong>Jenkins active-actice\/active-passive setup: <\/strong>Only <a href=\"https:\/\/docs.cloudbees.com\/docs\/cloudbees-ci\/latest\/ha\/ha-fundamentals?ref=devopscube.com\">enterprise Jenkin<\/a>s comes with a supported plugin to have this setup. But most organizations use open-source versions, and his option is out of scope. Also, there is an option with HAproxy, however, I think it&#8217;s a bit of administrative overhead.<\/li>\n<li><strong>Jenkins HA setup in autoscaling Group: <\/strong>Having Jenkins in the autoscaling group is a workaround to have a highly available Jenkins. It is not a 100% HA solution; however, for any reason if your Jenkins server crasher, another instance will come up within a short period. This will work on both VM and Kubernetes based Jenkins setup<\/li>\n<\/ol>\n<h2 id=\"jenkins-ha-setup-with-autoscaling-group\"><strong>Jenkins HA Setup With Autoscaling Group<\/strong><\/h2>\n<p>You can call this method a <strong>poor man&#8217;s solution for Jenkins HA.<\/strong> Because, when an instance goes down, there are a few minutes of downtime for another instance to come up (vm + java service startup time).  But it works \ud83d\ude42<\/p>\n<p>This method will work on any private\/public cloud platform with the option of autoscaling.<\/p>\n<p>This method is similar to <a href=\"https:\/\/devopscube.com\/setup-jenkins-on-kubernetes-cluster\/\" rel=\"noreferrer noopener\">deploying Jenkins on Kubernetes<\/a>, where if the Jenkins pod goes down, another pod will come up with the same data.<\/p>\n<p>Instead of a pod, it&#8217;s a VM., so the startup time takes more time than spinning up a new pod.<\/p>\n<p>Let&#8217;s look at the high-level architecture of the Jenkins HA setup using an autoscaling group.<\/p>\n<figure class=\"kg-card kg-image-card kg-card-hascaption\"><img decoding=\"async\" src=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-1.png\" class=\"kg-image\" alt=\"Jenkins HA Setup\" loading=\"lazy\" width=\"1665\" height=\"1713\" srcset=\"https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w600\/2025\/03\/jenkins-1.png 600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1000\/2025\/03\/jenkins-1.png 1000w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/size\/w1600\/2025\/03\/jenkins-1.png 1600w, https:\/\/storage.ghost.io\/c\/5f\/2f\/5f2f4d20-2abf-4534-8d40-7aa233aedd43\/content\/images\/2025\/03\/jenkins-1.png 1665w\" sizes=\"auto, (min-width: 720px) 720px\"><figcaption><span style=\"white-space: pre-wrap;\">Click to view in HD<\/span><\/figcaption><\/figure>\n<p>Here the concept is pretty simple.<\/p>\n<ol>\n<li>Jenkins is deployed in an autoscaling group with min and max one count. It ensures we have only one instance of Jenkins running all the time.<\/li>\n<li>Then, we have a dedicated external disk to hold the Jenkins data. It could be a separate volume or an NFS share. The autoscaling image startup script (AMI user data) gracefully attaches this disk when it comes up.<\/li>\n<li>If the active Jenkins instance goes down, the autoscaling policies will bring up another instance while terminative the inactive one. In this process, the data disk gets detached from the terminating instance gracefully (in AWS using lifecycle hooks) and gets attached to the new instance, preserving the previous Jenkins state and data.<\/li>\n<li>All the existing jobs will fail during downtime or continue when a new instance comes up.<\/li>\n<\/ol>\n<p>This setup also makes the upgrade and patching process so easy.<\/p>\n<h2 id=\"ha-setup-on-kubernetes\"><strong>HA Setup<\/strong> on Kubernetes<\/h2>\n<p>When deployed in Kubernetes, It should be deployed via StatefulSet. Also, wee need to keep the StatefulSet replica as one and the J<strong>enkins data directory should be mounted to the a Persistent Volume<\/strong> to store Jenkins data (e.g., job history, plugins, configurations).<\/p>\n<p>This ensures data persists even if the Jenkins master pod is rescheduled or restarted.<\/p>\n<h2 id=\"horizontal-scaling-for-agents\">Horizontal Scaling For Agents<\/h2>\n<p>A good news is, you can scale Jenkins agents horizontally.<\/p>\n<p>There are several ways to scale Jenkins agents. In this method, the agents are dynamically provisioned and terminated once the build is completed.<\/p>\n<p>For example,<\/p>\n<ol>\n<li><a href=\"https:\/\/devopscube.com\/jenkins-build-agents-kubernetes\/\">Scaling Agents with Kubernetes pods<\/a><\/li>\n<li><a href=\"https:\/\/devopscube.com\/docker-containers-as-build-slaves-jenkins\/\">Scaling Agents with Docker<\/a><\/li>\n<li>Scaling Agents with ec2 instances.<\/li>\n<\/ol>\n<h2 id=\"jenkins-ha-setup\">Jenkins HA Setup<\/h2>\n<p>If you want to try this setup on the AWS cloud, you can use my Documentation.<\/p>\n<p>I have documented the whole setup for AWS here -&gt; <a href=\"https:\/\/devopscube.com\/jenkins-autoscaling-setup\/\">Jenkins HA Setup Using AWS Autoscaling Group<\/a><\/p>\n<p>The <a href=\"https:\/\/devopscube.com\/infrastructure-as-code-configuration-management\/\">IaC<\/a> code for the setup is present in the <a href=\"https:\/\/devopscube.com\/devops-projects\/\">DevOps Projects<\/a> Githup Repo<\/p>\n<pre><code>https:\/\/github.com\/techiescamp\/devops-projects<\/code><\/pre>\n<p>Do try out this setup and see if it works for you.<\/p>\n<p>Also, you should <a href=\"https:\/\/devopscube.com\/jenkins-backup-data-configurations\/\" rel=\"noreferrer noopener\">backup jenkins data<\/a> periodically using plugins and disk snapshots. You can easily restore a working version if you have all the data backup.<\/p>\n<p>If you are new to Jenkins, check out our <a href=\"https:\/\/devopscube.com\/jenkins-2-tutorials-getting-started-guide\/\" rel=\"noreferrer noopener\">Jenkins tutorial for beginner<\/a>s.<\/p>\n<hr>\n<p><strong>Ngu\u1ed3n:<\/strong> <a href=\"https:\/\/devopscube.com\/setup-highly-available-jenkins\/\" target=\"_blank\" rel=\"noopener noreferrer\">How To Setup Highly Available Jenkins \u2014 DevOpsCube<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Source: https:\/\/devopscube.com\/setup-highly-available-jenkins\/<\/p>\n","protected":false},"author":1,"featured_media":881,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-880","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops"],"_links":{"self":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/880","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=880"}],"version-history":[{"count":0,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/posts\/880\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=\/wp\/v2\/media\/881"}],"wp:attachment":[{"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=880"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=880"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ngocha.biz\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=880"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}