Setting up a CI/CD pipeline using IBM Cloud Private

Containers are now the de-facto mechanism for app packaging and consequently an integral part of Continuous Integration (CI) and Continuous Delivery (CD) pipelines.

A typical CI/CD pipeline uses the following process:

  • Developers commit code to SCM, which triggers a Jenkins build pipeline.
  • Jenkins builds the code and runs tests.
  • If the tests pass, the code is deployed to a staging server and eventually to production. The deployment of the code to various environments might be automatic or based on manual approvals.

A container image is built and stored in a centralized repository that is then used for deployment to various environments.

In this article, we set up a CI/CD pipeline that uses containers on IBM Cloud Private.

IBM Cloud Private, which is built on open source technologies, including Kubernetes, provides a single platform that you can leverage for your on-premises software portfolio or for easily integrating next-generation data and software that is optimized for cloud.
You can use IBM Cloud Private to deploy workloads on multiple architectures (Intel, Power, and Z). We used IBM Cloud Private deployed on Power servers running Ubuntu for this setup. However, the instructions are general and applicable for any architecture.

Prerequisites

Following are the pre-requisites:

  1. An IBM Cloud Private 2.1 installation with 1 master and at least 1 worker node. See Installing.
  2. Install the Kubernetes command line kubectl and connect it to your IBM Cloud Private instance. See Accessing your IBM Cloud Private cluster by using the kubectl CLI.
  3. The ability to clone GitHub repositories from a container. You can use a privately hosted repository or a public repository.
  4. Configure the private Docker registry. See Pushing and pulling images.

Set up Jenkins

You can deploy Jenkins in IBM Cloud Private by using the public helm chart repository that is found here: https://kubernetes-charts.storage.googleapis.com/ 
On the IBM Cloud Private dashboard, click Menu > Admin > Repositories and then click Add.

Add the repository, and then click Sync repositories.

Jenkins appears in your IBM Cloud Private Catalog, and can deploy Jenkins on your cluster with just few clicks. While you add Jenkins, take the following actions:

  1. Ensure that the Jenkins image for both Jenkins Master and Slave that you specify in the Helm chart is correct.
  2. Set up a PersistentVolume. See Creating a PersistentVolume.
  3. You need to pass volumes by using the HostPath for the docker.sock file. The Jenkins slave uses this information to call the docker daemon that runs on the worker node. Add the following snippet to the Jenkins charts yaml file under the “volumes” section:
volumes:
- type: HostPath
hostPath: /var/run/docker.sock
mountPath: /var/run/docker.sock

After you deploy Jenkins, launch it.

  • Obtain the initial ADMIN password of your Jenkins server to log in. One of the ways to do this is to run the following kubectl command:
kubectl exec `kubectl get pods — selector=app=jenkins1-jenkins — output=jsonpath={.items..metadata.name}` env | grep ADMIN_PASSWORD

where jenkins1-jenkins is the name of your Jenkins deployment.

  • Click Menu > Helm releases > <Jenkins_app_you_deployed> > Deployment.
  • Click access http to access the Jenkins application. Use “admin” as the user name, and the password that you obtained.

Set up the Jenkins Pipeline

After logging in to the Jenkins UI, install the following plug-ins:

  • Kubernetes plug-in
  • Docker plug-in
  • Pipeline plugin

You can also upgrade Jenkins to the latest version from the UI.

Now create a pipeline. From the Jenkins home page, click New Item. Then, enter the name of your pipeline, click Pipeline, and click OK.

Open the pipeline page, and add the URL for the source code repository for your project.

In this article, we used the following GitHub project: https://github.com/sudswas/sampleflaskapp. If you don’t have a sample app, clone this app.
The project contains a Jenkinsfile that defines the pipeline stages. Copy the following sample Jenkinsfile to your GitHub project:

node {
dir("/root/"){
checkout scm
env.DOCKER_API_VERSION="1.23"
appName = "default/flask-app"
registryHost = "mycluster.icp:8500/"
imageName = "${registryHost}${appName}:${env.BUILD_ID}"
env.BUILDIMG=imageName
docker.withRegistry('https://mycluster.icp:8500/', 'docker'){
stage "Build"
def pcImg = docker.build("mycluster.icp:8500/default/flask-app:${env.BUILD_ID}", "-f Dockerfile.ppc64le .")
sh "cp /root/.dockercfg ${HOME}/.dockercfg"
pcImg.push()
input 'Do you want to proceed with Deployment?'
stage "Deploy"
sh "kubectl set image deployment/demoapp-demochart demochart=${imageName}"
sh "kubectl rollout status deployment/demoapp-demochart"
}
}
}

This Jenkinsfile contains the definition of a pipeline with two stages — Build and Deploy.

The build stage

In this stage, we build a Docker image that contains the latest changes that were pushed to our GitHub repository. 
After the Docker image is built with the latest changes, it’s pushed to the IBM Cloud Private private registry. IBM Cloud Private registry is available at port 8500, so the URI for the private Docker registry is https://ip_address:8500, where ip_address is the IP address that you use to access your IBM Cloud Private UI.
In our setup, the IBM Cloud Private private Docker registry is available at the following URI: https://mycluster.icp:8500/

Update your Jenkins file to use the URI of your private Docker registry.

You also need to add your IBM Cloud Private credentials to Jenkins so it can interact with the private Docker registry. From the Jenkins home page, open the Credentials page and add your IBM Cloud Private user name and password, as shown in the following image:

Here, we configured the IBM Cloud Private private registry credentials with the ID `docker`. This variable is used in the following line of the Jenkinsfile:

docker.withRegistry(‘https://mycluster.icp:8500/', ‘docker’){

After the build stage is complete, you can view the new image in the IBM Cloud Private registry. From the IBM Cloud Private UI, click Menu > Platform > Images.
 You can always enhance the build stage by adding more tests before you push the image to registry.

The deploy stage

The deploy stage involves deploying the app into your staging or production environment via Kubernetes rolling update. We configured this stage to work with an application that we deployed via a Helm chart. We want to continually upgrade the versions of the app as required. 
Deploy your application to the server. If you use the sample app, the Helm chart for it is available in the GitHub repository itself: https://github.com/sudswas/sampleflaskapp. To deploy the chart in IBM Cloud Private, see Working with charts.
Set the right values for the image repository in the values.yaml file. If you use your own project, add a copy of this file to your repository: https://github.com/sudswas/sampleflaskapp/blob/helm/helmchart/values.yaml

image:
repository: mycluster.icp:8500/default/demoapp
tag: latest

In this example, the image in your private Docker registry is named demoapp, and it contains a tag named latest.
In the following line of code in this file, add the name of the deployment:

sh “kubectl set image deployment/demoapp-demochart demochart=${imageName}”

The deployment name is demoapp-demochart. You can obtain the deployment name from the IBM Cloud Private dashboard or by using the kubectl command line.

Final steps

After the deployment stage completes, your app is rolled out with the latest image changes.
Here is a recorded video showing the sequence of steps.

Conclusion

In this article, we looked at how to design a CI/CD pipeline in IBM Cloud Private on Power by leveraging open source toolchain and the private Docker registry for IBM Cloud Private. I would also like to thank my co-author Sudipta Biswas for this article.


Originally published at www.ibm.com.