Create CI/CD pipeline with Jenkins and Google Kubernetes Engine (GKE)

Authors: Akash Acharya & Nishant Nath

Welcome to a journey of automation and efficiency!

In this comprehensive guide, we'll delve into the intricate art of constructing a robust and streamlined CI/CD pipeline. With the prowess of Jenkins, Docker Hub, and GitHub, we'll navigate the intricate pathways of software development, culminating in the seamless deployment of our applications onto the dynamic landscape of a Kubernetes Cluster hosted on Google Kubernetes Engine (GKE). Join us as we unlock the potential of automation, empowering your development endeavors with precision and agility.

Quick summary of the tools

  1. Jenkins: Jenkins is an open-source automation server that facilitates continuous integration (CI) and continuous delivery (CD) pipelines. It automates the building, testing, and deployment of software projects, enabling teams to rapidly deliver high-quality code changes.
  2. Docker Hub: Docker Hub is a cloud-based repository service provided by Docker for storing, sharing, and managing Docker container images. It serves as a centralized platform for developers to access a vast library of pre-built Docker images and collaborate on containerized applications.
  3. GitHub: GitHub is a web-based platform for version control and collaboration, primarily used for hosting Git repositories. It offers features like code review, issue tracking, and project management tools, making it a central hub for software development teams to collaborate on code, manage projects, and track changes efficiently.

Requisites:

  1. We need a running Jenkins server with SSH access to it. 
  2. We need active GCP Project and administrator credentials for that project.
CI/CD – Architecture Diagram

STEP - 1: Installation and configuration

  1. The first step is to prepare Jenkins to work with Docker and Kubernetes. This involves installing Docker and Kubernetes command-line tools on the Jenkins cloud server and installing the Jenkins GKE plugin. 
  2. Install docker on the Jenkins server following this link.
  3. Install the "Docker Pipeline" & "Google Kubernetes Engine" plugins in Jenkins from the 'Dashboard > Manage Jenkins > Manage Plugins page 

STEP - 2: Service account and key setup

  1. Jenkins will interact with the Kubernetes cluster using a Google Cloud Platform service account. For this, we need to set up the service account and give it API access. 
  2. Next, navigate to the "IAM & admin > Service accounts" page and create a new service account. For this demo, I have created a service account with the name "Jenkins" Assign the "Kubernetes Engine Admin" role.
  3. Next, create a new JSON key for the service account. Download and save this key, as it will be needed by Jenkins. 

STEP - 3: Setting up Credentials in Jenkins

  1. We will use the Jenkins credentials store for the pipeline to communicate with the Kubernetes cluster and the Docker Hub registry 
  2. Navigate to the "Dashboard > Manage Jenkins > Manage Credentials" menu item. 
  3. Select the "System" sub-menu" and the "Global credentials" domain 
  4. Click the "Add credentials" link. Select the "Username with password" credential type and enter your Docker Hub username and password in the corresponding fields. Set the "ID" field to dockerID. Click "OK" to save the changes
  5. Click the "Add credentials" link. Select the "Google Service Account from private key" credential type and set the project name (which doubles as the credential identifier) to multi-k8s. Select the "JSON key" radio button and upload the JSON key obtained in the previous step in Setting up the GCP Account. Click "OK" to
Step 3.5: Add credentials in Jenkins
Step 3.6: Upload the Google SA Key

STEP- 4: Jenkins Pipeline Setup

  1. Here is our GitHub repository of a sample NodeJS app 
  2. At this point, we are ready to start setting up our Jenkins pipeline.  
  3. Log in to Jenkins and create a new Item 
    1. Name: node-deploy-GKE
    2. Project Type: Pipeline 
    3. Select Pipeline script and write the pipeline
    4. Replace all the variables with the values from your environment
pipeline { 
    agent any 
    environment { 
        PROJECT_ID = <Your Project ID> 
        CLUSTER_NAME = < Your cluster name > 
        LOCATION = < Your region name > 
        CREDENTIALS_ID = “oceanic-granite-383005”  // service account credential name 
    } 

    stages { 
        stage("Checkout code") { 
            steps { 
                git branch: 'main', url: < Your repository URL > 
            } 
        } 
        stage("Build image") { 
            steps { 
                script { 
                    myapp = docker.build("<docker_repo_url>/<docker_image_name>:<docker_image_tag>>") 
                } 
            } 
        } 
        stage("Push image") { 
            steps { 
                script { 
                    docker.withRegistry('https://registry.hub.docker.com', 'dockerhub') { 
                            myapp.push("latest") 
 
                    } 
                } 
            } 
        } 
        stage('Deploy to GKE') { 
            steps{ 
                step([
                    $class: 'KubernetesEngineBuilder', 
                    projectId: env.PROJECT_ID, 
                    clusterName: env.CLUSTER_NAME, 
                    location: env.LOCATION, 
                    manifestPattern: 'deployment.yml', 
                    credentialsId: env.CREDENTIALS_ID, 
                    verifyDeployments: true
                ]) 
           } 
        } 
    } 
} 
  1. We have our deployment.yaml file which will be used to deploy nodejs application to k8s cluster.
    1. Replace all the variables with the values from your environment
apiVersion: apps/v1 
kind: Deployment 
metadata: 
  name: deploy 
  labels: 
    app: node 
spec: 
  replicas: 1 
  selector: 
    matchLabels: 
      app: node 
  template: 
    metadata: 
      labels: 
        app: node 
    spec: 
      containers: 
      - name: node 
        image: <docker_repo_url>/<docker_image_name>:<docker_image_tag>
        ports: 
        - containerPort: 4000 
 
--- 
 
apiVersion: v1 
kind: Service 
metadata: 
  labels: 
    app: node 
      name: hello 
spec: 
  ports: 
  - port: 4000 
    protocol: TCP 
    targetPort: 4000 
  selector: 
    app: node 
  sessionAffinity: None 
  type: LoadBalancer 
  1. Build the pipeline in Jenkins and it should be complete with success till the Deploy to GKE step, which would indicate that it is working fine.
  1. Login to the GCP console and navigate to the Kubernetes Engine > Services & Ingress. Your application should be listed there
  1. Click the Endpoint link and your Web page should greet with you a Happy message.

In conclusion, by harnessing the power of Jenkins, Docker Hub, GitHub, and Google Kubernetes Engine, we've not just built a CI/CD pipeline, but we've paved the road to seamless deployment nirvana. Embrace automation, empower your development journey, and let your code take flight with the wings of innovation.

Happy deploying, fellow tech enthusiasts!