mcpField
M
modern-automation-patterns

modern-automation-patterns

github.com/josiahsiegelクラウド・DevOps59160 回インストール19 週間前に更新
リポジトリ

modern-automation-patterns について

DevOps自動化、CI/CD、クラウドネイティブ運用向けのシェルスクリプトパターンをまとめたスキルです。運用スクリプトを書く開発者向けに、コンテナ検出、CI環境判定、デプロイ方式、ログ処理を扱います。

主な機能

  1. 01コンテナ検出とヘルスチェック
  2. 02CI環境判定のヘルパーパターン
  3. 03AWSとAzureのヘルパー関数
  4. 04並列ジョブ処理パターン
  5. 05ブルーグリーンとカナリアデプロイ
  6. 06構造化JSONログ

活用シーン

  1. 01コンテナ環境を考慮した運用スクリプトの作成
  2. 02パイプラインスクリプトでCIプロバイダーを判定
  3. 03段階的なアプリケーションデプロイの自動化
  4. 04シェルスクリプトから構造化ログを出力

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill modern-automation-patterns

インストール後、Claude Code で/modern-automation-patternsを入力して読み込まれたか確認します。

詳細

🚨 重要なガイドライン

Windows のファイルパス要件

必須:Windows ではファイルパスに必ずバックスラッシュを使用してください

Windows で Edit ツールまたは Write ツールを使用する場合、ファイルパスにはスラッシュ(/)ではなく、必ずバックスラッシュ(\)を使用してください。

例:

  • ❌ 誤り:D:/repos/project/file.tsx
  • ✅ 正しい:D:\repos\project\file.tsx

次に適用されます:

  • Edit ツールの file_path パラメーター
  • Write ツールの file_path パラメーター
  • Windows システムでのすべてのファイル操作
ドキュメント作成のガイドライン

ユーザーから明示的に依頼されない限り、新しいドキュメントファイルを作成しないでください。

  • 優先事項:新しいドキュメントを作成するのではなく、既存の README.md ファイルを更新してください
  • リポジトリの整理:ユーザーから別途依頼されない限り、リポジトリのルートには README.md 以外を置かないでください
  • スタイル:ドキュメントは簡潔、明瞭、専門的に記述し、AI が生成したような文体は避けてください
  • ユーザーの希望:ユーザーからドキュメント作成を明示的に依頼された場合にのみ、追加の .md ファイルを作成してください

最新の自動化パターン(2025)

概要

2025 年の業界標準に準拠した、DevOps の自動化、CI/CD パイプライン、クラウドネイティブ運用のための本番環境対応パターンです。

コンテナー対応スクリプト

Docker/Kubernetes の検出
#!/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
最小限のコンテナースクリプト
#!/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
ヘルスチェックスクリプト
#!/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 パイプラインのパターン

GitHub Actions ヘルパー
#!/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 ヘルパー
#!/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
マルチプラットフォーム CI の検出
#!/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
}

クラウドプロバイダーのパターン

AWS ヘルパー関数
#!/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 ヘルパー関数
#!/usr/bin/env bash
set -euo pipefail

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

# Get Azure subscription ID
get_az_subscription_id() {
    az account show --query id --output tsv
}

# Get secret from Azure Key Vault
get_keyvault_secret() {
    local vault_name="$1"
    local secret_name="$2"

    az keyvault secret show \
        --vault-name "$vault_name" \
        --name "$secret_name" \
        --query value \
        --output tsv
}

# Upload to Azure Blob Storage
az_blob_upload() {
    local file="$1"
    local container="$2"
    local blob_name="${3:-$(basename "$file")}"

    az storage blob upload \
        --file "$file" \
        --container-name "$container" \
        --name "$blob_name" \
        --overwrite
}

# Get managed identity token
get_managed_identity_token() {
    local resource="${1:-https://management.azure.com/}"

    curl -sf -H Metadata:true \
        "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$resource" \
        | jq -r .access_token
}

並列処理のパターン

GNU Parallel
#!/usr/bin/env bash
set -euo pipefail

# Check for GNU parallel
if command -v parallel &> /dev/null; then
    # Process files in parallel
    export -f process_file
    find data/ -name "*.json" | parallel -j 4 process_file {}
else
    # Fallback to bash background jobs
    max_jobs=4
    job_count=0

    for file in data/*.json; do
        process_file "$file" &

        ((job_count++))
        if ((job_count >= max_jobs)); then
            wait -n
            ((job_count--))
        fi
    done

    wait  # Wait for remaining jobs
fi
ジョブプールパターン
#!/usr/bin/env bash
set -euo pipefail

# Job pool implementation
job_pool_init() {
    readonly MAX_JOBS="${1:-4}"
    JOB_POOL_PIDS=()
}

job_pool_run() {
    # Wait if pool is full
    while ((${#JOB_POOL_PIDS[@]} >= MAX_JOBS)); do
        job_pool_wait_any
    done

    # Start new job
    "$@" &
    JOB_POOL_PIDS+=($!)
}

job_pool_wait_any() {
    # Wait for any job to finish
    if ((${#JOB_POOL_PIDS[@]} > 0)); then
        local pid
        wait -n
        # Remove finished PIDs
        for i in "${!JOB_POOL_PIDS[@]}"; do
            if ! kill -0 "${JOB_POOL_PIDS[$i]}" 2>/dev/null; then
                unset 'JOB_POOL_PIDS[$i]'
            fi
        done
        JOB_POOL_PIDS=("${JOB_POOL_PIDS[@]}")  # Reindex
    fi
}

job_pool_wait_all() {
    wait
    JOB_POOL_PIDS=()
}

# Usage
job_pool_init 4
for file in data/*.txt; do
    job_pool_run process_file "$file"
done
job_pool_wait_all

デプロイのパターン

ブルーグリーンデプロイ
#!/usr/bin/env bash
set -euo pipefail

# Blue-green deployment helper
deploy_blue_green() {
    local new_version="$1"
    local health_check_url="$2"

    echo "Starting blue-green deployment: $new_version"

    # Deploy to green (inactive) environment
    echo "Deploying to green environment..."
    deploy_to_environment "green" "$new_version"

    # Health check
    echo "Running health checks..."
    if ! check_health "$health_check_url"; then
        echo "Health check failed, rolling back" >&2
        return 1
    fi

    # Switch traffic to green
    echo "Switching traffic to green..."
    switch_traffic "green"

    # Keep blue as backup for rollback
    echo "Deployment complete. Blue environment kept for rollback."
}

check_health() {
    local url="$1"
    local max_attempts=30
    local attempt=1

    while ((attempt <= max_attempts)); do
        if curl -sf "$url" > /dev/null; then
            return 0
        fi

        echo "Health check attempt $attempt/$max_attempts failed"
        sleep 2
        ((attempt++))
    done

    return 1
}
カナリアデプロイ
#!/usr/bin/env bash
set -euo pipefail

# Canary deployment with gradual rollout
deploy_canary() {
    local new_version="$1"
    local stages=(5 10 25 50 100)  # Percentage stages

    echo "Starting canary deployment: $new_version"

    for percentage in "${stages[@]}"; do
        echo "Rolling out to $percentage% of traffic..."

        # Update traffic split
        update_traffic_split "$percentage" "$new_version"

        # Monitor for issues
        echo "Monitoring for 5 minutes..."
        if ! monitor_metrics 300; then
            echo "Issues detected, rolling back" >&2
            update_traffic_split 0 "$new_version"
            return 1
        fi

        echo "Stage $percentage% successful"
    done

    echo "Canary deployment complete"
}

monitor_metrics() {
    local duration="$1"
    local end_time=$((SECONDS + duration))

    while ((SECONDS < end_time)); do
        # Check error rate
        local error_rate
        error_rate=$(get_error_rate)

        if ((error_rate > 5)); then
            echo "Error rate too high: $error_rate%" >&2
            return 1
        fi

        sleep 10
    done

    return 0
}

ログ記録とモニタリング

構造化ログ記録
#!/usr/bin/env bash
set -euo pipefail

# JSON structured logging
log_json() {
    local level="$1"
    local message="$2"
    shift 2

    local timestamp
    timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

    # Build JSON
    local json
    json=$(jq -n \
        --arg timestamp "$timestamp" \
        --arg level "$level" \
        --arg message "$message" \
        --arg script "$SCRIPT_NAME" \
        --argjson context "$(echo "$@" | jq -Rs .)" \
        '{
            timestamp: $timestamp,
            level: $level,
            message: $message,
            script: $script,
            context: $context
        }')

    echo "$json" >&2
}

log_info() { log_json "INFO" "$@"; }
log_error() { log_json "ERROR" "$@"; }
log_warn() { log_json "WARN" "$@"; }

# Usage
log_info "Processing file" "file=/data/input.txt" "size=1024"

リソース


最新の自動化には、クラウドネイティブなパターン、コンテナーへの対応、堅牢な CI/CD 統合が必要です。これらのパターンにより、2025 年の本番環境に対応したデプロイが実現します。

コメント