Home DevOps the GitLab Way
Post
Cancel

DevOps the GitLab Way

Have you been searching for a platform to host your code, and build your DevOps workflow and processes all in one place? Why not use GitLab for CI/CD pipelines? GitLab lets you host your application code and use the GitLab CI CD feature to continuously test, build and deploy your application on every code change.

Table of Contents

Prerequisites

Initializing a GitLab Project

Before configuring a CI/CD pipeline on GitLab, you must first have a repository on GitLab that houses your application. This tutorial uses a Python flask application to illustrate GitLab CI CD in action.

Clone the following repo:

1
git clone https://gitea.ochoaprojects.com/brandon/gitlab-devop-scripts.git

Once cloned, open the directory containing your files from your root directory and open it up with your preferred code editor.

Next, run the command below to spin up flask run the flask application.

1
flask run

The output below indicates that the flask application is entirely functional and error-free.

Flask Run

Lastly, push the application up to your GitLab repository.

Configuring Jobs on GitLab

After initializing your GitLab project, you’ll need a way to execute tasks on your CI/CD pipeline. How? By configuring Jobs where you define tasks in a YAML file.

You’ll write the CI/CD pipeline as code in a YAML file, which GitLab will use to perform the CI/CD pipeline for your project.

There are two options involved when creating the YAML file:

  • Create, and push the file in your project directory locally from your machine alongside the pipeline configurations to your remote GitLab repository.
  • Create the file directly on your GitLab repository via the GitLab UI.

In this example, you’ll create the YAML file directly on your GitLab repository via the GitLab UI:

Click on the (+) icon shown below in your project’s root directory of your GitLab repository to initialize creating the (.gitlab-ci.yaml) file. Your browser redirects to a page where you can configure the new YAML file (step two).

Add New File Gitlab UI

Next, type in .gitlab-ci.yml in the input field with the filename placeholder, as shown below.

Creating GitLab CI Yaml Files

Add the code snippets below to the .gitlab-ci.yml file, which runs the test for the Python flask application.

1
2
3
4
5
6
7
8
9
10
11
12
13
run_tests:
    # Use GitLab-managed runner with a python:3.9-slim-buster image to run the job
    image: python:3.9-slim-buster
    before_script: 
        # Update the system package index
        - apt-get update
        # Install Python3 and pip
        - apt-get install -y python3-dev python3-pip
        # Install Flask and pytest
        - pip3 install Flask pytest
    script:
        # Run the pytest command to run the test for the Python flask application. 
        - pytest

Now, scroll down to the page’s bottom, and click on the Commit changes button to commit the changes. Doing so makes GitLab detect the pipeline configuration code and run the job.

Commit Changes

Lastly, navigate to the CI/CD section (left panel), and click on the Pipelines tab to view your pipeline.

You’ll see that the pipeline is currently in running status, as shown below.

Running Pipeline

Once executed successfully, your pipeline’s status changes to passed, which indicates your job ran successfully.

Passed Pipeline

Securing Credentials by Creating Secret Variables

You’ve just successfully executed your first job. And now, you’re almost ready to build and push the Docker image for the Python flask project to both Docker Hub and GitLab container registries.

But first, you’ll need a way to store your login credentials for Docker Hub and GitLab securely. What’s that secure way? You’ll create secret variables to hold these credentials and keep them away from public eyes.

Navigate to Settings (left panel), and click on the CI/CD tab, as shown below, to create a secret variable using GitLab project variables.

Open CI/CD Settings

Next, scroll down on the new page, click on the Variables sub-section, and click Expand (top-right of the section) to expand the Variables section.

Expand Variables

Once expanded, click Add variable (bottom-left) to add a secret variable.

Add Variable

Now, configure the new secret variable with the following:

  • Key – DOCKER_USERNAME
  • ValueInput your Docker Hub username.

Configure Variable

Finally, repeat step four, and add more variables with the following details:

  • Key – DOCKER_PASSWORD
  • ValueProvide your Docker Hub password.

  • Key - GITLAB_USERNAME
  • Value - Input your GitLab username.

  • Key – GITLAB_ACCESS_TOKEN
  • ValueInput your GitLab access token.

You should now have four secret variables, as shown below.

Completed Variables

Building and Pushing a Docker Image to Docker Hub

With your secrets kept a secret, it’s time to configure your second job. This job will build and deploy a Docker image for the Python flask application to Docker Hub.

Navigate to the CI/CD Pipeline Editor as you’ll need to add configurations to the pipeline.

Next, add the following code at the top of the run-test block. Be sure to replace dockerhub-user with your Docker Hub username.

1
2
3
variables:
    IMAGE_NAME: <dockerhub-user>/flask-app
    IMAGE_TAG: flask-app-1.0

Added Variables to Pipeline Editor

Add the following code below the run_test block, which builds a Docker image for the Python flask application. Be sure to replace gitlab-user with your GitLab username and project-name (in this example, mine is “gitlab-devop-scripts”) in the script block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
build_image:
    # Downloads a Docker client (docker:20.10.16).
    image: docker:20.10.16
    # Connects to a Docker daemon.
    services:
        - docker:20.10.16-dind
    # Create a certificate directory (DOCKER_TLS_CERTDIR) to enable the 
    # Docker client and Docker daemon to share the same certificate directory. 
    # Enable Docker client and Docker daemon to authenticate each other.
    variables:
        DOCKER_TLS_CERTDIR: '/certs'
    # Authenticate GitLab with login parameters described as secret variables.
    before_script:
        - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD 
        - docker login registry.gitlab.com -u $GITLAB_USERNAME -p $GITLAB_ACCESS_TOKEN
    # Build and push the flask image to DockerHub and GitLab container registry.
    script:
        - docker build -t $IMAGE_NAME:$IMAGE_TAG .
        - docker push $IMAGE_NAME:$IMAGE_TAG
        - docker build -t registry.gitlab.com/gitlab-user/project-name .
        - docker push registry.gitlab.com/gitlab-user/project-name

Added Build Image To Pipeline Editor

Now, click on Commit changes again to save the changes, and trigger the updated pipeline.

Commit Changes

You should now have the following output, which indicates your build is successful.

Build and Push Passed

We should also now see that our container registry push was successful by navigating to Package and registries > Container Registry and the following output will be shown below.

Navigate to the Packages & Registries (left panel) → Container Registry to confirm your Python flask image has been pushed to the GitLab container registry, as shown below.

Container Registry

Finally, switch to your Docker account and verify your Python flask application has been pushed to your Docker Hub registry.

Confirmed Docker Hub Pushed

Configuring Stages on the GitLab CI CD pipeline

Currently, each job in your pipeline is executed in isolation and running regardless of if any job is not successful, which is not good practice.

The best way to configure a pipeline is to make jobs execute accordingly, one after the other. With this behavior, if one job fails, other subsequent jobs will not execute.

Navigate to the Pipeline Editor and add the following code below the variables block in your pipeline.

The code below adds stages to the pipeline, referenced from jobs in the pipeline.

1
2
3
stages:
    - test
    - build

Reference the stages in both the run_test and build_image blocks, as shown below.

Referencing the Stages in YAML

Lastly, commit your changes to the pipeline, and navigate to Pipelines under the CI/CD section (left panel).

If all goes well, you’ll see each job executed one after the other in the Stages column, as shown below.

Viewing Stages in Pipeline

Once the run_tests job is done executing successfully, the build job begins immediately.

Viewing Second Stage in Pipeline

When the build job is executed successfully, you’ll see the following output showing two green checks under the Stages column.

Completed Stages in Pipeline

This post is licensed under CC BY 4.0 by the author.