DevOps is a modern software engineering approach that combines software development (Dev) and IT operations (Ops) into a unified practice aimed at improving the speed, reliability, and quality of software delivery. It is not a tool or a job title, but rather a culture, set of practices, and automation-driven methodology that enables organizations to build, test, and release software more efficiently.
At its core, DevOps is about breaking down the traditional silos between development and operations teams. In older models, developers would write code and “throw it over the wall” to operations teams for deployment and maintenance. This separation often led to delays, miscommunication, and unstable releases.
To gain a practical understanding of DevOps, we will examine a real-world project that involves deploying a simple web application using modern DevOps tools and methodologies.
Arm Your Workstation
Every DevOps engineer relies on a core set of tools to build, test, and deploy applications efficiently. In this setup, we will install three essential tools: Git for version control, curl for transferring data over networks, and Docker for containerizing applications. Together, these tools form a foundational toolkit for modern DevOps workflows.
1. Update Your Local Development Environment
This step updates your system's package repository information and upgrades installed software to the latest available versions. Keeping your system up to date ensures you have the latest security patches, bug fixes, and compatibility improvements, reducing the likelihood of installation failures or unexpected issues when setting up new tools.
Maintaining an updated and healthy environment is a fundamental operational practice. It helps ensure system reliability, consistency, and readiness for development and deployment activities, forming a strong foundation for efficient DevOps workflows.
winget upgrade --all
These commands are for windows operating systems
2. Install Git, Curl, and Docker
This step installs three essential tools used throughout modern software development and DevOps practices. Git for version control and collaboration, curl for transferring data and interacting with web services from the command line, and Docker for packaging and running applications in isolated, portable containers.
These tools form the foundation of many development, automation, and deployment workflows, making them indispensable for engineers working with cloud and DevOps technologies.
Equipping your environment with industry-standard tools enables efficient development, automation, troubleshooting, and deployment processes. Standardized tooling improves productivity, consistency, and reliability across the software delivery lifecycle, supporting operational excellence and best practices.
winget install -e --id Git.Git
winget install -e --id Docker.DockerDesktop
winget install -e --id curl.curl
docker --version
These commands are for windows operating systems
3. Configure Git with Your Identity
This step configures your Git identity by setting your username and email address. Git uses this information to label every commit you make, ensuring that all changes in a codebase are properly attributed to the correct developer.
Without this configuration, Git cannot associate commits with a user identity, which prevents proper tracking of changes and can block or invalidate contributions in collaborative repositories.
Defining a clear user identity in Git supports traceability and accountability across the software development lifecycle. It ensures that every change can be audited, reviewed, and attributed, which is essential for secure, compliant, and well-governed development practices.
# Sets Git configuration (username or aliases, etc.).
git config --global user.name "Your Name"
# Sets Git configuration (email).
git config --global user.email "you@example.com"
# Displays all Git configuration settings that are currently applied to your Git environment.
git config --list
4. Create a GitHub Repository
This step creates a remote repository on GitHub, providing a centralized location to store and manage your code in the cloud. A remote repository acts as a shared source of truth where your project is safely backed up, version-controlled, and accessible to collaborators.
In real DevOps environments, code is never kept only on a local machine. It is stored in remote repositories to enable team collaboration, trigger automated CI/CD pipelines, and ensure code is not lost due to local system failure.
Remote repositories are essential for enabling teamwork, transparency, and continuous integration in modern software delivery. They serve as the foundation for collaborative development workflows, automated deployments, and scalable DevOps practices.
# 1. Go to https://github.com and sign in (or create an account if you don't have one)
# 2. Click the '+' icon in the top-right corner → 'New repository'
# 3. Name it: devops-lab1
# 4. Leave it PUBLIC, do NOT add a README (we'll push our own code)
# 5. Click 'Create repository'
# 6. Copy the HTTPS URL — it will look like: https://github.com/YOUR-USERNAME/devops-lab1.git
Containerise the App
Develop a small application and package it inside a Docker container to ensure it runs consistently across any environment. Containerizing the application isolates it from system-level differences, making it portable, reproducible, and easy to deploy on any machine or cloud platform.
1. Create Your First App
This step initializes a local project directory, creates a simple Node.js application, tracks it using Git version control, and links the local repository to a remote GitHub repository. This ensures that all code changes are properly recorded, versioned, and synchronized with a central remote source.
From the beginning of development, integrating with GitHub ensures that your work is securely backed up, easily shareable, and ready for integration into CI/CD pipelines for automated testing and deployment.
Applying version control from the start establishes a reliable and traceable development workflow. It supports consistency, recoverability, and automation readiness, which are key principles of operational excellence in modern DevOps practices.
# Creates a new directory (folder).
mkdir devops-lab && cd devops-lab
# Let's create an app.js file. The '>' symbol redirects the 'echo' text into the file.
# ALTERNATIVE: You can just open a text editor (like VS Code or Notepad), create a new file called 'app.js', type 'console.log("Hello, DevOps!");' and save it!
# Prints text to the terminal — also used to write to files with > or >>.
echo 'console.log("Hello, DevOps!");' > app.js
# Initializes a new Git repository in the current directory.
git init
# Lists, creates, or manages branches.
git branch -M main
# Stages all changed files for the next commit.
git add . && git commit -m 'Initial commit'
# Now connect your local repo to the GitHub repo you created in Mission 1
# Replace YOUR-USERNAME with your actual GitHub username
# Stages the specified file(s) for the next commit.
git remote add origin https://github.com/YOUR-USERNAME/devops-lab1.git
# Manages remote repository connections (origin, upstream, etc.).
git remote -v
2. Build the Docker Container
This step involves creating a Dockerfile, which defines the instructions required to package an application into a Docker image, then building that image and running it as a container. This process standardizes how the application is built and executed across environments.
By containerizing the application, you ensure consistency between development, testing, and production environments. This eliminates environment-specific issues such as dependency mismatches or configuration differences, commonly referred to as “it works on my machine” problems.
Containerization improves system reliability by providing consistent, immutable runtime environments. This ensures applications behave predictably across all stages of deployment, reducing failures and improving confidence in releases.
# Here, 'printf' prints formatted text and '>' saves it into a file called 'Dockerfile'.
# ALTERNATIVE: Open your text editor, create 'Dockerfile', paste the 3 lines starting with FROM, COPY, and CMD, then save it.
# Prints formatted text — more control than echo (like C's printf).
printf 'FROM node:18-alpine\nCOPY app.js .\nCMD ["node","app.js"]\n' > Dockerfile
# Builds a Docker image from the Dockerfile in the current directory. The -t flag tags it with a name.
docker build -t devops-helloo .
# Creates and starts a new container from the specified image.
docker run --rm devops-helloo
Measure DORA Metrics
Learn the key performance indicators known as DORA metrics, which high-performing DevOps teams use to measure software delivery efficiency, stability, and overall engineering effectiveness. These metrics help evaluate and improve how quickly and reliably teams deliver changes to production.
1. Simulate a Super-Fast Deployment
This step creates an additional Git commit to simulate the process of delivering a new feature to a codebase. Each commit represents a versioned change, similar to how features are incrementally shipped in real software development workflows.
Frequent commits and deployments reflect a key DevOps performance indicator known as Deployment Frequency, which measures how often code changes are released into production. High-performing DevOps teams aim for frequent, small, and reliable deployments rather than large, infrequent releases.
Increasing deployment frequency demonstrates improved delivery speed and responsiveness. It supports agile development practices by enabling rapid iteration, faster feedback loops, and continuous delivery of value to users.
# Make a quick change and commit it
# Prints text to the terminal — also used to write to files with > or >>.
echo 'v2' >> app.js
# Stages all changed files for the next commit.
git add . && git commit -m 'feat: bump to v2'
# Shows the commit history. --oneline condenses each commit to one line, --graph shows branches visually.
git log --oneline
Automate with a Robot Butler (Make)
Instead of repeatedly typing long and complex commands, you can create a Makefile to automate and simplify repetitive tasks. A Makefile defines a set of instructions that can be executed with a single command, improving efficiency, consistency, and reducing the chance of human error during development workflows.
1. Write the Automation Script (Makefile)
This step involves creating a Makefile that defines reusable shortcuts (such as build, run, and clean) to automate long and repetitive Docker and development commands. Instead of manually typing complex instructions, a Makefile allows you to execute them using simple, consistent commands.
This improves workflow efficiency by reducing manual effort, minimizing human errors, and ensuring that common tasks are executed in a standardized way across all environments.
Automation of repetitive development tasks is a key principle of operational excellence. By using Makefiles, developers improve consistency, productivity, and reliability, while freeing up time to focus on higher-value engineering work.
# 'printf' writes our commands with literal tab characters (\t) to create a syntactically correct Makefile.
# ALTERNATIVE SIMPLER WAY: Open a text editor, create a file named 'Makefile', and manually type the build, run, and clean sections. (Make sure to use real tabs for indentation, not spaces!)
# Prints formatted text — more control than echo (like C's printf).
printf 'build:\n\tdocker build -t devops-helloo .\nrun:\n\tdocker run --rm devops-helloo\nclean:\n\tdocker rmi devops-helloo\n' > Makefile
Test Your New Butler
This step executes the automation defined in your Makefile by running predefined shortcuts to build a Docker image, start the application container, and clean up unused resources. It validates that your automated commands work correctly and produce the expected results in a local environment.
Testing automation locally is a critical practice before applying it to production systems, as it helps identify errors early and ensures that build, run, and cleanup processes behave consistently.
Verifying automation ensures that workflows are predictable, repeatable, and error-free. This strengthens system reliability by reducing deployment failures and ensuring that automated processes behave consistently across different environments.
make build
make run
make clean
Tag the Production Release
Assign a version number (tag) to your codebase using Git to mark a stable release point. This creates a clear reference for future deployments, enabling easier tracking, rollback, and release management in a controlled software development lifecycle.
1. Create a Release Tag
This step finalizes your code changes by committing any remaining work and applying a version tag (e.g., v1.0.0) to mark a stable release point in the Git history. Tags act as immutable references that identify specific states of the codebase, making it easier to track releases and manage deployments.
In a CI/CD pipeline, new version tags can automatically trigger build, test, and deployment processes, ensuring that only validated and stable versions are promoted to production environments.
Version tagging improves system reliability by creating clear, identifiable release points. This enables safe rollbacks, consistent deployments, and better traceability across the software delivery lifecycle.
# Stages all changed files for the next commit.
git add . && git commit -m 'feat: add Makefile automation'
# Creates a tag (label) on a commit — typically used for release versions (v1.0, v2.0).
git tag -a v1.0.0 -m 'First epic DevOps lab release!'
# Shows the commit history. --oneline condenses each commit to one line, --graph shows branches visually.
git log --oneline --decorate
2. Push Everything to GitHub
This step pushes all local Git commits and the version tag (e.g., v1.0.0) to a remote GitHub repository, synchronizing your local development history with a centralized version control system. This ensures that your code and release versions are securely stored and accessible in a shared environment.
In real DevOps workflows, code must live in a remote repository rather than only on a local machine. Pushing changes to GitHub enables collaboration across teams, provides reliable backup, and acts as a trigger point for CI/CD pipelines that automate testing, building, and deployment processes.
Publishing code to a remote repository is essential for enabling team-based development and automated delivery workflows. It ensures that changes are shared, traceable, and ready for continuous integration and deployment across environments.
# Push all your commits to GitHub
# Uploads your local commits to the remote repository.
git push -u origin main
# If you get an error about 'main', your default branch might be called 'master' — try:
# git push -u origin master
# Push your release tag too
# Uploads your local commits to the remote repository.
git push origin v1.0.0
# Prints text to the terminal — also used to write to files with > or >>.
echo ''
# Prints text to the terminal — also used to write to files with > or >>.
echo ' 🎉 CONGRATULATIONS! 🎉'
# Prints text to the terminal — also used to write to files with > or >>.
echo ' ✅ v1.0.0 is tagged and pushed to GitHub!'
# Prints text to the terminal — also used to write to files with > or >>.
echo ' 🌐 Check your repo at: https://github.com/YOUR-USERNAME/devops-lab'
# Prints text to the terminal — also used to write to files with > or >>.
echo ''
# Prints text to the terminal — also used to write to files with > or >>.
echo 'Next up: CI/CD Pipelines with GitHub Actions'
# Prints text to the terminal — also used to write to files with > or >>.
echo '================================================'
DevOps is a transformative approach that enables organizations to deliver software faster, more reliably, and at scale. By combining automation, collaboration, and continuous improvement, DevOps bridges the gap between development and operations, making it a cornerstone of modern cloud-native engineering practices.
Whether you are a developer, system administrator, or aspiring cloud engineer, understanding DevOps is essential for working in today’s technology landscape.










Top comments (1)
Nice