DevOps 101: Complete Guide to Modern Engineering Practices
· Pavan Y N · devops, fundamentals, cicd, culture, best-practices
Published: October 30, 2025
Reading Time: 25 minutes
Tags: DevOps, CI/CD, Culture, Best Practices, Fundamentals
# Introduction
DevOps has revolutionized how we build, deploy, and maintain software systems. It's not just a set of tools or practices—it's a cultural shift that breaks down silos between development and operations teams, enabling faster delivery of high-quality software.
In this comprehensive guide, we'll explore DevOps from the ground up, covering core concepts, practices, tools, and emerging trends that every modern engineer should know.
# What is DevOps?
DevOps is a culture, mindset, and set of practices that combines software development (Dev) and IT operations (Ops) to shorten the development lifecycle and deliver high-quality software continuously.
## The Problem DevOps Solves
Traditional software development followed a waterfall model where:
- →Developers wrote code in isolation
- →Operations teams received code "over the wall"
- →Deployment was manual, error-prone, and infrequent
- →Feedback loops were slow, taking weeks or months
This created friction, delays, and quality issues.
## The DevOps Solution
DevOps addresses these challenges through:
- →Collaboration: Breaking down silos between teams
- →Automation: Eliminating manual, repetitive tasks
- →Continuous Feedback: Rapid iteration based on real data
- →Shared Responsibility: Everyone owns the entire lifecycle
# The DevOps Lifecycle: The Infinite Loop
DevOps operates as a continuous cycle, often visualized as an infinity loop:
## 1. Plan
- →Define requirements and user stories
- →Prioritize features and bug fixes
- →Use tools like Jira, Azure Boards, or GitHub Projects
## 2. Code
- →Write application code
- →Implement version control with Git
- →Conduct code reviews and pair programming
- →Follow coding standards and best practices
## 3. Build
- →Compile source code
- →Create deployable artifacts (JARs, Docker images, etc.)
- →Run unit tests
- →Tools: Maven, Gradle, npm, Docker
## 4. Test
- →Execute automated tests (unit, integration, E2E)
- →Perform security scanning
- →Validate code quality
- →Tools: JUnit, Selenium, SonarQube
## 5. Release
- →Package application for deployment
- →Create release notes
- →Version artifacts
- →Store in artifact repositories (Nexus, Artifactory)
## 6. Deploy
- →Deploy to target environments
- →Use blue-green or canary deployments
- →Automate with CI/CD pipelines
- →Tools: Jenkins, GitLab CI, GitHub Actions
## 7. Operate
- →Manage production infrastructure
- →Handle scaling and load balancing
- →Perform routine maintenance
- →Tools: Kubernetes, Terraform, Ansible
## 8. Monitor
- →Track application performance
- →Collect logs and metrics
- →Set up alerts for anomalies
- →Tools: Prometheus, Grafana, ELK Stack
# Core DevOps Practices
## 1. Version Control
Concept: Version control systems track changes to code over time, enabling collaboration and providing a history of modifications.
Why It Matters:
- →Single source of truth for all code
- →Enables parallel development
- →Facilitates code reviews
- →Provides rollback capabilities
Implementation with Git:
# Initialize a repository
git init
# Configure your identity
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# Stage and commit changes
git add .
git commit -m "feat: Add user authentication module"
# Push to remote repository
git push origin main
Best Practices:
- →Use meaningful commit messages (follow Conventional Commits)
- →Create feature branches for new work
- →Require pull requests for code review
- →Protect main/master branch from direct commits
- →Use .gitignore to exclude sensitive files
Common Issues & Solutions:
Problem: Merge conflicts
# Solution: Resolve conflicts manually, then
git add <resolved-files>
git commit -m "fix: Resolve merge conflicts"
Problem: Accidentally committed sensitive data
# Solution: Remove from history
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch path/to/sensitive/file' \
--prune-empty --tag-name-filter cat -- --all
## 2. Continuous Integration/Continuous Deployment (CI/CD)
Concept: CI/CD automates the process of integrating code changes, running tests, and deploying to production.
Continuous Integration (CI):
- →Developers merge code frequently (multiple times per day)
- →Automated builds and tests run on every commit
- →Fast feedback on code quality
Continuous Deployment (CD):
- →Automated deployment to staging/production
- →Every change that passes tests goes live
- →Reduces deployment risk through small, frequent releases
Example: GitHub Actions Pipeline:
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage
- name: Build application
run: npm run build
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
deploy:
needs: build-and-test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to production
run: |
echo "Deploying to production..."
# Add deployment commands here
STAR Approach for CI/CD:
Situation: Team was deploying manually once per week, leading to large, risky releases and slow feedback.
Task: Implement automated CI/CD pipeline to enable multiple daily deployments.
Action:
- →Set up GitHub Actions workflow
- →Automated testing (unit, integration, E2E)
- →Implemented blue-green deployment strategy
- →Added automated rollback on failure
- →Created deployment notifications in Slack
Result:
- →Deployment frequency increased from weekly to 10+ times per day
- →Deployment time reduced from 2 hours to 10 minutes
- →Production incidents decreased by 60%
- →Mean time to recovery (MTTR) improved from 4 hours to 30 minutes
Common Issues & Troubleshooting:
Problem: Flaky tests causing pipeline failures
# Solution: Retry failed tests
- name: Run tests with retry
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
command: npm test
Problem: Slow pipeline execution
# Solution: Parallelize jobs and use caching
jobs:
test-unit:
runs-on: ubuntu-latest
steps:
- uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
test-integration:
runs-on: ubuntu-latest
# Runs in parallel with test-unit
## 3. Containerization with Docker
Concept: Containers package applications with all dependencies into isolated, portable units that run consistently across environments.
Why Containers?:
- →Consistency: "Works on my machine" problem solved
- →Isolation: Applications don't interfere with each other
- →Portability: Run anywhere (dev, staging, production)
- →Efficiency: Lightweight compared to VMs
Docker Architecture:
- →Images: Read-only templates for containers
- →Containers: Running instances of images
- →Dockerfile: Instructions to build an image
- →Registry: Storage for images (Docker Hub, ECR, etc.)
Example Dockerfile:
# Use official Node.js runtime as base image
FROM node:20-alpine AS builder
# Set working directory
WORKDIR /usr/src/app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Build application
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /usr/src/app
# Copy built artifacts from builder
COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules
COPY package*.json ./
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js
# Start application
CMD ["node", "dist/server.js"]
Docker Commands:
# Build image
docker build -t myapp:1.0.0 .
# Run container
docker run -d -p 3000:3000 --name myapp-container myapp:1.0.0
# View running containers
docker ps
# View logs
docker logs myapp-container
# Execute command in container
docker exec -it myapp-container sh
# Stop and remove container
docker stop myapp-container
docker rm myapp-container
# Push to registry
docker tag myapp:1.0.0 myregistry.azurecr.io/myapp:1.0.0
docker push myregistry.azurecr.io/myapp:1.0.0
Docker Compose for Multi-Container Apps:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://db:5432/myapp
depends_on:
- db
- redis
networks:
- app-network
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=secret
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
redis:
image: redis:7-alpine
networks:
- app-network
volumes:
postgres-data:
networks:
app-network:
driver: bridge
Common Issues & Solutions:
Problem: Image size too large
# Solution: Use multi-stage builds and alpine images
FROM node:20-alpine AS builder
# Build stage...
FROM node:20-alpine
# Only copy necessary files
COPY --from=builder /usr/src/app/dist ./dist
Problem: Container can't connect to database
# Solution: Check network connectivity
docker network ls
docker network inspect app-network
# Ensure containers are on same network
docker run --network app-network myapp:1.0.0
## 4. Infrastructure as Code (IaC)
Concept: Managing infrastructure through code rather than manual processes, enabling version control, automation, and reproducibility.
Benefits:
- →Reproducibility: Create identical environments
- →Version Control: Track infrastructure changes
- →Automation: Provision infrastructure programmatically
- →Documentation: Code serves as documentation
Example: Terraform:
# Configure AWS provider
provider "aws" {
region = "us-west-2"
}
# Create VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "main-vpc"
Environment = "production"
}
}
# Create subnet
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "us-west-2a"
map_public_ip_on_launch = true
tags = {
Name = "public-subnet"
}
}
# Create security group
resource "aws_security_group" "web" {
name = "web-sg"
description = "Security group for web servers"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "web-security-group"
}
}
# Create EC2 instance
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y docker
systemctl start docker
systemctl enable docker
EOF
tags = {
Name = "web-server"
}
}
# Output public IP
output "instance_public_ip" {
value = aws_instance.web.public_ip
}
Terraform Workflow:
# Initialize Terraform
terraform init
# Preview changes
terraform plan
# Apply changes
terraform apply
# Destroy infrastructure
terraform destroy
STAR Approach for IaC:
Situation: Manual infrastructure provisioning took 2-3 days and was error-prone.
Task: Implement Infrastructure as Code to automate and standardize provisioning.
Action:
- →Migrated all infrastructure to Terraform
- →Created reusable modules for common patterns
- →Implemented state management with remote backend
- →Added automated testing with Terratest
- →Set up CI/CD for infrastructure changes
Result:
- →Provisioning time reduced from days to 15 minutes
- →Configuration errors decreased by 80%
- →Environment parity improved (dev matches production)
- →Infrastructure changes now peer-reviewed like code
## 5. Observability
Concept: Understanding system behavior through metrics, logs, and traces—the three pillars of observability.
The Three Pillars:
1. Metrics: Numerical data aggregated over time
- →CPU usage, memory consumption
- →Request rate, error rate
- →Response time, throughput
2. Logs: Timestamped records of discrete events
- →Application logs
- →Access logs
- →Error logs
3. Traces: Lifecycle of requests across services
- →Distributed tracing
- →Request flow visualization
- →Performance bottleneck identification
Example: Prometheus + Grafana Setup:
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'node-app'
static_configs:
- targets: ['localhost:3000']
metrics_path: '/metrics'
- job_name: 'node-exporter'
static_configs:
- targets: ['localhost:9100']
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
rule_files:
- 'alerts.yml'
Application Instrumentation:
// Node.js with Prometheus client
const express = require('express');
const promClient = require('prom-client');
const app = express();
// Create metrics
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests in seconds',
labelNames: ['method', 'route', 'status_code']
});
const httpRequestTotal = new promClient.Counter({
name: 'http_requests_total',
help: 'Total number of HTTP requests',
labelNames: ['method', 'route', 'status_code']
});
// Middleware to track metrics
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = (Date.now() - start) / 1000;
const labels = {
method: req.method,
route: req.route?.path || req.path,
status_code: res.statusCode
};
httpRequestDuration.observe(labels, duration);
httpRequestTotal.inc(labels);
});
next();
});
// Metrics endpoint
app.get('/metrics', async (req, res) => {
res.set('Content-Type', promClient.register.contentType);
res.end(await promClient.register.metrics());
});
app.listen(3000);
Common Issues & Troubleshooting:
Problem: High cardinality metrics causing performance issues
// Bad: Using user ID as label (high cardinality)
const counter = new promClient.Counter({
name: 'requests_total',
labelNames: ['user_id'] // DON'T DO THIS
});
// Good: Use aggregated labels
const counter = new promClient.Counter({
name: 'requests_total',
labelNames: ['user_type'] // 'free', 'premium', 'enterprise'
});
# The DevOps Toolkit
## Essential Tools by Category
Version Control:
- →Git, GitHub, GitLab, Bitbucket
CI/CD:
- →Jenkins, GitLab CI, GitHub Actions, CircleCI, Azure DevOps
Containerization:
- →Docker, Podman, containerd
Orchestration:
- →Kubernetes, Docker Swarm, Amazon ECS
Infrastructure as Code:
- →Terraform, Pulumi, CloudFormation, ARM Templates
Configuration Management:
- →Ansible, Chef, Puppet, SaltStack
Monitoring & Observability:
- →Prometheus, Grafana, ELK Stack, Datadog, New Relic
Cloud Platforms:
- →AWS, Azure, Google Cloud Platform
Security:
- →HashiCorp Vault, AWS Secrets Manager, Snyk, Aqua Security
# Emerging Trends in DevOps
## 1. DevSecOps
Concept: Integrating security into every phase of the DevOps lifecycle—"shifting left" to catch vulnerabilities early.
Key Practices:
- →Static Application Security Testing (SAST)
- →Dynamic Application Security Testing (DAST)
- →Software Composition Analysis (SCA)
- →Container image scanning
- →Infrastructure security scanning
Example: Security in CI/CD:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run SAST with SonarQube
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: Dependency vulnerability scan
run: npm audit --audit-level=high
- name: Container image scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:latest'
severity: 'CRITICAL,HIGH'
## 2. Platform Engineering
Concept: Building Internal Developer Platforms (IDPs) that provide self-service capabilities and "paved roads" for developers.
Benefits:
- →Reduced cognitive load for developers
- →Standardized toolchains and workflows
- →Faster onboarding
- →Improved developer experience
Components of an IDP:
- →Service catalog
- →Self-service provisioning
- →Automated CI/CD pipelines
- →Centralized observability
- →Documentation portal
## 3. GitOps
Concept: Using Git as the single source of truth for declarative infrastructure and applications.
Principles:
- →Declarative configuration stored in Git
- →Automated synchronization to desired state
- →Version control for all changes
- →Easy rollback capabilities
Example: ArgoCD for Kubernetes:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/myapp
targetRevision: HEAD
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
## 4. FinOps
Concept: Financial operations for cloud—managing and optimizing cloud costs.
Key Practices:
- →Cost visibility and allocation
- →Resource right-sizing
- →Reserved instance planning
- →Automated cost optimization
## 5. AIOps
Concept: Using AI and machine learning for IT operations—anomaly detection, predictive analytics, and automated remediation.
Use Cases:
- →Anomaly detection in metrics
- →Log analysis and pattern recognition
- →Predictive capacity planning
- →Automated incident response
# Best Practices for DevOps Success
## 1. Start Small, Think Big
- →Begin with one team or project
- →Prove value before scaling
- →Learn from failures
## 2. Automate Everything
- →If you do it more than twice, automate it
- →Eliminate manual toil
- →Focus on high-value work
## 3. Measure Everything
- →Define key metrics (DORA metrics)
- →Track deployment frequency
- →Monitor lead time for changes
- →Measure MTTR and change failure rate
## 4. Foster a Culture of Learning
- →Conduct blameless postmortems
- →Share knowledge through documentation
- →Encourage experimentation
- →Celebrate failures as learning opportunities
## 5. Security is Everyone's Responsibility
- →Integrate security from the start
- →Automate security testing
- →Regular security training
- →Implement least privilege access
# Conclusion
DevOps is a journey, not a destination. It requires continuous learning, adaptation, and improvement. By embracing DevOps culture, implementing core practices, leveraging the right tools, and staying current with emerging trends, teams can deliver software faster, more reliably, and with higher quality.
Remember: DevOps is about people, processes, and tools—in that order. Technology enables DevOps, but culture makes it successful.
# Additional Resources
- →The Phoenix Project - Novel about DevOps transformation
- →The DevOps Handbook - Comprehensive guide to DevOps practices
- →DORA State of DevOps Report - Annual research on DevOps performance
- →12 Factor App - Methodology for building SaaS applications
- →CNCF Landscape - Cloud native technology ecosystem
Ready to dive deeper? Check out our hands-on tutorials on Docker, Kubernetes, CI/CD pipelines, and more!