All posts

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:

code
# 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

code
# Solution: Resolve conflicts manually, then
git add <resolved-files>
git commit -m "fix: Resolve merge conflicts"

Problem: Accidentally committed sensitive data

code
# 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:

code
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

code
# 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

code
# 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:

code
# 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:

code
# 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:

code
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

code
# 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

code
# 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:

code
# 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:

code
# 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:

code
# 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:

code
// 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

code
// 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:

code
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:

code
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


Ready to dive deeper? Check out our hands-on tutorials on Docker, Kubernetes, CI/CD pipelines, and more!