堅牢なシェルスクリプト設計:APIデータ取得とシステム構成の安全な自動更新

Tech

{ “style”: “technical_sre_guide”, “focus”: “robust_shell_scripting”, “tools”: [“bash”, “jq”, “curl”, “systemd”] }

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

堅牢なシェルスクリプト設計:APIデータ取得とシステム構成の安全な自動更新

【導入と前提】 外部APIからJSONを取得・加工し、システム設定を安全に更新する自動化スクリプトの堅牢な設計手法と実装例を解説します。

  • 実行環境:Ubuntu 22.04 LTS 以降(GNU/Linux環境を想定)

  • 必須ツール:curl (データ取得), jq (JSON解析), systemd (スケジュール実行)

【処理フローと設計】

graph TD
A[Start] --> B["Create Temp Directory"]
B --> C{"Fetch API Data"}
C -->|Failure| D["Trap: Error Cleanup"]
C -->|Success| E["jq: Filter & Transform"]
E --> F["Atomic Replace Config"]
F --> G["Trap: Success Cleanup"]
G --> H[End]

処理フローは、異常終了時でもゴミを残さない「一時ディレクトリの利用」と、不完全なファイルをシステムに適用させない「原子的な置換(Atomic Replace)」を主軸に設計しています。

【実装:堅牢な自動化スクリプト】 以下は、APIから設定を取得し、検証後にシステム設定ファイルを更新するテンプレートスクリプトです。

#!/usr/bin/env bash

# -e: エラー発生時に即座に終了


# -u: 未定義変数の参照時にエラー


# -o pipefail: パイプ内のコマンド失敗を検知

set -euo pipefail

# --- 設定項目 ---

API_URL="https://api.example.com/v1/config"
CONFIG_DEST="/etc/myapp/config.json"
TEMP_DIR=$(mktemp -d) # 一時ディレクトリの作成

# --- トラップ処理 ---


# スクリプト終了時(正常・異常問わず)に一時ファイルを削除

cleanup() {
    local exit_code=$?
    rm -rf "$TEMP_DIR"
    if [ $exit_code -ne 0 ]; then
        echo "[ERROR] Operation failed with exit code $exit_code" >&2
    fi
}
trap cleanup EXIT

# --- メイン処理 ---

echo "[INFO] Fetching configuration..."

# curlオプション説明:


# -s: 進捗非表示, -S: エラー時は表示, -L: リダイレクト追従, --retry: 失敗時再試行

curl -sSL --retry 3 --retry-delay 2 "$API_URL" -o "$TEMP_DIR/raw.json"

# jqによるバリデーションと加工


# 入力が空でないか、必要なフィールドが含まれているか確認

if ! jq -e '.version' "$TEMP_DIR/raw.json" > /dev/null; then
    echo "[ERROR] Invalid JSON structure received" >&2
    exit 1
fi

# 加工したファイルを生成

jq '.settings | .updated_at = now' "$TEMP_DIR/raw.json" > "$TEMP_DIR/final.json"

# 原子的なファイル更新 (mvは同一FS内ならアトミック)


# 権限を維持しつつ、書き込みが完了したファイルのみを配置

install -m 644 "$TEMP_DIR/final.json" "$CONFIG_DEST"

echo "[INFO] Configuration updated successfully."

このスクリプトを定期実行する場合、systemdのTimerユニットを活用します。

# /etc/systemd/system/myapp-config-update.service

[Unit]
Description=Update MyApp Config from API

[Service]
Type=oneshot
ExecStart=/usr/local/bin/update-config.sh
User=root

# 環境変数をセキュアに管理する場合

EnvironmentFile=-/etc/default/myapp-api-token

【検証と運用】

  1. 構文チェック: bash -n update-config.sh で構文エラーの有無を事前に確認します。

  2. 実行ログの確認: systemd経由で実行した場合、以下のコマンドでエラーの詳細を確認できます。

    journalctl -u myapp-config-update.service -f
    
  3. 副作用の検証: trapが正しく動作するか、curlの途中で Ctrl+C を送信し、/tmp 内に一時ディレクトリが残っていないか確認してください。

【トラブルシューティングと落とし穴】

  • 権限問題: install コマンドや mv を使用する際、宛先ディレクトリへの書き込み権限が必要です。SREとしては、スクリプト自体を root で動かすのではなく、特定の管理ユーザーに限定的な sudo 権限を付与することを検討してください。

  • パイプの罠: set -o pipefail がないと、curl ... | jq ...curl が失敗しても jq が成功すればスクリプトは続行されてしまいます。必ずセットで設定してください。

  • 環境変数の漏洩: APIトークンなどをスクリプト内にハードコードせず、EnvironmentFile や秘密情報管理ツールから読み込むように設計してください。

【まとめ】 運用の冪等性を維持するための3つのポイント:

  1. 原子性の確保: 中途半端な状態のファイルを作らず、mvinstallで一気に置き換える。

  2. クリーンアップの徹底: trapを使用して、いかなる終了時も一時リソースを解放する。

  3. 失敗の可視化: set -epipefail でサイレントな失敗を防ぎ、標準エラー出力を適切に活用する。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました