devops-cicd

CI/CD pipelines, infrastructure as code, and deployment strategies

INSTALLATION
npx skills add https://github.com/miles990/claude-software-skills --skill devops-cicd
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

DevOps & CI/CD

Overview

Practices for automating build, test, and deployment pipelines.

CI/CD Pipeline

Pipeline Stages

┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐

│  Commit  │ → │  Build   │ → │   Test   │ → │  Deploy  │ → │ Release  │

│          │   │          │   │          │   │ Staging  │   │   Prod   │

└──────────┘   └──────────┘   └──────────┘   └──────────┘   └──────────┘

     │              │              │              │              │

     │         ┌────┴────┐    ┌────┴────┐        │              │

     │         │ Compile │    │  Unit   │        │              │

     │         │  Lint   │    │  Integ  │        │              │

     │         │  Type   │    │   E2E   │        │              │

     │         └─────────┘    └─────────┘        │              │

     │                                           │              │

   Trigger                                    Manual?       Approval?

GitHub Actions

# .github/workflows/ci.yml

name: CI

on:

  push:

    branches: [main]

  pull_request:

    branches: [main]

jobs:

  build:

    runs-on: ubuntu-latest

    steps:

      - uses: actions/checkout@v4

      - name: Setup Node.js

        uses: actions/setup-node@v4

        with:

          node-version: '20'

          cache: 'npm'

      - name: Install dependencies

        run: npm ci

      - name: Lint

        run: npm run lint

      - name: Type check

        run: npm run type-check

      - name: Test

        run: npm run test -- --coverage

      - name: Upload coverage

        uses: codecov/codecov-action@v3

      - name: Build

        run: npm run build

      - name: Upload build artifact

        uses: actions/upload-artifact@v4

        with:

          name: build

          path: dist/

  deploy-staging:

    needs: build

    if: github.ref == 'refs/heads/main'

    runs-on: ubuntu-latest

    environment: staging

    steps:

      - name: Download build artifact

        uses: actions/download-artifact@v4

        with:

          name: build

          path: dist/

      - name: Deploy to staging

        run: |

          # Deploy script here

          echo "Deploying to staging..."

  deploy-production:

    needs: deploy-staging

    runs-on: ubuntu-latest

    environment:

      name: production

      url: https://myapp.com

    steps:

      - name: Deploy to production

        run: |

          echo "Deploying to production..."

Matrix Builds

jobs:

  test:

    runs-on: ${{ matrix.os }}

    strategy:

      matrix:

        os: [ubuntu-latest, windows-latest, macos-latest]

        node: [18, 20, 22]

        exclude:

          - os: windows-latest

            node: 18

    steps:

      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4

        with:

          node-version: ${{ matrix.node }}

      - run: npm ci

      - run: npm test

Deployment Strategies

Blue-Green Deployment

Before:

┌─────────────────────────────────────────┐

│           Load Balancer                  │

└─────────────────┬───────────────────────┘

                  │

          ┌───────┴───────┐

          ↓               ↓

    ┌───────────┐   ┌───────────┐

    │  Blue     │   │  Green    │

    │  (v1.0)   │   │  (idle)   │

    │  ACTIVE   │   │           │

    └───────────┘   └───────────┘

Deploy v1.1 to Green:

    ┌───────────┐   ┌───────────┐

    │  Blue     │   │  Green    │

    │  (v1.0)   │   │  (v1.1)   │

    │  ACTIVE   │   │  testing  │

    └───────────┘   └───────────┘

Switch traffic:

          ┌───────────────┐

          ↓               ↓

    ┌───────────┐   ┌───────────┐

    │  Blue     │   │  Green    │

    │  (v1.0)   │   │  (v1.1)   │

    │  standby  │   │  ACTIVE   │

    └───────────┘   └───────────┘

Canary Deployment

# Kubernetes canary with Argo Rollouts

apiVersion: argoproj.io/v1alpha1

kind: Rollout

metadata:

  name: my-app

spec:

  replicas: 10

  strategy:

    canary:

      steps:

        - setWeight: 10        # 10% traffic to new version

        - pause: { duration: 5m }

        - setWeight: 30

        - pause: { duration: 5m }

        - setWeight: 50

        - pause: { duration: 10m }

        - setWeight: 100

      analysis:

        templates:

          - templateName: success-rate

        startingStep: 2        # Start analysis at 30%

        args:

          - name: service-name

            value: my-app

Rolling Update

# Kubernetes rolling update

apiVersion: apps/v1

kind: Deployment

metadata:

  name: my-app

spec:

  replicas: 4

  strategy:

    type: RollingUpdate

    rollingUpdate:

      maxSurge: 1        # Can exceed replicas by 1

      maxUnavailable: 0  # All must be available during update

  template:

    spec:

      containers:

        - name: app

          image: my-app:v1.1

          readinessProbe:

            httpGet:

              path: /health

              port: 8080

            initialDelaySeconds: 5

            periodSeconds: 5

Infrastructure as Code

Terraform

# main.tf

terraform {

  required_providers {

    aws = {

      source  = "hashicorp/aws"

      version = "~> 5.0"

    }

  }

  backend "s3" {

    bucket = "my-terraform-state"

    key    = "prod/terraform.tfstate"

    region = "us-east-1"

  }

}

# Variables

variable "environment" {

  type    = string

  default = "production"

}

variable "instance_count" {

  type    = number

  default = 2

}

# Resources

resource "aws_vpc" "main" {

  cidr_block = "10.0.0.0/16"

  tags = {

    Name        = "main-vpc"

    Environment = var.environment

  }

}

resource "aws_instance" "web" {

  count         = var.instance_count

  ami           = "ami-0c55b159cbfafe1f0"

  instance_type = "t3.micro"

  vpc_security_group_ids = [aws_security_group.web.id]

  tags = {

    Name = "web-${count.index}"

  }

}

# Outputs

output "instance_ips" {

  value = aws_instance.web[*].public_ip

}

Terraform Modules

# modules/vpc/main.tf

variable "cidr_block" {

  type = string

}

variable "environment" {

  type = string

}

resource "aws_vpc" "this" {

  cidr_block = var.cidr_block

  tags = {

    Environment = var.environment

  }

}

output "vpc_id" {

  value = aws_vpc.this.id

}

# Using the module

module "vpc" {

  source      = "./modules/vpc"

  cidr_block  = "10.0.0.0/16"

  environment = "production"

}

resource "aws_subnet" "main" {

  vpc_id = module.vpc.vpc_id

  # ...

}

Docker

Dockerfile Best Practices

# Use specific version tags

FROM node:20-alpine AS builder

# Set working directory

WORKDIR /app

# Copy dependency files first (layer caching)

COPY package*.json ./

# Install dependencies

RUN npm ci --only=production

# Copy source code

COPY . .

# Build application

RUN npm run build

# Production stage - smaller final image

FROM node:20-alpine AS production

WORKDIR /app

# Create non-root user

RUN addgroup -g 1001 -S nodejs && \

    adduser -S nodejs -u 1001

# Copy from builder

COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist

COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules

# Use non-root user

USER nodejs

# Expose port

EXPOSE 3000

# Health check

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s \

  CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1

# Run application

CMD ["node", "dist/index.js"]

Docker Compose

# docker-compose.yml

version: '3.8'

services:

  app:

    build:

      context: .

      dockerfile: Dockerfile

    ports:

      - "3000:3000"

    environment:

      - DATABASE_URL=postgres://postgres:password@db:5432/myapp

      - REDIS_URL=redis://cache:6379

    depends_on:

      db:

        condition: service_healthy

      cache:

        condition: service_started

  db:

    image: postgres:15-alpine

    volumes:

      - postgres_data:/var/lib/postgresql/data

    environment:

      - POSTGRES_PASSWORD=password

      - POSTGRES_DB=myapp

    healthcheck:

      test: ["CMD-SHELL", "pg_isready -U postgres"]

      interval: 5s

      timeout: 5s

      retries: 5

  cache:

    image: redis:7-alpine

    volumes:

      - redis_data:/data

volumes:

  postgres_data:

  redis_data:

Kubernetes

Basic Deployment

# deployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: my-app

  labels:

    app: my-app

spec:

  replicas: 3

  selector:

    matchLabels:

      app: my-app

  template:

    metadata:

      labels:

        app: my-app

    spec:

      containers:

        - name: my-app

          image: my-app:v1.0.0

          ports:

            - containerPort: 3000

          resources:

            requests:

              memory: "128Mi"

              cpu: "100m"

            limits:

              memory: "256Mi"

              cpu: "500m"

          livenessProbe:

            httpGet:

              path: /health/live

              port: 3000

            initialDelaySeconds: 3

            periodSeconds: 10

          readinessProbe:

            httpGet:

              path: /health/ready

              port: 3000

            initialDelaySeconds: 5

            periodSeconds: 5

          env:

            - name: DATABASE_URL

              valueFrom:

                secretKeyRef:

                  name: app-secrets

                  key: database-url

---

apiVersion: v1

kind: Service

metadata:

  name: my-app

spec:

  selector:

    app: my-app

  ports:

    - port: 80

      targetPort: 3000

  type: ClusterIP

ConfigMaps and Secrets

# configmap.yaml

apiVersion: v1

kind: ConfigMap

metadata:

  name: app-config

data:

  LOG_LEVEL: "info"

  MAX_CONNECTIONS: "100"

---

# secret.yaml (base64 encoded)

apiVersion: v1

kind: Secret

metadata:

  name: app-secrets

type: Opaque

data:

  database-url: cG9zdGdyZXM6Ly91c2VyOnBhc3NAaG9zdDo1NDMyL2Ri

GitOps

ArgoCD Application

# application.yaml

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

  name: my-app

  namespace: argocd

spec:

  project: default

  source:

    repoURL: https://github.com/org/k8s-manifests.git

    targetRevision: HEAD

    path: apps/my-app/production

  destination:

    server: https://kubernetes.default.svc

    namespace: production

  syncPolicy:

    automated:

      prune: true

      selfHeal: true

    syncOptions:

      - CreateNamespace=true

Feature Flags

// Using LaunchDarkly / Unleash pattern

interface FeatureFlags {

  newCheckoutFlow: boolean;

  betaFeatures: boolean;

  maxUploadSize: number;

}

class FeatureFlagService {

  constructor(private client: FeatureFlagClient) {}

  async isEnabled(flag: keyof FeatureFlags, user?: User): Promise<boolean> {

    return this.client.getBooleanValue(flag, false, {

      userId: user?.id,

      email: user?.email,

      groups: user?.groups

    });

  }

}

// Usage

if (await featureFlags.isEnabled('newCheckoutFlow', user)) {

  return <NewCheckoutFlow />;

} else {

  return <LegacyCheckout />;

}

Related Skills

  • [[testing-strategies]] - CI test integration
  • [[reliability-engineering]] - Deployment reliability
  • [[monitoring-observability]] - Deployment monitoring
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card