Create a Continuous Integration Pipeline with GitLab and Kubernetes

Vikram Vaswani

As development velocity increases, it’s now become essential for enterprises to have a reliable and readily-available Continuous Integration/Continuous Delivery (CI/CD) pipeline integrated with cloud infrastructure. But although the requirements of such infrastructure are well understood, setting up this pipeline is still a complex task involving knowledge of cloud platforms, containerization tools like Docker, Docker Compose and others, container orchestration tools like Kubernetes and Helm, and DevOps tools and techniques.

Bitnami eases the task of building an enterprise-ready CI/CD pipeline with its application stacks and container images.

Put the two together, and you have everything you need to create a modern, enterprise-grade CI/CD pipeline that leverages the scalability of Kubernetes with the flexibility of GitLab and the development agility of Bitnami containers. This guide walks you through the process.

Overview

This guide shows you how to set up a CI/CD pipeline between GitLab (deployed using the Bitnami GitLab CE stack) and a Kubernetes cluster with GitLab’s Auto DevOps feature. With this configuration, every change to application code is automatically built as a Docker container (based on a Bitnami Node.js base container) and deployed to the Kubernetes cluster for review and test.

Communication and monitoring between the GitLab deployment and the Kubernetes cluster is achieved through the use of Helm, Ingress and GitLab Runner. When GitLab deploys each built container to the cluster, it also makes it available for review at an auto-generated sub-domain of your main domain name.

Assumptions and prerequisites

This guide makes the following assumptions:

Step 1: Configure DNS and SSL for GitLab

As a first step, you must configure a domain name and SSL certificate for GitLab, such that browsing to the domain directs you to a secure page for your GitLab deployment. If you already have an SSL certificate for your domain, you can continue to use that or, if not, you can follow the approach below and generate a free Let’s Encrypt SSL certificate.

GitLab secure login

Step 2: Configure and activate the GitLab registry

The next step is to activate the GitLab registry, as follows:

  • Log in to the server console using SSH (if you’re not already logged in).

  • Edit the /etc/gitlab/gitlab.rb file and uncomment and update the registry_external_url parameter as below, remembering to replace the DOMAIN placeholder with the GitLab domain name:

    registry_external_url 'https://DOMAIN:5005'
    
  • In the same file, uncomment and update the external_url parameter as below, replacing the DOMAIN placeholder with the GitLab domain name:

    external_url 'https://DOMAIN'
    
  • Save your changes to the file.

  • Configure the GitLab registry to use the SSL certificates generated in the previous step. Replace the DOMAIN placeholder with the GitLab domain name.

    cd /etc/gitlab/ssl
    sudo ln -sf server.crt DOMAIN.crt
    sudo ln -sf server.key DOMAIN.key
    
  • Execute the commands below to reconfigure and restart GitLab with the changes.

    sudo gitlab-ctl reconfigure
    sudo /opt/bitnami/ctlscript.sh restart
    
  • Open port 5005 in the server firewall so that GitLab can connect to, and push built containers, to its internal registry. Learn about opening firewall ports for your cloud platform.

Step 3: Create a new GitLab project

You can now log in to GitLab and prepare a new project. This project will host the code that you will eventually run through your CI/CD pipeline to build and deploy on Kubernetes.

  • Browse to your GitLab domain and log in using the administrator credentials.
  • On the welcome page, select the “Create a project” option.

GitLab project creation

  • Enter a name and slug for your project. Set the visibility level to “Internal”. Click “Create project”.

GitLab project creation

Your project is created and you should see the project page, as shown below:

GitLab project page

Click the “Clone” button and note the clone URL for the repository, which will be needed in Step 6.

GitLab project clone URL

Before you can commit any code to the project repository, you must add your SSH key to your profile, as follows:

  • Click your user profile icon in the top right corner of the navigation bar.
  • Select the “Settings” menu icon.
  • On the “User Settings” page, select the “SSH Keys” menu item.
  • Paste the public key component of your SSH key pair in the “Key” field. Add an optional label and click the “Add Key” button to save the changes.

GitLab key addition

Step 4: Configure a Kubernetes cluster for the project

GitLab comes with built-in support for Kubernetes, making it easy to build and test your projects using a Kubernetes cluster. Learn more about Kubernetes support in GitLab.

First, allow outbound requests from GitLab hooks and services, as follows:

  • Navigate to the GitLab administration panel by selecting the “Admin Area” link.
  • Navigate to the “Settings -> Network” page and select the “Outbound requests” section.
  • Tick the checkboxes to allow requests to the local network from hooks and services.

GitLab network requests

Then, configure your Kubernetes cluster in GitLab by following these steps:

  • Use the kubectl command-line tool to obtain the following details for your Kubernetes cluster using the instructions in the GitLab documentation:
    • Cluster API URL
    • Cluster CA certificate
    • Cluster service token
  • From the project page in GitLab, select the “Operations -> Kubernetes” menu item.
  • On the resulting page, click the “Add Kubernetes cluster” button.

GitLab cluster configuration

  • Select the “Add existing cluster” tab.
  • Enter a name for your cluster with the API URL, CA certificate and server token obtained already. Check the boxes for “RBAC-enabled” cluster and “GitLab-managed cluster”.

GitLab cluster configuration

  • Click the “Add Kubernetes cluster” button to save the changes.
  • On the resulting page, find the “Applications” section and install Helm, followed by Ingress. Note the Ingress endpoint IP address generated after installing Ingress.

Helm/Ingress installation

  • Configure a wildcard DNS record for your domain pointing to the Ingress IP address through your DNS provider’s control panel. Learn how to configure wildcard DNS records for popular DNS providers like GoDaddy, NameCheap and AWS Route53.
  • Enter the base domain name used by the wildcard DNS record in the “Base domain” field in your GitLab Kubernetes cluster configuration. For example, if you configured a wildcard DNS record for *.example.com, use example.com as the base domain name. This will be the base domain used for all Auto DevOps review deployments. Click “Save changes” to save the changes.

GitLab base domain configuration

  • Return to the “Applications” section and install Cert-Manager. Remember to provide a valid email address so that Cert-Manager can correctly associate your certificates with your account.
  • From the same “Applications” section, install GitLab Runner.
  • Confirm that the runner is successfully installed and activated for the project by navigating to the project’s “Settings -> CI/CD” page and checking the status of the runner in the “Runners” section.

GitLab runner status

Step 5: Enable Auto DevOps for the project

Once the Kubernetes integration is complete and a runner is active, enable Auto DevOps for the project. Auto DevOps provides a preconfigured CI/CD pipeline which can be used to quickly get started with building, testing and deploying your project. Learn more about Auto DevOps in GitLab.

To enable Auto DevOps for the project:

  • Navigate to the project’s “Settings -> CI/CD” page.
  • In the “Auto DevOps” section, check the box for “Default to Auto DevOps pipeline” and select the “Continuous deployment to production” strategy.
  • Click “Save changes” to enable the default pipeline.

GitLab Auto DevOps configuration

The default Auto DevOps pipeline comes with various stages already configured, depending on which version of GitLab you are running. For example, there are stages to build, run tests, check code quality, scan for dependencies, review code, deploy code and test performance. This default pipeline is fully customizable and stages can be added or removed depending on your requirements, simply by adjusting pipeline variables. Learn about the available variables.

This tutorial will focus on creating a very simple pipeline consisting of only two stages: build and deploy. To turn off the other stages included in the default pipeline, follow these steps:

  • Navigate to the project’s “Settings -> CI/CD” page.

  • In the “Variables” section, add the following three variables and values:

    TEST_DISABLED: true
    CODE_QUALITY_DISABLED: true
    PERFORMANCE_DISABLED: true
    
  • Click “Save variables”.

GitLab Auto DevOps configuration

Step 6: Commit, test and repeat

At this point, you are ready to commit some code to the project and have GitLab test and deploy it. This tutorial will create a simple “Hello, world” application in Node.js and then configure a Dockerfile to run it with Bitnami’s Node.js development container image.

Follow these steps:

  • Create a working directory for the application on your local host:

    mkdir myproject
    cd myproject
    
  • Create a package.json file listing the dependencies for the project:

    {
      "name": "simple-node-app",
      "version": "1.0.0",
      "description": "Node.js on Docker",
      "main": "server.js",
      "scripts": {
        "start": "node server.js"
      },
      "dependencies": {
        "express": "^4.13"
      }
    }
    
  • Create a server.js file for the Express application which returns a “Hello world” message on access:

    'use strict';
    
    const express = require('express');
    
    // Constants
    const PORT = process.env.PORT || 3000;
    
    // App
    const app = express();
    app.get('/', function (req, res) {
      res.send('Hello world\n');
    });
    
    app.listen(PORT);
    console.log('Running on http://localhost:' + PORT);
    
  • Create a Dockerfile with the following content:

    FROM bitnami/node:9 as builder
    ENV NODE_ENV="production"
    
    # Copy app's source code to the /app directory
    COPY . /app
    
    # The application's directory will be the working directory
    WORKDIR /app
    
    # Install Node.js dependencies defined in '/app/packages.json'
    RUN npm install
    
    FROM bitnami/node:9-prod
    ENV NODE_ENV="production"
    COPY --from=builder /app /app
    WORKDIR /app
    ENV PORT 5000
    EXPOSE 5000
    
    # Start the application
    CMD ["npm", "start"]
    

    This multi-stage Dockerfile creates a new image using Bitnami’s Node.js container image as base. It copies the application files to the container’s /app directory and then runs npm install to install Express. It then creates a production-ready container image and configures the application to listen to request on port 5000.

Note: Exposing the application on port 5000 is a requirement of GitLab’s default Helm chart, which is used to deploy the application to the cluster. This can be overridden if needed using a custom Helm chart. Read more in our tutorial on using a custom Helm chart with the Auto DevOps pipeline.

  • Initialize a Git repository and commit and push the application code to GitLab. Replace the NAME and EMAIL-ADDRESS placeholders with your name and email address (if not already configured) and the CLONE-URL placeholder with the repository clone URL obtained in Step 3.

    git config --global user.name "NAME"
    git config --global user.name "EMAIL-ADDRESS"
    git init    
    git remote add origin CLONE-URL
    git add .
    git commit -m "Initial commit"
    git push origin master
    

Pushing this commit should automatically trigger the Auto DevOps pipeline in GitLab. To see the pipeline in action, navigate to the project’s “CI/CD -> Pipelines” page and confirm that the pipeline is running, as shown below:

GitLab pipeline

In the first stage, GitLab will attempt to build a container image containing the application code using the provided Dockerfile. The container will be pushed to the internal GitLab registry. Here’s an example of the output you should see in this first stage:

GitLab pipeline build output

Once the container image has been built and pushed, the second stage of the pipeline will attempt to deploy it to Kubernetes for review. If successful, the stage output will display a URL, which you can browse to in order to see the application in action. Here’s an example of the output you should see in this second stage:

GitLab pipeline deployment output

If you browse to the application URL listed in the output, you should see the output of the Node.js app, as shown below:

Example output

To test the CI/CD feature, make a change to the application - for example, update the message “Hello world” in the server.js file to “Aloha world” - and push the change to GitLab.

sed -i 's/Hello world/Aloha world/g' server.js
git add .
git commit -m "Modified message text"
git push origin master

The new commit should trigger the pipeline, causing a new build and deployment to take place, and the new application will be deployed on your cluster for review. As before, check pipeline status in GitLab, wait for it to complete and then browse to the application URL listed in the output of the second stage. You should see the revised output, as shown below:

Example output

At this point, you have successfully created a simple CI/CD pipeline between GitLab and a Kubernetes cluster. You can now continue to enhance it by adding new stages to the Auto DevOps pipeline, modifying how your code is deployed with a custom deployment Helm chart, or configuring pipelines to run on a schedule.

To learn more about the topics discussed in this guide, use the links below:

Frequently Asked Questions

What is a CI/CD pipeline?

Continuous integration/continuous delivery pipelines are essential DevSecOps workflows that ensure the security and automation of the software delivery process.

How do you create a CI/CD pipeline in GitLab?

CI/CD pipelines are created using a Bitnami GitLab CE stack and a Kubernetes cluster with GitLab’s Auto DevOps feature. After configuring DNS and SSL for GitLab, configure and active GitLab registry, create a new GitLab project, configure a k8 cluster for the project, enable Auto DevOps, and finally, commit code, test and deploy on GitLab.

How do you integrate Kubernetes with GitLab?

Kubernetes clusters can be integrated and configured safely with GitLab using the GitLab Kubernetes Agent.

How do you deploy a GitLab pipeline?

GitLab pipelines can be executed manually by navigating to ‘Menu > Projects’, selecting ‘CI/CD > Pipelines,’ then selecting ‘Run Pipeline’ with the proper branch, tag, and variables.

How do containerized CI/CD pipelines work with Kubernetes and GitLab?

Containerized CI/CD pipelines are directly integrated into the GitLab platform, allowing existing k8 clusters to be deployed within CI/CD pipeline workloads.