Create an account


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Set Up a CI/CD Pipeline with a Jenkins Pod in Kubernetes (Part 2)

#1
Set Up a CI/CD Pipeline with a Jenkins Pod in Kubernetes (Part 2)

<div style="margin: 5px 5% 10px 5%;"><img src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2.png" width="256" height="256" title="" alt="" /></div><div><p><span><span>In </span><a href="https://www.linux.com/blog/learn/chapter/Intro-to-Kubernetes/2017/5/set-cicd-pipeline-kubernetes-part-1-overview"><span>Part 1</span></a><span> </span></span><span><span>of our series, we got our local Kubernetes cluster up and running with Docker, Minikube, and kubectl. We set up an image repository, and tried building, pushing, and deploying a container image with code changes we made to the Hello-Kenzan app. It’s now time to automate this process. </span></span></p>
<p><span><span>In Part 2, we’ll set up continuous delivery for our application by running Jenkins in a pod in Kubernetes. We’ll create a pipeline using a Jenkins 2.0 Pipeline script that automates building our Hello-Kenzan image, pushing it to the registry, and deploying it in Kubernetes. That’s right: we are going to deploy pods from a registry pod using a Jenkins pod. While this may sound like a bit of deployment alchemy, once the infrastructure and application components are all running on Kubernetes, it makes the management of these pieces easy since they’re all under one ecosystem. </span></span></p>
<p><span><span>With Part 2, we’re laying the last bit of infrastructure we need so that we can run our Kr8sswordz Puzzle in Part 3.</span></span></p>
<p><em>Read all the articles in the series:</em></p>
<div> </p>
<div>
<table>
<tbody>
<tr>
<td><span><img alt="RyHz4CL2OgRH4G8M7BLPxwZ7MMAZh-DpmmEuXBoa" height="20" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2.png" width="20" /></span></td>
<td>
<p><span><span>This tutorial only runs locally in Minikube and will not work on the cloud. You’ll need a computer running an up-to-date version of Linux or macOS. Optimally, it should have 16 GB of RAM. Minimally, it should have 8 GB of RAM. For best performance, reboot your computer and keep the number of running apps to a minimum. </span></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<h2><span><span>Creating and Building a Pipeline in Jenkins </span></span></h2>
<p><span><span>Before you begin, you’ll want to make sure you’ve run through the steps in </span><span>Part 1</span><span>, in which we set up our image repository running in a pod (to do so quickly, you can run the </span><a href="https://docs.google.com/document/d/13kscUdwcIYScZgjAo5TtLpYxHJRDX-P6UIxlRywRSgg/edit#heading=h.uttahhp9vaq6"><span>npm part1 automated script detailed below</span></a><span>). </span></span></p>
<p><span><span>If you previously stopped Minikube, you’ll need to start it up again. Enter the following terminal command, and wait for the cluster to start:</span></span></p>
<pre>
<span><span>minikube start</span></span></pre>
<p><span><span>You can check the cluster status and view all the pods that are running. </span></span></p>
<pre>
<span><span>kubectl cluster-info</span></span> <span><span>kubectl get pods --all-namespaces</span></span></pre>
<p><span><span>Make sure that the </span><strong><span>registry</span></strong><span> pod has a Status of Running.</span><span> </span></span></p>
<p><span><span>We are ready to build out our Jenkins infrastructure. </span></span></p>
<p><strong><span><span>Remember, you don’t actually have to type the commands below—just press Enter at each step and the script will enter the command for you!</span></span></strong></p>
<p><span><span>1. First, let’s build the Jenkins image we’ll use in our Kubernetes cluster. </span></span></p>
<pre>
<span><span>docker build -t 127.0.0.1:30400/jenkins:latest </span></span> <span><span> -f applications/jenkins/Dockerfile applications/jenkins</span></span></pre>
<p><span><span>2. Once again we’ll need to set up the Socat Registry proxy container to push images, so let’s build it. Feel free to skip this step in case the socat-registry image already exists from Part 1 (to check, run </span><em><span>docker images</span></em><span>). </span></span></p>
<pre>
<span><span>docker build -t socat-registry -f applications/socat/Dockerfile applications/socat</span></span></pre>
<p><span><span>3. Run the proxy container from the image. </span></span></p>
<pre>
<span><span>docker stop socat-registry; docker rm socat-registry; </span></span> <span><span> docker run -d -e "REG_IP=`minikube ip`" -e "REG_PORT=30400" </span></span> <span><span> --name socat-registry -p 30400:5000 socat-registry</span></span></pre>
<div>
<div>
<table>
<tbody>
<tr>
<td><span><img alt="n-z3awvRgVXCO-QIpllgiqXOWtsTeePM62asXPD5" height="20" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2.png" width="20" /></span></td>
<td>
<p><span><span>This step will fail if local port 30400 is currently in use by another process. You can check if there’s any process currently using this port by running the command</span><br class="kix-line-break" /><span>lsof -i :30400</span></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p><span><span>4. With our proxy container up and running, we can now push our Jenkins image to the local repository.</span></span></p>
<pre>
<span><span>docker push 127.0.0.1:30400/jenkins:latest</span></span></pre>
<p><span><span>You can see the newly pushed Jenkins image in the registry UI using the following command.</span></span></p>
<pre>
<span><span>minikube service registry-ui</span></span></pre>
<p><span><span>5. The proxy’s work is done, so you can go ahead and stop it.</span></span></p>
<pre>
<span><span>docker stop socat-registry</span></span></pre>
<p><span><span>6. Deploy Jenkins, which we’ll use to create our automated CI/CD pipeline. It will take the pod a minute or two to roll out. </span></span></p>
<pre>
<span><span>kubectl apply -f manifests/jenkins.yaml; kubectl rollout status deployment/jenkins</span></span></pre>
<p><span><span>Inspect all the pods that are running. You’ll see a pod for Jenkins now.</span></span></p>
<pre>
<span><span>kubectl get pods</span></span></pre>
<div>
<div>
<div>
<table>
<tbody>
<tr>
<td><span><img alt="_YIHeGg141vkuJmdJZBO0zN2s3pjLdDMgo5pfQFe" height="20" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2.png" width="20" /></span></td>
<td>
<p><span><span>Jenkins as a CD tool needs special rights in order to interact with the Kubernetes cluster, so we’ve setup </span><a href="https://kubernetes.io/docs/reference/access-authn-authz/rbac/"><span>RBAC</span></a><span> (Role Based Access Control) authorization for it inside the jenkins.yaml deployment manifest. RBAC consists of a </span><span>Role</span><span>, a </span><span>ServiceAccount</span><span> and a </span><span>Binding</span><span> object that binds the two together. Here’s how we configured Jenkins with these resources:</span></span></p>
<p><span><span>Role</span><span>: For simplicity we leveraged the pre-existing ClusterRole “cluster-admin” which by default has unlimited access to the cluster. (In a real life scenario you might want to narrow down Jenkins’ access rights by creating a new role with the least privileged PolicyRule.)</span></span></p>
<p><span><span>ServiceAccount</span><span>: We created a new ServiceAccount named “Jenkins”. The property “automountServiceAccountToken” has been set to true; this will automatically mount the authentication resources needed for a kubeconfig context to be setup on the pod (i.e. Cluster info, User represented by a token and a Namespace). </span></span></p>
<p><span><span>RoleBinding</span><span>: We created a ClusterRoleBinding that binds together the “Jenkins” serviceAccount to the “cluster-admin” ClusterRole.</span></span></p>
<p><span><span>Lastly, we tell our Jenkins deployment to run as the Jenkins ServiceAccount.</span></span></p>
</td>
</tr>
</tbody>
</table>
</div>
<div>
<table>
<tbody>
<tr>
<td><span><img alt="n-z3awvRgVXCO-QIpllgiqXOWtsTeePM62asXPD5" height="20" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2.png" width="20" /></span></td>
<td>
<p><span><span>Notice our Jenkins deployment has an </span><span>initContainer</span><span>. This is a container that will run to completion before the main container is deployed on our pod. The job of this init container is to create a kubeconfig file based on the provided context and to share it with the main Jenkins container through an “emptyDir” volume.</span></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div>
<p><span><span>7. Open the Jenkins UI in a web browser.</span></span></p>
<pre>
<span><span>minikube service jenkins</span></span></pre>
<p><span><span>8. Display the Jenkins admin password with the following command, and right-click to copy it.</span></span></p>
<pre>
<span><span>kubectl exec -it `kubectl get pods --selector=app=jenkins </span></span> <span><span>--output=jsonpath={.items..metadata.name}` </span></span><span><span>cat </span></span> <span><span>/var/jenkins_home/secrets/initialAdminPassword</span></span></pre>
<p><span><span>9. Switch back to the Jenkins UI. Paste the Jenkins admin password in the box and click </span><strong><span>Continue</span></strong><span><strong>.</strong> Click </span><strong><span>Install suggested plugins</span></strong><span><strong>.</strong> Plugins have actually been pre-downloaded during the Jenkins image build, so this step should finish fairly quickly.</span></span></p>
<div>
<div>
<table>
<tbody>
<tr>
<td><span><img alt="RyHz4CL2OgRH4G8M7BLPxwZ7MMAZh-DpmmEuXBoa" height="20" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2.png" width="20" /></span></td>
<td>
<p><span><span>One of the plugins being installed is </span><a href="https://plugins.jenkins.io/kubernetes-cd"><span>Kubernetes Continuous Deploy</span></a><span>, which allows Jenkins to directly interact with the Kubernetes cluster rather than through kubectl commands. This plugin was pre-downloaded with the Jenkins image build. </span><span> </span></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<p><span><span>10. Create an admin user and credentials, and click </span><span><strong>Save and Continue</strong>. (</span><span>Make sure to remember these credentials as you will need them for repeated logins.)</span></span></p>
<p><span><span><img alt="s7KGWbFBCOau5gi7G05Fs_mjAtBOVNy7LlEQ4wTL" height="385" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2-1.png" width="576" /></span></span><span><span> </span></span></p>
<p><span><span>11. On the Instance Configuration page, click </span><strong><span>Save and Finish</span></strong><span><strong>.</strong> On the next page, click </span><strong><span>Restart</span></strong><span> (if it appears to hang for some time on restarting, you may have to refresh the browser window). Login to Jenkins. </span></span></p>
<p><span><span>12. Before we create a pipeline, we first need to provision the Kubernetes Continuous Deploy plugin with a kubeconfig file that will allow access to our Kubernetes cluster. In Jenkins on the left, click on </span><strong><span>Credentials</span></strong><span>, select the </span><strong><span>Jenkins </span></strong><span>store, then </span><strong><span>Global credentials (unrestricted)</span></strong><span>, and </span><strong><span>Add Credentials</span></strong><span><strong> </strong>on the left menu</span></span></p>
<p><span><span>13. </span></span><span><span>The following values must be entered precisely as indicated: </span></span></p>
<ul>
<li>
<p><span><strong><span>Kind</span></strong><span><strong>:</strong> Kubernetes configuration (kubeconfig)</span></span></p>
</li>
<li>
<p><span><strong><span>ID</span></strong><span><strong>:</strong> kenzan_kubeconfig</span></span></p>
</li>
<li>
<p><span><strong><span>Kubeconfig</span></strong><span><strong>:</strong> From a file on the Jenkins master</span></span></p>
</li>
<li>
<p><span><strong><span>File</span></strong><span><strong>:</strong> /var/jenkins_home/.kube/config</span></span></p>
</li>
</ul>
<p><span>Finally click </span><strong><span>Ok</span></strong><span>.</span></p>
<p><span><span><img alt="HznE6h9fOjuiv543Oqs5MqiIj0D52wSFJ44a-3An" height="299" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2-2.png" width="624" /></span></span></p>
<p><span><span>13. We now want to create a new pipeline for use with our Hello-Kenzan app. Back on Jenkins Home, on the left, click </span><strong><span>New Item</span><span>.</span></strong></span></p>
<p><span><span><img alt="EdS4p4roTIfvBrg5Fz0n7sx8gTtMiXQMT7mqYqT-" height="191" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2-3.png" width="243" /></span></span></p>
<p><span><span><span>Enter the item name as </span><strong><span>Hello-Kenzan Pipeline</span></strong><span>, select </span><strong><span>Pipeline</span></strong><span>, and click </span><strong><span>OK</span></strong><span>.</span></span></span></p>
<p><img alt="4If4KfHDUj8hGFn8kkaavcX9H8sboABcODIkrVL3" height="215" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2-4.png" width="577" /></p>
<p><span><span>14. Under the Pipeline section at the bottom, change the </span><span><strong>Definition</strong> </span><span>to be </span><strong><span>Pipeline script from SCM</span></strong><span>.</span></span></p>
<p><span><span>15. Change the </span><strong><span>SCM</span></strong><span> to </span><strong><span>Git</span></strong><span>. Change the </span><strong><span>Repository URL </span></strong><span>to be the URL of your forked Git repository, such as </span><strong><span><a href="https://github.com/%5BGIT">https://github.com/[GIT</a> USERNAME]/kubernetes-ci-cd. </span></strong></span></p>
<p><span><span><img alt="OPuG1YZM70f-TcKx-dkQQLl223gu0PudZe12eQPl" height="415" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2-5.png" width="573" /></span></span></p>
<div>
<div>
<table>
<tbody>
<tr>
<td><span><img alt="RyHz4CL2OgRH4G8M7BLPxwZ7MMAZh-DpmmEuXBoa" height="20" src="http://www.sickgaming.net/blog/wp-content/uploads/2018/10/set-up-a-ci-cd-pipeline-with-a-jenkins-pod-in-kubernetes-part-2.png" width="20" /></span></td>
<td>
<p><span><span>Note for the Script Path, we are using a Jenkinsfile located in the root of our project on our Github repo. This defines the build, push and deploy steps for our hello-kenzan application. </span><span> </span></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<p><span><span>Click </span><strong><span>Save</span></strong><span><strong>.</strong> On the left, click </span><strong><span>Build Now</span></strong><span> to run the new pipeline. You should see it run through the build, push, and deploy steps in a few seconds.</span></span></p>
<p><span><span><img alt="b4KTpFJ4vnNdFbTKcMxn7Yy3aFr8UTlmQBuVK6YB" height="341" src="https://lh6.googleusercontent.com/b4KTpFJ4vnNdFbTKcMxn7Yy3aFr8UTlmQBuVK6YBTxg1MFvYJkMXLA2OkLn5HS5lBoEia3ctLcLc1nNgAm2U7XZ2ztNvKXDdJSy1pIHu3BbQAshQol6ZwZYAGrdnJcd9gmmM_1Hx" width="577" /></span></span></p>
<p><span><span>16. After all pipeline stages are colored green as complete, view the Hello-Kenzan application.</span></span></p>
<pre>
<span><span>minikube service hello-kenzan</span></span></pre>
<p><span><span>You might notice that you’re not seeing the uncommitted change you previously made to<strong> </strong></span><span><strong>index.html</strong> </span><span>in Part 1. That’s because Jenkins wasn’t using your local code. Instead, Jenkins pulled the code from your forked repo on GitHub, used that code to build the image, push it, and then deploy it. </span></span></p>
<h2><span><span>Pushing Code Changes Through the Pipeline</span></span></h2>
<p><span><span>Now let’s see some Continuous Integration in action! try changing the </span><strong><span>index.html</span></strong><span> in our Hello-Kenzan app, then building again to verify that the Jenkins build process works. </span></span></p>
<p><span><span>a. Open </span><span><strong>applications/hello-kenzan/index.html</strong> </span><span>in a text editor.</span></span></p>
<pre>
<span><span>nano applications/hello-kenzan/index.html</span></span></pre>
<p><span><span>b. Add the following html at the end of the file (or any other html you like). (</span><strong><span>Tip:</span></strong><span> You can right-click in nano and choose </span><strong><span>Paste</span></strong><span><strong>.</strong>)</span></span></p>
<pre>
<span><span>&lt;p style="font-family:sans-serif"&gt;For more from Kenzan, check out our &lt;a href="http://kenzan.io"&gt;website&lt;/a&gt;.&lt;/p&gt;</span></span></pre>
<p><span><span>c. Press </span><span>Ctrl+X</span><span> to close the file, type </span><span>Y</span><span> to confirm the filename, and press </span><span>Enter</span><span> to write the changes to the file.</span></span></p>
<p><span><span>d. Commit the changed file to your Git repo (you may need to enter your GitHub credentials):</span></span></p>
<pre>
<span><span>git commit -am "Added message to index.html"</span></span> <span><span>git push</span></span></pre>
<p><span><span>In the Jenkins UI, click </span><strong><span>Build Now</span></strong><span> to run the build again.</span></span></p>
<p><span><span><img alt="Jc8EnFCovLr3FfxWQxfuaeqX4VDJCHaq-mxvBIeC" height="413" src="https://lh4.googleusercontent.com/Jc8EnFCovLr3FfxWQxfuaeqX4VDJCHaq-mxvBIeCuWCLnW2I12pqkXPOiX-0WeJR8CNIEhoGrDWzD7y1L0r35yXAF_NhoISFUXbCleZuZv4hGBRAwVqwx737cwTvHCM4ZwST6s23" width="624" /></span></span></p>
<p><span><span>18. View the updated Hello-Kenzan application. You should see the message you added to index.html. (If you don’t, hold down Shift and refresh your browser to force it to reload.)</span></span></p>
<pre>
<span><span>minikube service hello-kenzan</span></span></pre>
<p><span><span><img alt="ZyyeJWIXiqbBXfNd9MwG25_9Ewb8YmrKFTI-4zUz" height="304" src="https://lh5.googleusercontent.com/ZyyeJWIXiqbBXfNd9MwG25_9Ewb8YmrKFTI-4zUzeWw1W2nJ9erU0zaUKppXrtpLlkAv23kb55K5eXMO5bu73Oj_GE-SFdbTAFfxyzSC2XFCMlrLxziPB6vFIRjBnAH9bG59unOc" width="624" /></span></span></p>
<p><span><span>And that’s it! You’ve successfully used your pipeline to automatically pull the latest code from your Git repository, build and push a container image to your cluster, and then deploy it in a pod. And you did it all with one click—that’s the power of a CI/CD pipeline.</span></span></p>
<p><span><span>If you’re done working in Minikube for now, you can go ahead and stop the cluster by entering the following command:</span></span></p>
<pre>
<span><span>minikube stop</span></span>
</pre>
<div>
<table>
<tbody>
<tr>
<td>
<h3><span><span>Automated Scripts</span></span></h3>
<p><span><span>If you need to walk through the steps we did again (or do so quickly), we’ve provided npm scripts that will automate running the same commands in a terminal.  </span></span></p>
<p><span><span>1. To use the automated scripts, you’ll need to install NodeJS and npm. </span></span></p>
<p><span><span>On </span><strong><span>Linux</span></strong><span>, follow the </span><a href="https://nodejs.org/en/download/package-manager/"><span>NodeJS installation steps</span></a><span> for your distribution. To quickly install NodeJS and npm on Ubuntu 16.04 or higher, use the following terminal commands. </span></span></p>
<pre>
<span><span>a. curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -</span></span> <span><span>b. sudo apt-get install -y nodejs</span></span></pre>
<p><span><span>2. </span></span>Change directories to the cloned repository and install the interactive tutorial script:</p>
<pre>
a. cd ~/kubernetes-ci-cd b. npm install</pre>
<p>3. Start the script</p>
<pre>
npm run part1 (or part2, part3, part4 of the blog series)</pre>
<p>​4. <span>Press <strong>Enter</strong> to proceed running each command.</span></p>
</td>
</tr>
</tbody>
</table>
</div>
<h2>Up Next</h2>
<p><span><span>In Parts 3 and 4, we will deploy our Kr8sswordz Puzzle app through a Jenkins CI/CD pipeline. We will demonstrate its use of caching with etcd, as well as scaling the app up with multiple puzzle service instances so that we can try running a load test. All of this will be shown in the UI of the app itself so that we can visualize these pieces in action. </span></span></p>
<p><em>Curious to learn more about Kubernetes? <a href="https://www.edx.org/course/introduction-kubernetes-linuxfoundationx-lfs158x">Enroll in Introduction to Kubernetes</a>, a FREE training course from The Linux Foundation, hosted on edX.org.</em></p>
<p><em>This article was revised and updated by David Zuluaga, a front end developer at Kenzan. He was born and raised in Colombia, where he studied his BE in Systems Engineering. After moving to the United States, he studied received his master’s degree in computer science at Maharishi University of Management. David has been working at Kenzan for four years, dynamically moving throughout a wide range of areas of technology, from front-end and back-end development to platform and cloud computing. David’s also helped design and deliver training sessions on Microservices for multiple client teams.</em></p>
</div>
Reply



Forum Jump:


Users browsing this thread:
2 Guest(s)

Forum software by © MyBB Theme © iAndrew 2016