Claude
Skills
Sign in
Back

modern-automation-patterns

Included with Lifetime
$97 forever

Modern DevOps and CI/CD bash automation patterns with containers and cloud (2025). PROACTIVELY activate for: (1) writing CI/CD scripts (GitHub Actions, GitLab CI, Azure DevOps), (2) container-aware shell scripting (detecting containers, Kubernetes pods), (3) cloud provider helpers (AWS CLI, Azure CLI, gcloud), (4) blue-green and canary deployments via bash, (5) writing idempotent rollback scripts, (6) integrating with Docker/Compose from bash, (7) cross-environment variable management, (8) build matrix orchestration. Provides: copy-pasteable CI snippets, container detection helpers, cloud CLI wrappers, deployment orchestration patterns, and idempotent rollback templates.

Cloud & DevOps

What this skill does


## 🚨 CRITICAL GUIDELINES

### Windows File Path Requirements

**MANDATORY: Always Use Backslashes on Windows for File Paths**

When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).

**Examples:**
- ❌ WRONG: `D:/repos/project/file.tsx`
- ✅ CORRECT: `D:\repos\project\file.tsx`

This applies to:
- Edit tool file_path parameter
- Write tool file_path parameter
- All file operations on Windows systems


### Documentation Guidelines

**NEVER create new documentation files unless explicitly requested by the user.**

- **Priority**: Update existing README.md files rather than creating new documentation
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
- **User preference**: Only create additional .md files when user specifically asks for documentation


---

# Modern Automation Patterns (2025)

## Overview

Production-ready patterns for DevOps automation, CI/CD pipelines, and cloud-native operations following 2025 industry standards.

## Container-Aware Scripting

### Docker/Kubernetes Detection

```bash
#!/usr/bin/env bash
set -euo pipefail

# Detect container environment
detect_container() {
    if [[ -f /.dockerenv ]]; then
        echo "docker"
    elif grep -q docker /proc/1/cgroup 2>/dev/null; then
        echo "docker"
    elif [[ -n "${KUBERNETES_SERVICE_HOST:-}" ]]; then
        echo "kubernetes"
    else
        echo "host"
    fi
}

# Container-aware configuration
readonly CONTAINER_ENV=$(detect_container)

case "$CONTAINER_ENV" in
    docker|kubernetes)
        # Container-specific paths
        DATA_DIR="/data"
        CONFIG_DIR="/config"
        ;;
    host)
        # Host-specific paths
        DATA_DIR="/var/lib/app"
        CONFIG_DIR="/etc/app"
        ;;
esac
```

### Minimal Container Scripts

```bash
#!/bin/sh
# Use /bin/sh for Alpine-based containers (no bash)

set -eu  # Note: No pipefail in POSIX sh

# Check if running as PID 1
if [ $$ -eq 1 ]; then
    # PID 1 must handle signals properly
    trap 'kill -TERM $child 2>/dev/null' TERM INT

    # Start main process in background
    /app/main &
    child=$!

    # Wait for child
    wait "$child"
else
    # Not PID 1, run directly
    exec /app/main
fi
```

### Health Check Scripts

```bash
#!/usr/bin/env bash
# healthcheck.sh - Container health probe

set -euo pipefail

# Quick health check (< 1 second)
check_health() {
    local timeout=1

    # Check process is running
    if ! pgrep -f "myapp" > /dev/null; then
        echo "Process not running" >&2
        return 1
    fi

    # Check HTTP endpoint
    if ! timeout "$timeout" curl -sf http://localhost:8080/health > /dev/null; then
        echo "Health endpoint failed" >&2
        return 1
    fi

    # Check critical files
    if [[ ! -f /app/ready ]]; then
        echo "Not ready" >&2
        return 1
    fi

    return 0
}

check_health
```

## CI/CD Pipeline Patterns

### GitHub Actions Helper

```bash
#!/usr/bin/env bash
# ci-helper.sh - GitHub Actions utilities

set -euo pipefail

# Detect GitHub Actions
is_github_actions() {
    [[ "${GITHUB_ACTIONS:-false}" == "true" ]]
}

# GitHub Actions output
gh_output() {
    local name="$1"
    local value="$2"

    if is_github_actions; then
        echo "${name}=${value}" >> "$GITHUB_OUTPUT"
    fi
}

# GitHub Actions annotations
gh_error() {
    if is_github_actions; then
        echo "::error::$*"
    else
        echo "ERROR: $*" >&2
    fi
}

gh_warning() {
    if is_github_actions; then
        echo "::warning::$*"
    else
        echo "WARN: $*" >&2
    fi
}

gh_notice() {
    if is_github_actions; then
        echo "::notice::$*"
    else
        echo "INFO: $*"
    fi
}

# Set job summary
gh_summary() {
    if is_github_actions; then
        echo "$*" >> "$GITHUB_STEP_SUMMARY"
    fi
}

# Usage example
gh_notice "Starting build"
build_result=$(make build 2>&1)
gh_output "build_result" "$build_result"
gh_summary "## Build Complete\n\nStatus: Success"
```

### Azure DevOps Helper

```bash
#!/usr/bin/env bash
# azdo-helper.sh - Azure DevOps utilities

set -euo pipefail

# Detect Azure DevOps
is_azure_devops() {
    [[ -n "${TF_BUILD:-}" ]]
}

# Azure DevOps output variable
azdo_output() {
    local name="$1"
    local value="$2"

    if is_azure_devops; then
        echo "##vso[task.setvariable variable=$name]$value"
    fi
}

# Azure DevOps logging
azdo_error() {
    if is_azure_devops; then
        echo "##vso[task.logissue type=error]$*"
    else
        echo "ERROR: $*" >&2
    fi
}

azdo_warning() {
    if is_azure_devops; then
        echo "##vso[task.logissue type=warning]$*"
    else
        echo "WARN: $*" >&2
    fi
}

# Section grouping
azdo_section_start() {
    is_azure_devops && echo "##[section]$*"
}

azdo_section_end() {
    is_azure_devops && echo "##[endsection]"
}

# Usage
azdo_section_start "Running Tests"
test_result=$(npm test)
azdo_output "test_result" "$test_result"
azdo_section_end
```

### Multi-Platform CI Detection

```bash
#!/usr/bin/env bash
set -euo pipefail

# Detect CI environment
detect_ci() {
    if [[ "${GITHUB_ACTIONS:-false}" == "true" ]]; then
        echo "github"
    elif [[ -n "${TF_BUILD:-}" ]]; then
        echo "azuredevops"
    elif [[ -n "${GITLAB_CI:-}" ]]; then
        echo "gitlab"
    elif [[ -n "${CIRCLECI:-}" ]]; then
        echo "circleci"
    elif [[ -n "${JENKINS_URL:-}" ]]; then
        echo "jenkins"
    else
        echo "local"
    fi
}

# Universal output
ci_output() {
    local name="$1"
    local value="$2"
    local ci_env
    ci_env=$(detect_ci)

    case "$ci_env" in
        github)
            echo "${name}=${value}" >> "$GITHUB_OUTPUT"
            ;;
        azuredevops)
            echo "##vso[task.setvariable variable=$name]$value"
            ;;
        gitlab)
            echo "${name}=${value}" >> ci_output.env
            ;;
        *)
            echo "export ${name}=\"${value}\""
            ;;
    esac
}

# Universal error
ci_error() {
    local ci_env
    ci_env=$(detect_ci)

    case "$ci_env" in
        github)
            echo "::error::$*"
            ;;
        azuredevops)
            echo "##vso[task.logissue type=error]$*"
            ;;
        *)
            echo "ERROR: $*" >&2
            ;;
    esac
}
```

## Cloud Provider Patterns

### AWS Helper Functions

```bash
#!/usr/bin/env bash
set -euo pipefail

# Check AWS CLI availability
require_aws() {
    if ! command -v aws &> /dev/null; then
        echo "Error: AWS CLI not installed" >&2
        exit 1
    fi
}

# Get AWS account ID
get_aws_account_id() {
    aws sts get-caller-identity --query Account --output text
}

# Get secret from AWS Secrets Manager
get_aws_secret() {
    local secret_name="$1"

    aws secretsmanager get-secret-value \
        --secret-id "$secret_name" \
        --query SecretString \
        --output text
}

# Upload to S3 with retry
s3_upload_retry() {
    local file="$1"
    local s3_path="$2"
    local max_attempts=3
    local attempt=1

    while ((attempt <= max_attempts)); do
        if aws s3 cp "$file" "$s3_path"; then
            return 0
        fi

        echo "Upload failed (attempt $attempt/$max_attempts)" >&2
        ((attempt++))
        sleep $((attempt * 2))
    done

    return 1
}

# Assume IAM role
assume_role() {
    local role_arn="$1"
    local session_name="${2:-bash-script}"

    local credentials
    credentials=$(aws sts assume-role \
        --role-arn "$role_arn" \
        --role-session-name "$session_name" \
        --query Credentials \
        --output json)

    export AWS_ACCESS_KEY_ID=$(echo "$credentials" | jq -r .AccessKeyId)
    export AWS_SECRET_ACCESS_KEY=$(echo "$credentials" | jq -r .SecretAccessKey)
    export AWS_SESSION_TOKEN=$(echo "$credentials" | jq -r .SessionToken)
}
```

### Azure Helper Functions

```bash
#!/usr/bin/env bash
set -euo pipefai

Related in Cloud & DevOps