Jenkins is an open-source automation server, mainly used for continuous integration and continuous delivery (CI/CD). It's extensible and widely used, so you can almost always find a plugin that fits your CI/CD or automation needs. This tutorial will show you how to install Jenkins using Civo and how to troubleshoot the installation. It will also show you how data persistence works for Jenkins in Civo. By the end of this tutorial, you will have enough knowledge that you can use to implement your own CI/CD system with Jenkins.

Prerequisites

Before starting this tutorial, you will need the following in place:

In addition to the tools, you need to have basic knowledge about Kubernetes Objects such as namespaces, pods, ingress, and ingress controllers.

Installing Jenkins using Civo Marketplace

To install Jenkins using the Civo Marketplace UI, login to your account on your dashboard and go to Kubernetes > Kubernetes cluster > Marketplace. You will have a screen, as shown below:

Installing Jenkins using Civo Marketplace

After you have this screen up, select the CI/CD tab under the Marketplace section and click the Jenkins option.

Scroll to the bottom of the page and click the Create cluster button. Wait a few minutes until your cluster's status is Running.

Running Jenkins using Civo Marketplace

Under the Cluster Information section, click the link to download your cluster's kubeconfig file. Once it's downloaded, take note of its file path. Open your terminal application and run the following command. Replace <download-file-path> with the actual file path.

$ export KUBECONFIG=<downloaded-file-path>

With that, any command that you run using kubectl moving forward will be run in the context of your newly created jenkins cluster. Run the following command to check. The output should be jenkins, your cluster name:

$ kubectl config current-context

Now, run the following command to check the namespaces in your cluster. Since you just installed Jenkins in your cluster, there should be a namespace named jenkins in the list of the namespaces:

$ kubectl get namespace
NAME            STATUS  AGE
kube-system     Active      31m
kube-public     Active      31m
kube-node-lease Active      31m
default             Active      31m
jenkins             Active      30m

If your Jenkins installation is successful, there should be a pod named jenkins-0 running in the jenkins namespace. Run the following command to check:

$ kubectl get pods -n jenkins
NAME        READY   STATUS  RESTARTS    AGE
jenkins-0   2/2         Running     0           34m

Accessing the Jenkins web UI

Now, you already have Jenkins running in your cluster, but you still can't access the Jenkins web UI. To access a pod running inside a Kubernetes cluster, you need to create an ingress object. This type of object is controlled by an ingress controller. If you recall, when you created the cluster, 3 applications were selected to be installed. One of them is traefik2-nodeport, which is an ingress controller. So, you already have an ingress controller running in your cluster.

Before creating an ingress, you need to find the DNS name for your Kubernetes cluster. To do this, open the details page of your cluster in the Civo dashboard. You can find the DNS name under the Cluster Information section. Take note of the DNS name.

Accessing the Jenkins web UI DNS Name

Create a file named ingress-jenkins.yaml, copy the following yaml code, and paste it into the newly created yaml file:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jenkins-ingress
  namespace: jenkins
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
  rules:
  - host: jenkins.<cluster-dns-entry>
    http:
       paths:
       - path: /
         pathType: Prefix
         backend:
           service:
             name: jenkins
             port:
               number: 8080
Note: Replace <cluster-dns-entry> in the host field with your cluster DNS name.

Use the kubectl and ingress-jenkins.yaml file to create the ingress object:

$ kubectl apply -f ingress-jenkins.yaml
ingress.networking.k8s.io/jenkins-ingress created

Now run kubectl get ingress -n jenkins to verify that an ingress object has been created. The output should show you the information about the ingress object you created.

$ kubectl get ingress -n jenkins
NAME            CLASS   HOSTS                                                       ADDRESS                                             PORTS   AGE
jenkins-ingress   <none>   jenkins.671d97a8-37df-4d01-81d6-58782b715386.k8s.civo.com   671d97a8-37df-4d01-81d6-58782b715386.k8s.civo.com   80     7s

Copy the URL under the HOSTS column for the jenkins-ingress object. Open the URL in your browser. It should now show you your Jenkins login page.

Jenkins web UI

You can get the login credentials information from the cluster details page in the Civo dashboard. Click the Installed Applications tab.

Installing Applications on Jenkins UI

You can find the login credentials under the Jenkins section.

Jenkins login credentials

Use the credentials to log into your Jenkins dashboard.

Sign in for Jenkins Dashboard

Congrats! Now, you have successfully logged into your Jenkins dashboard.

Creating a simple Jenkins job

To test your new Jenkins installation, let's create a new Jenkins job. On the Jenkins dashboard, click New Item.

Creating a simple Jenkins job

Type in hello-world for the name and choose Freestyle project as the type of the job. Click OK.

Creating a simple Jenkins job

In the configuration page, scroll down to the Build steps section and click Add build step. Click Execute shell as the type of the build step.

Execute Shell when Creating a simple Jenkins job

Type in echo "Hello, world!" inside the Command text area. Click Save.

Hello World task, Creating a simple Jenkins job

The page for hello-world Jenkins job will open up. The job is ready to be executed. Before you click the Build Now button to execute the job, open your terminal and run the following command:

$ watch kubectl get pods -n jenkins

By running the previous command, you can monitor the pods running inside jenkins namespace. Now, click the Build Now button on the hello-world Jenkins job page.

Jenkins job page

Under the Build History section, you will now see a new build with status pending.

Jenkins build history

Go back to your terminal. You will now see that there is a new pod with status ContainerCreating. This pod is created by Jenkins when you click the Build Now button. The hello-world job will be executed by this pod.

Jenkins test pod created

Because this is the first time you have executed a job in Jenkins, Kubernetes will need time to pull the image needed to execute the job. After a few minutes, the pod's status will change to Running.

Jenkins pod running

Once the status of the pod is Running, go back to your Jenkins UI. The job execution item under the Build History section should now show the date and time of the job and a status bar.

Jenkins status bar

Click on the date to open the job execution details page.

Jenkins job execution details page

Click Console Output on the left-side menu to view the output of the job execution. It should show you something like the following:

Jenkins output menu

At the bottom of the console output, you should see the simple script that you typed in the job configuration previously executed by Jenkins.

Jenkins job execution details page successful screen

Go back to your terminal. The pod created to run your Jenkins job is not in the list of running pods because it has been terminated by Kubernetes when the job is finished.

Jenkins job finished outcome

With that, you have successfully run a simple job on your Jenkins installation.

Jenkins data persistence

Since now your Jenkins server runs in a pod on a Kubernetes cluster, you might wonder whether its data will be persisted in case the pod is terminated or restarted by the cluster. The answer is yes, your Jenkins data persisted. When you created the cluster and installed Jenkins as one of the applications, the installation also set up the data persistence for you by creating a persistent volume claim object, and this object is used by the jenkins-0 pod.

You can run the following command to confirm that the jenkins-0 pod is indeed using a volume created from a persistent volume claim:

$ kubectl get pods -n jenkins -o jsonpath='{.spec.volumes[?(@.name=="jenkins-home")]}' jenkins-0

The previous command prints the information about a volume named jenkins-home inside the jenkins-0 pod. The output should be a JSON object like the following:

{"name":"jenkins-home","persistentVolumeClaim":{"claimName":"jenkins"}}

What the output tells you is that a volume named jenkins-home is created using a persistent volume claim named jenkins. Using kubectl, you can get the information about this persistent volume claim:

$ kubectl get persistentvolumeclaim -n jenkins
NAME    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
jenkins   Bound pvc-eb86b9ef-15ee-44bb-ae22-4c31aa3312d1   10Gi     RWO         civo-volume 24h

The output should tell you that there is a persistent volume claim named jenkins. Its size is 10 GB, just like the plan that you chose for Jenkins installation when you created the cluster. Under the VOLUME column is the name of the volume created for your Jenkins data. You can check that the volume exists by checking the volume lists on the Civo dashboard.

Jenkins data persistence

The information on that page shows you that the volume is attached to Kubernetes: jenkins, and the size is 10 GB. The name of the volume should match the name from the kubectl command output previously.

Test data persistence

To check whether your Jenkins data really persisted, you can try to kill the jenkins-0 pod by running the following command:

$ kubectl delete pod -n jenkins jenkins-0

As soon as you execute the previous command, the jenkins-0 pod's status will change to Terminated, but it will change back to Init:0/2. This is because the jenkins-0 is controlled by another Kubernetes object called StatefulSet. Because of this stateful set, anytime the jenkins-0 is terminated, Kubernetes will create a new pod with the same name and configuration. Run the following command to monitor the progression of the jenkins-0 pod created automatically by Kubernetes to replace the previous pod that you just deleted:

$ watch kubectl get pods -n jenkins

Test data persistence

You will have to wait until the jenkins-0 pod returns to Running status. While the status is not Running, you will not be able to access the Jenkins UI.

Running Test data persistence

It will come back to running after all the pod initialization process is finished.

Jenkins pod initialization process finished

Now that the jenkins-0 pod is back to running state, using your browser, access your Jenkins dashboard. You will be asked to re-login.

After logging in, you will see that the hello-world job that you created still exists.

Jenkins job creation screen

If you click on the job, you will see that the build history data still exists. So does the console output of the job execution previously.

Jenkins build history

Jenkins build history

With this, you have confirmed that the data persistence in your Jenkins installation works.

Cleaning up

To clean up the resources that you created in this tutorial, go back to your Civo dashboard and access the Kubernetes clusters page. Click the X button at the right side of your cluster item.

Cleaning up Jenkins resources

Type in your cluster name on the pop-up confirmation dialog and click Delete.

Cleaning up Jenkins resources delete

Deleting your cluster will not automatically delete the volume storage used for your Jenkins, and the volume will incur some fee. To delete it, access the volumes page on your Civo dashboard.

Cleaning up Jenkins resources Dashboard view

You might not see the Actions drop-down on your volume item if you access the page immediately after you delete your cluster. This is because the cluster deletion process is still ongoing. Wait for a few minutes and refresh the page. You should now see the drop-down. Click it and then click delete. A confirmation dialog will pop up. Copy your volume name, paste it into the name field, and click Delete.

Cleaning up Jenkins resources

With that, all the resources created for this tutorial have been deleted.

Summary

In this tutorial, you have learned how to install Jenkins in your Kubernetes cluster and make it accessible from outside the cluster. You have also created a very simple Jenkins job using your new Jenkins installation. Lastly, you have learned how data persistence works in your Jenkins installation and tested it by deleting your Jenkins pod.

If you are interested in learning more about this topic, check out some of these additional resources:

  • Installing Jenkins on Kubernetes: This is the official guide on Jenkins docs on installing Jenkins on Kubernetes. It shows you multiple ways to do it, and by learning it this way, you can learn in detail how Jenkins installations on Kubernetes actually works.
  • Kubernetes plugin for Jenkins: This plugin is automatically installed when you install Jenkins on Kubernetes. Behind the scenes, this plugin is responsible for allocating the Jenkins agent to execute your build.
  • Kaniko: A tool to build container images inside a Kubernetes cluster. You might need to build a docker image in your CI/CD pipeline. While it's possible to run Docker inside a Jenkins pod, it's not a good practice from a security point of view. For this purpose, you can use Kaniko.