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.
![](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701074138/devops-ci-gitlab/orghskjzvm3ozoinfr5y.webp)
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](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701140314/devops-ci-gitlab/vssoclrjwurhszxl4tmh.webp)
Then fill in project detail
![Fill in project detail](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701140334/devops-ci-gitlab/tz5etan7ivq25ltjjeyu.webp)
First pipeline
Now we have an empty project, click on New file
to open Web IDE
![Add new file](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701140334/devops-ci-gitlab/xdvupsufxhqmkwnsr6yc.webp)
Create a file named .gitlab-ci.yml
for CI configuration, let's start our test run with something simple
![New gitlab CI file](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701140334/devops-ci-gitlab/xwf0aae7pehbrl700qxf.webp)
Commit and push the file to main
, open menu Build -> Pipelines
to see our pipeline already run sucessfully
![Pipeline run detail](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701140334/devops-ci-gitlab/z5xyvlbrjicrdfp766jm.webp)
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:
![](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701074138/devops-ci-gitlab/hmffqxjubz0xsctxeaob.webp)
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:
![](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701153869/devops-ci-gitlab/ifnnruw3skvbxyafmzok.webp)
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:
![](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701159119/devops-ci-gitlab/ov4nvb7tn82qrwrkhash.webp)
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:
![](https://res.cloudinary.com/ddceq9zjs/image/upload/v1701160819/devops-ci-gitlab/ltfwaptsyc2ca4ytgg0f.webp)
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
-
Automation: Utilizing automation tools to streamline and accelerate various processes, such as testing, deployment, and infrastructure provisioning.
-
Collaboration: Fostering a culture of collaboration and communication between development and operations teams, breaking down traditional silos.
-
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.
-
Continuous Deployment (CD): The automated process of deploying code changes to production or staging environments after passing automated tests.
-
Infrastructure as Code (IaC): Managing and provisioning infrastructure using code, allowing for version control, consistency, and automation of infrastructure changes.
-
Monitoring and Logging: Implementing robust monitoring and logging practices to identify and address issues proactively, ensuring the stability and performance of systems.
-
Microservices: Architectural approach where an application is composed of small, independently deployable services, facilitating scalability and continuous delivery.
-
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.