Namaste Everyone !! In my earlier task, I had launched a server on Kubernetes using the Jenkins GUI.
Link to that project - https://github.com/sparshpnd23/DevOps-Task-3-Integrating-Jenkins-with-Kubernetes-.git
In this project, the motive is to do the same but using the Groovy code & Kubernetes YML files.
#What is Groovy ?
Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax. It integrates smoothly with any Java program, and immediately delivers to your application powerful features, including scripting capabilities, Domain-Specific Language authoring, runtime and compile-time meta-programming and functional programming.
We know that Jenkins is a Java based application. So, here I'll integrate Groovy with jenkins to create all the Jenkins tasks through a Groovy code.
#About the Project -
The key points of the project are : 1- Creation of a container image that has Jenkins installed using Dockerfile. 2- On launching the image, Jenkins should auto start. 3- Creation of the following tasks in that Jenkins using Groovy code :-
Production : This task will auto download the code from github whenever any new code is pushed.
Deployment : A suitable Kubernetes pod will be launched automatically & the code will be auto deployed. Ex- If the code is in php, the program will auto detect and launch a php pod and deploy the code. The pod will be auto exposed & the data will be persistent as a dynamic PVC will be attached to ensure that no data is lost in case of container crash.
Testing : The Deployed code will be automatically tested and if the page isn't working, an email will be automatically sent to the devdeloper. The pod will be redeployed after the developer has corrected the code.
Monitoring : Since we are using a Replica Set, hence we need not worry about pod monitoring. If the pod goes down, the Replica Set will automatically relaunch it based on the labels.
Step - 1: I have created a container image that has Jenkins installed using Dockerfile.
The commands in Dockerfile are as follows--
I have used Centos latest version. We need to install sudo & wget because they will be furthur needed in the installation of Jenkins. Then we have installed Jenkins & the suitable jdk version. Since systemctl doesn't work in Centos, so we would require to use sudo service jenkins start command. But service command isn't avvailable in Centos latest image. So, we have installed /sbin/service We have also installed git because we'll need it later. The third last line is to give powers to jenkins to perform operations inside the container. The, we have started the Jenkins by sudo service jenkins start but we also need to start /bin/bash otherwise the container will close as soon as jenkins starts because there will be no tasks left. Hence, we also start the bash in same coomand.
Note : The bash has to be started in the same command because if there are more than one commands in the Dockerfile, then only the last command runs.
After that, we have exposed Port 8080 because Jenkins runs on port 8080.
Build an image from this Dockerfile using docker build -t NAME:TAG /location of Dockerfile/
Run a container from your newly built image & expose it to any available port using PAT.
Ex- docker run -it -p 2301:8080 --name jenpro jentest:v5
**Now, before moving on to the building Jenkins tasks through Groovy code, we first need to setup some YML files for our Server deployment on Kubernetes, which will be needed later.
Step -2: Create a Dockerfile to launch the server. Now, when I had done this task using the Jenkins GUI earlier, I had checked the downloaded code & launched a suitable container. Here also, I'll consider 2 cases - If the downloaded code is in html, then the deployment will be created using the first image. If the code is in php, then the deployment will be created using the second image. You can also create a single image & install all the necessary programs in it, be it html, java, php or python, but here, to show that we can make a choice, I'll create two separate images for html & php.
HTML DOCKERFILE
FROM centos:latest
RUN yum install httpd -y
COPY *.html /var/www/html/
CMD /usr/sbin/httpd -DFOREGROUND && /dev/bash
PHP DOCKERFILE
FROM centos:latest
RUN yum install httpd -y
RUN yum install php -y
COPY *.php /var/www/html/
CMD /usr/sbin/httpd -DFOREGROUND && /dev/bash
Step -2:: Creating a PV & PVC which will be used later by the server pod.
FOR HTML
Persistent Volume -
apiVersion: v1
kind: PersistentVolume
metadata:
name: server-pv-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/sdr/data/website"
Now, create a PV using the command -
kubectl create -f server-pv-vol.yml
Persistent Volume Claim -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: server-pv-vol-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
We claim the storage from the PV by creating this PVC file using the following command -
kubectl create -f server-pv-vol-claim.yml
FOR PHP
Persistent Volume -
apiVersion: v1
kind: PersistentVolume
metadata:
name: phpserver-pv-vol
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/sdr/data/website"
Now, create a PV using the command -
kubectl create -f phpserver-pv-vol.yml
Persistent Volume Claim -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: phpserver-pv-vol-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
We claim the storage from the PV by creating this PVC file using the following command -
kubectl create -f phpserver-pv-vol-claim.yml
Step - 3: Creating a Deployment for the server.
FOR HTML
apiVersion: apps/v1
kind: Deployment
metadata:
name: server-deploy
labels:
app: webserver
spec:
replicas: 5
selector:
matchLabels:
app: webserver
template:
metadata:
name: server-deploy
labels:
app: webserver
spec:
volumes:
- name: server-pv-vol
persistentVolumeClaim:
claimName: server-pv-vol-claim
containers:
- name: html-deploy
image: server:v1
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: "/var/log/httpd"
name: server-pv-vol
FOR PHP
apiVersion: apps/v1
kind: Deployment
metadata:
name: phpserver-deploy
labels:
app: webserver
spec:
replicas: 5
selector:
matchLabels:
app: webserver
template:
metadata:
name: phpserver-deploy
labels:
app: webserver
spec:
volumes:
- name: phpserver-pv-vol
persistentVolumeClaim:
claimName: phpserver-pv-vol-claim
containers:
- name: phpserver-deploy
image: phpserver:v1
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: "/var/log/httpd"
name: phpserver-pv-vol
Step - 4: Creating a service to expose the Pod to the outside world using type=NodePort.
apiVersion: v1
kind: Service
metadata:
name: expose
spec:
type: NodePort
selector:
app: webserver
ports:
- port: 80
targetPort: 80
nodePort: 2301
Now, it's time to move on to Groovy to create our Jnekins tasks
Step -5: Task -1 - PRODUCTION
This will download the code from the mentioned Github repo, check the extension to identify whether the code is in html or php. Then, it will push the suitable image to docker hub so that it can be used later.
job("production") {
steps {
scm {
github("sparshpnd23/face-recog-by-transfer-learning", "master")
}
triggers {
scm("* * * * *")
}
shell("sudo cp -rvf * /sparsh")
if(shell("ls /sparsh/ | grep html")) {
dockerBuilderPublisher {
dockerFileDirectory("/sparsh/")
cloud("docker")
tagsString("server:v1")
pushOnSuccess(true)
fromRegistry {
url("sparshpnd23")
credentialsId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
}
pushCredentialsId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
cleanImages(false)
cleanupWithJenkinsJobDelete(false)
noCache(false)
pull(true)
}
}
else {
dockerBuilderPublisher {
dockerFileDirectory("/sparsh/")
cloud("docker")
tagsString("phpserver:v1")
pushOnSuccess(true)
fromRegistry {
url("sparshpnd23")
credentialsId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
}
pushCredentialsId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
cleanImages(false)
cleanupWithJenkinsJobDelete(false)
noCache(false)
pull(true)
}
}
}
}
TASK - 2: DEPLOYMENT
This Jenkins task will deploy the code using the suitable container & the Kubernetes deployment created above.
job("Deployment") {
triggers {
upstream {
upstreamProjects("Production")
threshold("SUCCESS")
}
}
steps {
if(shell("ls /sparsh | grep html")) {
shell("if sudo kubectl get pv server-pv-vol; then if sudo kubectl get pvc server-pv-vol-claim; then echo "volume present"; else kubectl create -f server-pv-vol-claim.yml; fi; else sudo kubectl create -f server-pv-vol.yml; sudo kubectl create -f server-pv-vol-claim.yml; fi; if sudo kubectl get deployments server-deploy; then sudo kubectl rollout restart deployment/server-deploy; sudo kubectl rollout status deployment/server-deploy; else sudo kubectl create -f web-deploy-server.yml; sudo kubectl create -f webserver_expose.yml; sudo kubectl get all; fi")
}
else {
shell("if sudo kubectl get pv phpserver-pv-vol; then if sudo kubectl get pvc phpserver-pv-vol-claim; then echo "volume present"; else kubectl create -f phpserver-pv-vol-claim.yml; fi; else sudo kubectl create -f phpserver-pv-vol.yml; sudo kubectl create -f phserverp-pv-vol-claim.yml; fi; if sudo kubectl get deployments phpserver-deploy; then sudo kubectl rollout restart deployment/phpserver-deploy; sudo kubectl rollout status deployment/phpserver-deploy; else sudo kubectl create -f web-deploy-phpserver.yml; sudo kubectl create -f webserver_expose.yml; sudo kubectl get all; fi")
}
}
}
Now, you can go & check that your code will be deployed.
TASK - 3: TESTING
This task will test the code & if the code is found corrupt, it will automatically send an email to the mentioned email of the developer. (Note - If your email is not working, I have explained the process in detail in my previous task, whose link is provided at the top. Please refer to it.)
job("Testing") {
steps {
shell('export status=$(curl -siw "%{http_code}" -o /dev/null 192.168.99.102:2301); if [ $status -eq 200 ]; then exit 0; else python3 mail.py; exit 1; fi')
}
}
As far as the monitoring part is concerned, we need not worry as we have used Kubernetes Deploynment to launch the server. The Replica Set working behind the deployment will keep on monitoring the pods & will launch them again if they crash.
Our system is ready to use
Any suggestions are highly welcome.