DevOps Best Practices: From CI/CD to Infrastructure as Code
As a developer who has worked extensively with DevOps practices, I've learned that automation and infrastructure as code are key to maintaining reliable and scalable systems. Let's explore the essential practices and tools for modern DevOps.
CI/CD Pipeline Implementation
1. GitHub Actions Workflow
Create robust CI/CD pipelines:
# .github/workflows/main.yml name: CI/CD Pipeline on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: "18" cache: "npm" - name: Install dependencies run: npm ci - name: Run tests run: npm test - name: Run linting run: npm run lint - name: Run type checking run: npm run type-check build: needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: "18" cache: "npm" - name: Install dependencies run: npm ci - name: Build application run: npm run build - name: Upload build artifacts uses: actions/upload-artifact@v3 with: name: build path: dist/ deploy: needs: build if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - name: Download build artifacts uses: actions/download-artifact@v3 with: name: build path: dist/ - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-east-1 - name: Deploy to S3 run: | aws s3 sync dist/ s3://${{ secrets.AWS_S3_BUCKET }} --delete - name: Invalidate CloudFront run: | aws cloudfront create-invalidation \ --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \ --paths "/*"
2. Docker Configuration
Create optimized Docker images:
# Dockerfile # Build stage FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Production stage FROM node:18-alpine WORKDIR /app COPY /app/dist ./dist COPY /app/package*.json ./ RUN npm ci --only=production # Security: Run as non-root user USER node # Health check HEALTHCHECK \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 EXPOSE 3000 CMD ["npm", "start"]
Infrastructure as Code
1. Terraform Configuration
Manage cloud infrastructure:
# main.tf provider "aws" { region = "us-east-1" } # VPC Configuration module "vpc" { source = "terraform-aws-modules/vpc/aws" name = "my-vpc" cidr = "10.0.0.0/16" azs = ["us-east-1a", "us-east-1b"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] enable_nat_gateway = true single_nat_gateway = true tags = { Environment = "production" Terraform = "true" } } # ECS Cluster resource "aws_ecs_cluster" "main" { name = "my-ecs-cluster" setting { name = "containerInsights" value = "enabled" } } # Application Load Balancer module "alb" { source = "terraform-aws-modules/alb/aws" name = "my-alb" load_balancer_type = "application" vpc_id = module.vpc.vpc_id subnets = module.vpc.public_subnets security_groups = [aws_security_group.alb.id] target_groups = [ { name_prefix = "app-" backend_protocol = "HTTP" backend_port = 80 target_type = "ip" health_check = { path = "/health" healthy_threshold = 2 unhealthy_threshold = 2 timeout = 5 interval = 30 } } ] }
2. Kubernetes Configuration
Deploy applications to Kubernetes:
# deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-app namespace: production spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: my-app image: my-app:latest ports: - containerPort: 3000 resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "200m" memory: "256Mi" livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 3000 initialDelaySeconds: 5 periodSeconds: 5 env: - name: NODE_ENV value: "production" - name: DATABASE_URL valueFrom: secretKeyRef: name: app-secrets key: database-url --- apiVersion: v1 kind: Service metadata: name: my-app namespace: production spec: type: ClusterIP ports: - port: 80 targetPort: 3000 selector: app: my-app --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-app namespace: production annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-prod spec: rules: - host: app.example.com http: paths: - path: / pathType: Prefix backend: service: name: my-app port: number: 80 tls: - hosts: - app.example.com secretName: app-tls
Monitoring and Observability
1. Prometheus Configuration
Set up monitoring:
# prometheus.yml global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: "kubernetes-pods" kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) - job_name: "node-exporter" static_configs: - targets: ["localhost:9100"] alerting: alertmanagers: - static_configs: - targets: ["alertmanager:9093"] rule_files: - /etc/prometheus/rules/*.yml
2. Grafana Dashboard
Create monitoring dashboards:
{ "dashboard": { "id": null, "title": "Application Overview", "tags": ["kubernetes", "application"], "timezone": "browser", "panels": [ { "title": "Request Rate", "type": "graph", "datasource": "Prometheus", "targets": [ { "expr": "sum(rate(http_requests_total[5m])) by (status_code)", "legendFormat": "{{status_code}}" } ] }, { "title": "Response Time", "type": "graph", "datasource": "Prometheus", "targets": [ { "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))", "legendFormat": "95th percentile" } ] } ] } }
Best Practices
- Automate Everything: From testing to deployment
- Infrastructure as Code: Version control your infrastructure
- Monitoring and Alerting: Implement comprehensive monitoring
- Security First: Implement security at every stage
- Continuous Learning: Keep up with new tools and practices
Implementation Checklist
- Set up version control
- Implement CI/CD pipeline
- Configure infrastructure as code
- Set up container orchestration
- Implement monitoring and logging
- Configure automated backups
- Set up security scanning
- Document deployment processes
Conclusion
DevOps practices are essential for modern software development. Focus on automation, monitoring, and continuous improvement to build reliable and scalable systems.