Website Deployment using Kubernetes through Jenkins using Groovy script.

We have seen a lot of things with Jenkins, Kubernetes and have deployed the websites using these tools and it really do give a lot many great features. Moreover, technology has unlimited corners and its widening in the blink of an eye and there are many such features been continuously added to upgrade our lives by making things easy. In this article, I will be discussing about one such feature which is more feasible to use Jenkins, i.e Groovy script. It’s a very powerful language and has a capability to do anything practically.

It reads the files in which Jenkins master has access to on the host. Groovy is used as a scripting language for Java offering many active features like DSL support, dynamic typing, etc. Earlier, we used to create freestyle jobs and then configure, build it. We used to create Jenkins pipeline for job execution, here, we can use Jenkinsfile in this case.

So, its an object oriented programming language, mainly used for Java platform which manages Jenkins pipeline, where we can use different languages together. Groovy is and agile and dynamic language having seamless integration with all java objects and libraries. Let’s move towards the task execution. I’ve attached the screenshots of steps that I followed to complete the task.

I’ve used technologies like Github, Docker, Jenkins, Kubernetes, Groovy. Java and Groovy has a same syntax. I created a Dockerfile, groovy file for Jenkins named Jenkins.groovy and a normal php or html file for testing, PVC and service file for deployment purpose. I will list out the codes of all those files below-

Dockerfile-

FROM centos:latest

RUN cd /usr/local/bin && curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl && \
  chmod +x kubectl &&\
  mkdir /root/task && \
  yum -y install java-11-openjdk-devel && \
  yum -y install wget && \
  rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key  && \
  wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo && \
  yum install -y initscripts &&\
  yum install sudo -y &&\
  yum install net-tools -y &&\
  yum install git jq -y && \
  mkdir /root/YML &&\
  yum install jenkins -y && \
  sed -i '100i\jenkins ALL=(ALL)       NOPASSWD: ALL ' /etc/sudoers

COPY ca.crt client.key client.crt /root/
COPY config /root/.kube
COPY php.yml pvc.yml service.yml /root/YML/

EXPOSE 8080


CMD ["java", "-jar", "/usr/lib/jenkins/jenkins.war"]

Groovy code-

job('Job-1') {
    scm {
        github('Shreya-cyber/Devops6','master')
    }
    steps{
        shell('sudo cp -rvf * /root/task')
    triggers {
        upstream('JOB DSL', 'SUCCESS')
    }
    }


    }


//-----------------------------------------------------------JOB-2-------------------------------------------------------------------------


job('JOB-2') {


steps {
        shell('''#!/bin/bash
cd /root/task/


output=$(find -name "*.php")


if [[ $output == *".php"* ]]; then


    kubectl apply -f /root/YML/pvc.yml 
    kubectl apply -f /root/YML/php.yml
    sleep 25
	kubectl get pods --output json > /root/pods.json
	parser=$(jq  -r ".items[]?.status.containerStatuses[]?.ready" /root/pods.json)
	if [[ $parser == *"true"* ]]; then
          trans=$(jq -r  ".items[].metadata.name" /root/pods.json) #parsing 
      	  kubectl cp /root/task/*.php $trans:/var/www/html  #paste file in container 
      	  kubectl apply -f /root/YML/service.yml # service creation 
          kubectl get all --output json > /root/pods.json
      
	else
      echo "NO"
	fi
fi


#optional
jq  -r  ".items[]?.status.containerStatuses[]?.ready" /root/pods.json 
jq  -r  ".items[].metadata.name" /root/pods.json


port=$(jq  -r ".items[2]?.spec.ports[].nodePort" /root/pods.json) #store value
ip=$(jq -r ".items[]?.status.hostIP //empty " /root/pods.json)


echo $ip:$port # pass this into new job ''')
   triggers {
        upstream('Job-1', 'SUCCESS')
    }
    }
}
//----------------------------------------------------------JOB-3------------------------------------------------------------------------


job('JOB-3') {


   


    steps{
        shell('''port=$(jq -r ".items[2]?.spec.ports[].nodePort" /root/pods.json)
ip=$(jq -r ".items[]?.status.hostIP //empty " /root/pods.json)
if curl -s --head --request GET http://$ip:$port | grep "200 OK" > /dev/null; then
   echo "Working"
else
      curl http://192.168.198.128:1999/job/JOB-4/build?token=redhat --user admin:redhat
      exit 1
fi ''')


triggers {
        upstream('JOB-2', 'SUCCESS')
}
    }


    }
//--------------------------------------------------------------JOB-4----------------------------------------------------------------------
job('JOB-4') {
    authenticationToken('redhat')
	  publishers {
	        extendedEmail {
	            recipientList('shreya02santoshwar@gmail.com')
	            defaultSubject('Job status')
	            defaultContent('Status Report')
	            contentType('text/html')
	            triggers {
	                always {
	                    subject('build Status')
	                    content('Body')
	                    sendTo {
	                        developers()
	                        recipientList()
	                    }
			       }
		       }
		   }
	  }
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++BUILD_PIPELINE+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++====
buildPipelineView('project-A') {
    filterBuildQueue()
    filterExecutors()
    title('Project A CI Pipeline')
    displayedBuilds(5)
    selectedJob('Job-1')
    alwaysAllowManualTrigger()
    showPipelineParameters()
    refreshFrequency(60)
}

Service –

apiVersion: v1 
kind: Service 
metadata: 
    name: mysvc
spec:
  type: NodePort
  selector:
     type: php
  ports:
  - port:  80
    nodePort: 30300
    
    protocol: TCP 

PVC-

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: php-html-vol1
  labels:
    name: data-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: log-vol2
  labels:
    name: logpvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

After saving all the files in one folder, I have uploaded the Groovy code and php code to Github, so that my Jenkins job will fetch the code after building. I have added the rest files to redhat root directory using Winscp.

No alt text provided for this image
No alt text provided for this image

Below is my Dockerfile, this will create a container image that has Jenkins installed in it. It will download all the required files needed for Jenkins setup. Then it will copy the cert files for configuring Kubernetes. After the image is created, you can launch the container where you will get Jenkins and Kubernetes readily available. 

No alt text provided for this image

Use the command for building an image-

# docker build -t jenkins6:v1 /root

Jenkins6 will be the name of my image having v1 as version 1. /root is the path of where my Dockerfile resides.

No alt text provided for this image
No alt text provided for this image

Image is been created successfully. Now, we are ready to launch a container and execute the task. Its more fun now! After you launch the container by using command-

# docker run -it –name <container_name> -p <port no.> :8080 <image_name>

Container name would be of your choice. You have to assign any port no. where your Jenkins will be running, eg: 8088:8080. Jenkin runs on default port no 8080, so we have to use it for assigning port no. 8088, so your container will be exposed in outside world, and you are free to use it from browser. Image name will be the image you created. Finally, go to the assigned port and configure Jenkins.

You will be asked to download some plugins, so I am listing some names below to install-

Build pipeline, Email Extension, Job-DSL, Github, etc.

Initially, you might not get some of the plugins available, but after configuring the Jenkins, and when you are done with username and password setup, you can go to the Manage Jenkins section and can install the rest plugins.

No alt text provided for this image

Configure your port no. and proceed ahead.

No alt text provided for this image

Your Jenkins is ready and finally you are good to go!

No alt text provided for this image

After you are done installing all the plugins, first we will create a Seed Job in Jenkins, which will fetch the Github repository for the groovy file. Its important to have Job-DSL plugin installed completely, or else this task will not be executed. Job-DSL plugin generally used for managing Jobs through Groovy. In the seed job select the Job-DSL from the > build drop-down section. 

No alt text provided for this image

Add your github repo here. 

No alt text provided for this image

Add the DSL script and keep everything default. Apply and save it.

No alt text provided for this image

Apparently it will show you error when you build the job because we have not approved the groovy script. To approve go to Manage Jenkins > In-process Script Approval.

No alt text provided for this image
No alt text provided for this image

Click on Approve and then run the job again. You will see new jobs come up automatically on your dashboard.

No alt text provided for this image
No alt text provided for this image

Lets move ahead with Job-1-

Everything will be pre-created and the code will also be fetched from the github repo as you save it. It will also copy the code from Jenkins and will paste it in the directory that we mention. 

No alt text provided for this image

See the console output, the job is build successfully.

No alt text provided for this image

In Job-2, we need to choose the container type according to the code developer push. So we create multiple containers are we are not knowing which code will be fetched. We have used jq here which will fetch the data from JSON file. It fetches a required value from pods.json, and I need Status of Deploymentof K8s. if its true then it’ll go inside those conditions and it contains one more condition which provide k8s pod name to $trans variable which also exposes the pod to outside world. It will also store the ip and port of the pod exposed in the $ip and $port. You will get to see all this after the job is built successfully. Check the console output-

No alt text provided for this image

Job-3 tests the working of ip and port that pod gives and if it does not work then it triggers the next job. If the website is working then the job stops. It has a code which retrieve data from json and store it.  

No alt text provided for this image
No alt text provided for this image

Job-4- In my case, website was running well so it wont send me any mail. But in case your website is not been working, it sends the email to debveloper. Email plugin helps us in this setup. 

No alt text provided for this image

This is how my dashboard looks after successful build of all the jobs. 

No alt text provided for this image

The website is also running well. 

No alt text provided for this image

Check whether the pods are running just to re-verify by the cmd shown in the image. You can also view the status of all the pods. I’ve used deployment so in case my pod fail to work, automatically replicas will be launched so that website will run smoothly. 

No alt text provided for this image

So, this is how I executed the task.

Thank you for reading, stay safe and happy learning!

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s