Stafini
BlogFlashcardsProjectsResume

DevOps with GitLab CI/CD - Introduction to GitLab CI

As I strive to become a more proficient software developer, I acknowledge the crucial role of Continuous Integration and Continuous Deployment (CI/CD) in completing the full circle of software development. This post marks the first step in my quest to fundamentally understand the essential knowledge of DevOps. Let's explore together the basics of CI/CD and discover how it serves as a key component in achieving efficient and streamlined software development practices.

Setup Gitlab project

Started by createing your account on Gitlab if you dont't have one yet: https://gitlab.com/users/sign_up

Create a new project

Create project

Then fill in project detail

Fill in project detail

First pipeline

Now we have an empty project, click on New file to open Web IDE

Add new file

Create a file named .gitlab-ci.yml for CI configuration, let's start our test run with something simple

New gitlab CI file

Commit and push the file to main, open menu Build -> Pipelines to see our pipeline already run sucessfully

Pipeline run detail

Let's update our pipeline to make it a bit more interesting

# Stage name
build video game:
  # Specify image used:
  image: alpine
  # Scripts by line
  script: 
    - echo "Build a video game"
    - mkdir game
    - touch game/character.txt
    - echo "Spiderman" >> game/character.txt
    - cat game/character.txt

Open the pipeline to see our commands have been executed properly with no errors:

$ echo "Build a video game"
Build a video game
$ mkdir game
$ touch game/character.txt
$ echo "Spiderman" >> game/character.txt
$ cat game/character.txt
Spiderman
Cleaning up project directory and file based variables
Job succeeded

We will expand our pipleline in later section

What is YAML file

YAML (YAML Ain't Markup Language) is a human-readable data serialization format commonly used for configuration files and data exchange between languages with different data structures. It uses indentation to represent the structure of data and relies on whitespace for readability.

Example YAML Structure:

# Sample YAML File

user:
  name: John Doe
  age: 30
  email: [email protected]

preferences:
  theme: dark
  language: en_US

tasks:
  - title: Task 1
    completed: true
  - title: Task 2
    completed: false

What is Shell script

A Linux shell script is a plain text file containing a series of commands written in a scripting language that is interpreted by a Unix or Linux shell. The shell script allows users to automate sequences of commands, perform repetitive tasks, and execute complex operations by writing a script rather than entering individual commands one by one.

Example Shell Script:

#!/bin/bash

# This is a simple Bash script

echo "Hello, World!"

# Variables
name="John"
echo "Welcome, $name!"

# Command substitution
current_date=$(date +%Y-%m-%d)
echo "Today's date is $current_date"

Expand pipeline

Our script to build a video game is cool but what if we want to add another step, to test the video game, we can just add another command like test but it would not be practical and very hard to maintain later. Instead another stage should be added in yaml file:

# Add below build stage
test game:
  image: alpine
  script: 
    # Command to test if file exists
    - test -f game/character.txt

Then commit the file and check pipeline:

The pipeline failed then, why is that ? We're building the game at the same time we're testing it, essentially we want to have this in two separated stages right ? We want them to be depenedent on one another, so there would be two stages, let's define these stage: build stage and test state:

# Define stages
stages:
  - build
  - test

# Build stage
build game:
  # Specify image used:
  image: alpine
  # Specfy which step the job belongs to
  stage: build
  # Scripts by line
  script: 
    - echo "Build game"
    - mkdir game
    - touch game/character.txt
    - echo "Spiderman" >> game/character.txt
    - cat game/character.txt

# Test stage
test game:
  image: alpine
  stage: test
  script: 
    # Command to test if file exists
    - test -f game/character.txt

When we look at the pipeline we can see our stages will run one after the other, the test stage does not start until build stage is over. Let's commit these changes and take a look at the pipeline again:

It runs in order but it still fails, the reason is we have 2 jobs and they run on different docker, every time a job is done running, its Docker container will be destroy so when build job runs its container is fresh without game directory from build. To get around with this problem we will reply on artifacts in configuration, artifacts takes a job output and put it in another job. With that let's update configuration file.

  # Put below script in build job
  artifacts: 
    paths:
      - game

Check the pipeline again to see it works properly now:

You can check the jobs to see how artifacts works in more detail.

Test the build

Testing is an integral path of software development, unit test would be often set up in CI for testing. Since we don't have any code to test here, we still could do it hypothetically by check the content of the files using grep command

# Add this to test job script step
- grep "Spiderman" game/character.txt
- grep "Dante" game/character.txt

Then commit the file and go to pipeline page:

Of course it fails since we're testing something does not exist.

What is Devops ?

DevOps is a set of practices, principles, and cultural philosophies aimed at improving collaboration and communication between software development teams (Dev) and IT operations teams (Ops). The primary goal of DevOps is to enhance the efficiency and effectiveness of the software development and delivery process.

Key Characteristics and Principles

  1. Automation: Utilizing automation tools to streamline and accelerate various processes, such as testing, deployment, and infrastructure provisioning.

  2. Collaboration: Fostering a culture of collaboration and communication between development and operations teams, breaking down traditional silos.

  3. Continuous Integration (CI): The practice of frequently integrating code changes into a shared repository, with automated testing to catch issues early in the development process.

  4. Continuous Deployment (CD): The automated process of deploying code changes to production or staging environments after passing automated tests.

  5. Infrastructure as Code (IaC): Managing and provisioning infrastructure using code, allowing for version control, consistency, and automation of infrastructure changes.

  6. Monitoring and Logging: Implementing robust monitoring and logging practices to identify and address issues proactively, ensuring the stability and performance of systems.

  7. Microservices: Architectural approach where an application is composed of small, independently deployable services, facilitating scalability and continuous delivery.

  8. Containerization: Using lightweight, portable containers to package and deploy applications consistently across different environments.

DevOps is not just about tools and technologies; it's also about fostering a cultural shift where development and operations teams collaborate seamlessly, share responsibilities, and collectively own the end-to-end software delivery lifecycle. The aim is to create a more agile, efficient, and responsive development and deployment pipeline, ultimately delivering better-quality software to end-users more quickly and reliably.

Resource