How To Install Jenkins On A Kubernetes Cluster

Introduction

Jenkins is a CI tool ( continuous integration) that automates a large portion of the software development process. Several development teams working on multiple projects in a complex microservices environment can be a strain on limited resources.  In this tutorial, you will learn how to install Jenkins and create a CI/CD pipeline.

Prerequisites

  • Docker installed on your server.
  • A Kubernetes cluster.
  • Root privileges.

Jenkins Installation On Kubernetes

Jenkins installation is consisting of 5 steps:

        1. Namespace creation for the Jenkins Deployment

          To isolate our Jenkings deployment from the rest of the namespaces that might exist (dev, staging, production) a separate namespace will provide the essential layer of isolation we need to our environment. Create a namespace for your Jenkins deployment by executing the following command on your terminal:

          kubectl create namespace jenkins

          You will see the output:

          namespace/jenkins created

          And if you execute:

          kubectl get namespaces

          You will see:

          NAME                   STATUS   AGE
          default                Active   11d
          jenkins                Active   2m34s
          kube-node-lease        Active   11d
          kube-public            Active   11d
          kube-system            Active   11d
          kubernetes-dashboard   Active   11d
        2. Create a Jenkins Service Account, Role, and Rolebinding.

          Now that we have created our namespace, we shall create a jenkins-service-account.yaml file. The service account, the role, and the role binding are all necessary for Jenkins to be able to have the appropriate permissions to connect to the cluster, create new pods, delete pods etc:

          apiVersion: v1
          kind: ServiceAccount
          metadata:
            name: jenkins
            namespace: jenkins
          ---
          kind: Role
          apiVersion: rbac.authorization.k8s.io/v1
          metadata:
            name: jenkins
            namespace: jenkins
          rules:
          - apiGroups: [""]
            resources: ["pods"]
            verbs: ["create","delete","get","list","patch","update","watch"]
          - apiGroups: [""]
            resources: ["pods/exec"]
            verbs: ["create","delete","get","list","patch","update","watch"]
          - apiGroups: [""]
            resources: ["pods/log"]
            verbs: ["get","list","watch"]
          - apiGroups: [""]
            resources: ["events"]
            verbs: ["watch"]
          - apiGroups: [""]
            resources: ["secrets"]
            verbs: ["get"]
          ---
          apiVersion: rbac.authorization.k8s.io/v1
          kind: RoleBinding
          metadata:
            name: jenkins
          roleRef:
            apiGroup: rbac.authorization.k8s.io
            kind: Role
            name: jenkins
          subjects:
          - kind: ServiceAccount
            name: jenkins


          Save the file and exit. Now we will apply to this service account and rules to the Jenkins namespace we already created. Execute the command:

          kubectl apply -n jenkins -f jenkins-service-account.yaml

          As you noticed, we deployed the Jenkins service account into the Kubernetes Jenkins namespace.

        3. Create Jenkins Services.

          Now we need to create the appropriate Services. A Kubernetes Service is an abstraction that exposes an application (in our case Jenkins pod(s) )to the Internet.

          We will create 2 services. The first one will have a type NodePort for exposing Jenkins user interface to us at port 32000, and a second Service which will handle all the internal workins. Create a file jenkins-services.yaml file, as shown below:

          apiVersion: v1
          kind: Service
          metadata:
            name: jenkins-ui
          spec:
            type: NodePort
            selector:
              app: jenkins
            ports:
              - port: 8080
                targetPort: 8080
                nodePort: 32000
            selector:
              app: jenkins
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: jenkins
            labels:
              app: jenkins
          spec:
            type: ClusterIP
            ports:
              - name: jenkins-ui
                port: 8080
                targetPort: 8080
                protocol: TCP
              - name: jenkins-agent
                port: 50000
                protocol: TCP
              - name: http
                port: 80
                targetPort: 8080
            selector:
              app: jenkins

          In the next step, we will apply our Services to the Cluster.

        4. Deploy Jenkins Services

          Now that everything is in place, it’s time to see our services taking shape:

          kubectl apply -n jenkins -f jenkins-services.yaml
        5. Create a Jenkins Stateful Set

          This is basically the core of Jenkins deployment. Like a Kubernetes Deployment, a StatefulSet manages Pods that are based on an identical container specification. Unlike a Deployment, a StatefulSet maintains a sticky identity for each of their Pods. These pods are created from the same specifications, but are not interchangeable: each one of them is having a persistent identifier which is maintained unchanged across any rescheduling or server restarts. StatefulSets are a very important Kubernetes function for applications requiring stable, unique network identifiers, stable and persistent storage, graceful deployment, automated rolling updates, and horizontal scaling.
          Let’s create a file jenkins-stateful.yaml, with the following content:

          apiVersion: apps/v1
          kind: StatefulSet
          metadata:
            name: jenkins
          spec:
            selector:
              matchLabels:
                app: jenkins # has to match .spec.template.metadata.labels
            serviceName: jenkins
            replicas: 1
            template:
              metadata:
                labels:
                  app: jenkins
                  name: jenkins
                name: jenkins
              spec:
                serviceAccountName: jenkins
                terminationGracePeriodSeconds: 10
                containers:
                - env:
                  - name: JAVA_OPTS
                    value: -Xmx2048m -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85
                  name: jenkins
                  image: jenkins/jenkins:lts-alpine
                  ports:
                  - containerPort: 8080
                    name: jenkins
                  - containerPort: 50000
                    name: jenkins-agent
                  volumeMounts:
                  - name: jenkins-home
                    mountPath: /var/jenkins_home
                volumes:
                  - name: jenkins-home
                    emptyDir: {}
        6. Apply Jenkins Stateful Set

          Apply the above stateful set using the command:

          kubectl apply -n jenkins -f jenkins-stateful.yaml
        7. Open Jenkins In Your Browser.

          Visit Http://<node_address>:32000 in your browser to open the initial Jenkins setup wizard.
          At that point, you will need the auto-generated password that Jenkins created. This can be found easily but checking the Kubernetes logs for the jenkins-0 pod that is currently running.
          This can be done by issuing the commands:

          kubectl get pods -n jenkins

          Output:

          NAME       READY   STATUS    RESTARTS   AGE
          jenkins-0   1/1     Running   0          2h

          And,

          kubectl logs jenkins-0 -n jenkins

          Output,

          2020-05-23 13:01:26.939+0000 [id=25]	INFO	o.s.b.f.s.DefaultListableBeanFactory#preInstantiateSingletons: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@64487588: defining beans [filter,legacy]; root of factory hierarchy
          2020-05-23 13:01:27.129+0000 [id=25]	INFO	jenkins.install.SetupWizard#init: 
          
          *************************************************************
          *************************************************************
          *************************************************************
          
          Jenkins initial setup is required. An admin user has been created and a password generated.
          Please use the following password to proceed to installation:
          
          ae7e043ee34047be8f7d84fd59b9586b
          
          This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
          
          *************************************************************
          *************************************************************
          *************************************************************
          
          2020-05-23 13:01:36.346+0000 [id=25]	INFO	jenkins.InitReactorRunner$1#onAttained: Completed initialization
          2020-05-23 13:01:36.351+0000 [id=19]	INFO	hudson.WebAppMain$3#run: Jenkins is fully up and running
          2020-05-23 13:01:36.579+0000 [id=39]	INFO	h.m.DownloadService$Downloadable#load: Obtained the updated data file for hudson.tasks.Maven.MavenInstaller
          2020-05-23 13:01:36.580+0000 [id=39]	INFO	hudson.util.Retrier#start: Performed the action check updates server successfully at the attempt #1
          2020-05-23 13:01:36.582+0000 [id=39]	INFO	hudson.model.AsyncPeriodicWork#lambda$doRun$0: Finished Download metadata. 10,521 ms

          Copy the password and past it to the appropriate field. By continuing the setup, you will be asked to create a new user account and create and another one.