`kubectl –dry-run=client` を用いたKubernetesマニフェスト検証

Tech

<!--META { "title": "kubectl --dry-run=client を用いたKubernetesマニフェスト検証", "primary_category": "クラウド>Kubernetes", "secondary_categories": ["DevOps","CI/CD"], "tags": ["kubectl", "dry-run", "Kubernetes", "マニフェスト検証", "CI/CD", "bash", "systemd", "jq"], "summary": "kubectl --dry-run=client を活用し、KubernetesマニフェストをCI/CDで安全かつ効率的に検証する手順と、bashスクリプト、jq、systemdの利用例を解説します。", "mermaid": true, "verify_level": "L0", "tweet_hint": {"text":"Kubernetesマニフェストの安全な検証にはkubectl --dry-run=clientが必須。CI/CDへの組み込み方、安全なbashスクリプト、jqによる出力解析、systemdでの自動化を解説。#Kubernetes #CI_CD","hashtags":["#Kubernetes","#DevOps"]}, "link_hints": [ "https://kubernetes.io/docs/reference/kubectl/usage/#dry-run", "https://jqlang.github.io/jq/manual/", "https://curl.se/docs/manpage.html", "https://www.freedesktop.org/software/systemd/man/systemd.service.html" ] } --> 本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

kubectl --dry-run=client を用いたKubernetesマニフェスト検証

Kubernetes環境における安定した運用には、デプロイ前にマニフェストファイルの健全性を確認することが不可欠です。kubectl --dry-run=client は、実際にリソースを作成することなく、クライアントサイドでマニフェストの構文と基本的なスキーマ検証を行うための強力なツールです。本記事では、このコマンドをDevOpsパイプラインに組み込むための実践的な手順、安全なBashスクリプトの書き方、jqsystemd の活用例を解説します。

1. 要件と前提

kubectl --dry-run=client は、Kubernetes APIサーバーに接続することなく、ローカルに保持されているOpenAPIスキーマ定義に基づいてマニフェストの構文エラーや基本的なフィールドの検証を行います。これはCI/CDパイプラインの初期段階で、開発者が手元で素早くフィードバックを得るために非常に有用です。

1.1. dry-run モードの種類

kubectl applykubectl create などのコマンドで利用できる dry-run オプションには、以下の3つのモードがあります。

  • client: APIサーバーと通信せず、ローカルのスキーマに基づき構文と基本的な構造を検証します。Admission Webhookによる検証は行われません。これは本記事の主題です。

  • server: APIサーバーにリクエストを送信しますが、リソースは永続化されません。Admission Webhookを含む、より本番に近い検証が可能です。ネットワーク接続とRBAC権限が必要です。

  • none: dry-run を行わず、通常通りリソースを作成・更新します。

1.2. 必要なツールと権限

  • kubectl: Kubernetesクラスターとの対話に必須です。ローカルマシンまたはCI/CDエージェントにインストールされている必要があります。

  • jq: kubectl が出力するJSON形式の検証結果を解析するために使用します。

  • curl: (オプション)検証結果を外部システム(例: Slack、Webhook)に通知する際に使用します。

  • 実行環境: Linuxベースのシステム(bashsystemd が利用可能な環境)。

  • 権限: kubectl --dry-run=client の実行には、マニフェストファイルへの読み取り権限と、一時ディレクトリへの書き込み権限があれば十分です。Kubernetesクラスターへのアクセス権限(例: $HOME/.kube/config)は必須ではありませんが、kubectl コマンドが利用可能な状態である必要があります。最小権限の原則に基づき、root権限での実行は避けるべきです。

1.3. 利点と制約

利点:

  • 高速性: APIサーバーとの通信がないため、非常に高速に実行できます。

  • 安全性: 実際のKubernetesリソースを作成・変更しないため、本番環境への意図しない影響を回避できます。

  • 開発効率: CI/CDの早い段階で基本的なエラーを検出し、開発サイクルの短縮に貢献します。

制約:

  • APIサーバーとの乖離: ローカルのスキーマ情報に基づくため、カスタムリソース定義 (CRD) やAdmission Webhookによる検証は行われません。これらは server モードでの検証が必要です。

  • 最新性: kubectl クライアントのバージョンが古い場合、最新のKubernetes APIの変更に対応できない可能性があります。

2. 実装

ここでは、kubectl --dry-run=client を用いてKubernetesマニフェストを検証するBashスクリプトの実装例を示します。jq を使った結果解析や、安全なスクリプトの書き方を含みます。

2.1. 検証対象マニフェストの準備

まずは検証対象となるKubernetesマニフェストファイル nginx-deployment.yaml を作成します。

# nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:

      - name: nginx
        image: nginx:1.21.6 # 意図的に古いバージョンを使用
        ports:

        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:

    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

2.2. 安全なBashスクリプトによるマニフェスト検証

以下のBashスクリプト validate_manifest.sh は、kubectl --dry-run=client を実行し、その結果を jq で解析します。スクリプトは set -euo pipefail でエラーハンドリングを強化し、trapmktemp で一時ファイルを安全に扱います。

#!/usr/bin/env bash


# File: validate_manifest.sh

# 厳格なエラーハンドリングを有効にする


# -e: コマンドが失敗した場合、即座に終了する


# -u: 未定義の変数を参照した場合、エラーとする


# -o pipefail: パイプライン中のコマンドが失敗した場合、パイプライン全体を失敗とする

set -euo pipefail

# 一時ディレクトリの作成と終了時のクリーンアップ


# 前提: mktempコマンドが利用可能であること


# 計算量: O(1)


# メモリ: 非常に小さい

TMP_DIR=$(mktemp -d -t dry-run-XXXXXX)

# スクリプト終了時に一時ディレクトリを削除する

trap 'rm -rf "$TMP_DIR"' EXIT

# マニフェストファイルへのパス


# 入力: マニフェストファイルパス (例: "./nginx-deployment.yaml")

MANIFEST_FILE="${1:-./nginx-deployment.yaml}"

# ファイルが存在するか確認

if [[ ! -f "$MANIFEST_FILE" ]]; then
    echo "エラー: マニフェストファイル '$MANIFEST_FILE' が見つかりません。" >&2
    exit 1
fi

echo "--- Kubernetesマニフェスト検証開始 ($MANIFEST_FILE) ---"

# kubectl --dry-run=client を実行し、JSON形式で出力を取得


# 出力: JSON形式のkubectl実行結果


# 前提: kubectlコマンドが利用可能であること


# 計算量: O(N) (Nはマニフェストファイルのサイズに比例)


# メモリ: マニフェストファイルのサイズに応じて変動

if kubectl apply --dry-run=client -f "$MANIFEST_FILE" -o json > "$TMP_DIR/dry-run-output.json"; then
    echo "INFO: クライアントサイドでの検証は成功しました。"

    # jq を用いて検証結果からリソースの種類と名前を抽出


    # 入力: JSONファイル


    # 出力: フィルタリングされたJSONまたはテキスト


    # 前提: jqコマンドが利用可能であること


    # 計算量: O(M) (MはJSON出力のサイズに比例)


    # メモリ: JSON出力のサイズに応じて変動

    echo "--- 検証されたリソース ---"
    jq -r '.items[] | {kind: .kind, name: .metadata.name}' "$TMP_DIR/dry-run-output.json"
    echo "--------------------------"

    # 検証成功のWebhook通知(例)


    # 入力: Webhook URL、JSONペイロード


    # 出力: curlの実行結果 (標準出力/エラー)


    # 前提: curlコマンドが利用可能であること、ネットワーク接続


    # 計算量: O(ネットワークI/O)


    # メモリ: 小さい


    # 実際にはここに設定ファイルなどからURLを取得するロジックが入る

    WEBHOOK_URL="https://example.com/webhook/success"
    NOTIFICATION_PAYLOAD=$(jq -n --arg file "$MANIFEST_FILE" '{"status": "validation_success", "message": "マニフェストのクライアントサイド検証が成功しました。", "file": $file}')
    if curl --fail --retry 5 --retry-delay 3 --max-time 10 -H "Content-Type: application/json" -d "$NOTIFICATION_PAYLOAD" "$WEBHOOK_URL" &> /dev/null; then
        echo "INFO: 検証成功のWebhook通知を送信しました。"
    else
        echo "警告: 検証成功のWebhook通知の送信に失敗しました。" >&2
    fi

    exit 0
else

    # kubectl apply --dry-run=client が失敗した場合

    echo "エラー: クライアントサイドでの検証が失敗しました。" >&2

    # エラーメッセージを標準エラー出力に直接表示(kubectlの出力は通常すでにエラー)

    cat "$TMP_DIR/dry-run-output.json" >&2 || true # ファイルが存在しない場合もエラーにしない

    # 検証失敗のWebhook通知(例)

    WEBHOOK_URL="https://example.com/webhook/failure"
    ERROR_MESSAGE=$(cat "$TMP_DIR/dry-run-output.json" | jq -r .message 2>/dev/null || echo "Unknown kubectl error")
    NOTIFICATION_PAYLOAD=$(jq -n --arg file "$MANIFEST_FILE" --arg error "$ERROR_MESSAGE" '{"status": "validation_failure", "message": "マニフェストのクライアントサイド検証が失敗しました。", "file": $file, "error": $error}')
    if curl --fail --retry 5 --retry-delay 3 --max-time 10 -H "Content-Type: application/json" -d "$NOTIFICATION_PAYLOAD" "$WEBHOOK_URL" &> /dev/null; then
        echo "INFO: 検証失敗のWebhook通知を送信しました。"
    else
        echo "警告: 検証失敗のWebhook通知の送信に失敗しました。" >&2
    fi

    exit 1
fi

2.3. CI/CDフローにおける検証位置(Mermaid)

kubectl --dry-run=client はCI/CDパイプラインの非常に早い段階で組み込むべきです。これにより、開発者は迅速にフィードバックを得られ、後続の重いステージ(例: クラスタへのデプロイ試行)に進む前に基本的なエラーを排除できます。

graph TD
    A["開発者がマニフェストを作成・更新"] --> B{"Gitリポジトリにプッシュ"};
    B --|コミット/プッシュ| --> C("CIパイプライン開始");
    C --> D["マニフェストをチェックアウト"];
    D --> E{"kubectl --dry-run=client で検証"};
    E --|検証成功| --> F["jqで出力解析"];
    E --|検証失敗| --> G["検証エラー: 開発者に通知"];
    F --> H["追加のツールで検証 (例:OPA/KubeLinter)"];
    H --|追加検証成功| --> I["Artifactリポジトリに保存"];
    H --|追加検証失敗| --> J["追加検証エラー: 開発者に通知"];
    I --> K["CDパイプラインへ"];

3. 検証

上記のBashスクリプト validate_manifest.sh を用いて、正常なケースと異常なケースのマニフェストを検証します。

3.1. 正常なマニフェストの検証

nginx-deployment.yaml を使用してスクリプトを実行します。

bash validate_manifest.sh ./nginx-deployment.yaml

期待される出力例:

--- Kubernetesマニフェスト検証開始 (./nginx-deployment.yaml) ---
INFO: クライアントサイドでの検証は成功しました。
--- 検証されたリソース ---
{
  "kind": "Deployment",
  "name": "nginx-deployment"
}
{
  "kind": "Service",
  "name": "nginx-service"
}
--------------------------
INFO: 検証成功のWebhook通知を送信しました。

curl の実行結果は &> /dev/null で標準出力/エラーに出力されない設定のため、成功メッセージのみ表示されます。)

3.2. 異常なマニフェストの検証

意図的にエラーを挿入したマニフェスト bad-deployment.yaml を作成します。ここでは apiVersion を不正な値に設定します。

# bad-deployment.yaml

apiVersion: apps/v1beta1 # 不正なAPIバージョン
kind: Deployment
metadata:
  name: bad-nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bad-nginx
  template:
    metadata:
      labels:
        app: bad-nginx
    spec:
      containers:

      - name: bad-nginx
        image: nginx:latest
        ports:

        - containerPort: 80

bad-deployment.yaml を使用してスクリプトを実行します。

bash validate_manifest.sh ./bad-deployment.yaml

期待される出力例:

--- Kubernetesマニフェスト検証開始 (./bad-deployment.yaml) ---
エラー: クライアントサイドでの検証が失敗しました。
Error: validation for 'bad-deployment.yaml' failed, no matches for kind "Deployment" in version "apps/v1beta1"
INFO: 検証失敗のWebhook通知を送信しました。

このように、--dry-run=client はAPIサーバーに到達する前に基本的なスキーマエラーを検出できることが確認できます。

4. 運用

kubectl --dry-run=client をCI/CDパイプラインに統合するだけでなく、systemd を用いて定期的にマニフェストの健全性をチェックする自動化も可能です。

4.1. CI/CDパイプラインへの統合

GitHub Actions、GitLab CI/CD、JenkinsなどのCI/CDツールにおいて、Gitリポジトリへのプッシュやプルリクエストの作成時に validate_manifest.sh スクリプトを実行するように設定します。これにより、マージ前にマニフェストの構文エラーが確実に検出されます。

例: GitLab CI/CD の .gitlab-ci.yml スニペット

stages:

  - validate

validate_kubernetes_manifests:
  stage: validate
  image: alpine/git:latest # kubectlは別途インストールまたは指定
  before_script:

    - apk add --no-cache curl jq # Alpine Linuxの場合

    - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

    - chmod +x kubectl

    - mv kubectl /usr/local/bin/
  script:

    - bash validate_manifest.sh ./nginx-deployment.yaml

    - bash validate_manifest.sh ./other-manifests/*.yaml # 複数のマニフェストを検証する場合
  rules:

    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

4.2. systemd による定期的な自動検証

systemd を利用して、例えば毎日特定の時間にマニフェストリポジトリをチェックアウトし、--dry-run=client で検証するタスクを設定できます。これは、依存するツールやKubernetesのバージョンアップに伴うスキーマ変更などを早期に発見するのに役立ちます。

4.2.1. systemd サービスユニットファイル (manifest-validation.service)

マニフェスト検証スクリプトを実行するサービスを定義します。

# /etc/systemd/system/manifest-validation.service

[Unit]
Description=Kubernetes Manifest Client-Side Validation Service
Documentation=https://kubernetes.io/docs/reference/kubectl/usage/#dry-run
Requires=network-online.target # curlによるWebhook通知のためにネットワークが必要
After=network-online.target

[Service]
Type=oneshot
User=validation-user # 最小権限の専用ユーザーで実行
Group=validation-group # 最小権限の専用グループで実行
WorkingDirectory=/opt/manifest-repo # マニフェストリポジトリのパス
ExecStart=/opt/scripts/validate_manifest.sh /opt/manifest-repo/nginx-deployment.yaml

# 環境変数KUBECONFIGを設定する場合 (dry-run=serverなどを用いる場合)


# Environment="KUBECONFIG=/home/validation-user/.kube/config"

ProtectSystem=full
ProtectHome=true
PrivateTmp=true
NoNewPrivileges=true
ReadWritePaths=/opt/manifest-repo /tmp

# 実行ユーザーの作成例 (root権限で実行):


# sudo useradd -r -s /usr/sbin/nologin -d /opt/manifest-repo validation-user


# sudo chown validation-user:validation-group /opt/manifest-repo

root権限の扱いと権限分離の注意点: 上記の例では User=validation-userGroup=validation-group を指定し、サービスを特権のないユーザーで実行しています。kubectl --dry-run=client は基本的にAPIサーバーへのアクセスを必要としないため、KUBECONFIG は不要な場合が多いです。マニフェストファイルへの読み取り権限と、スクリプトが作成する一時ファイル(/tmp 以下に作成されますが、PrivateTmp=true によりサービス専用の一時空間に限定されます)への書き込み権限のみを持つように、validation-user の権限を最小限に抑えることが重要です。

4.2.2. systemd タイマーユニットファイル (manifest-validation.timer)

サービスを定期的に実行するためのタイマーを定義します。ここでは毎日午前3時に実行するように設定します。

# /etc/systemd/system/manifest-validation.timer

[Unit]
Description=Run Kubernetes Manifest Client-Side Validation daily

[Timer]
OnCalendar=daily

# Persistent=true # サービスが停止中に発生したイベントも次回の起動時に実行

[Install]
WantedBy=timers.target

4.2.3. systemd タイマーの起動とログ確認

これらのファイルを配置したら、systemd にリロードを指示し、タイマーを有効化・起動します。

# systemd設定をリロード

sudo systemctl daemon-reload

# タイマーを有効化し、起動

sudo systemctl enable manifest-validation.timer
sudo systemctl start manifest-validation.timer

# タイマーの状態を確認

sudo systemctl list-timers | grep manifest-validation

# サービスの実行ログを確認 (実行後に確認可能)

sudo journalctl -u manifest-validation.service

5. トラブルシュート

5.1. kubectl --dry-run=client が検出できないエラー

  • CRDやAdmission Webhookによる検証エラー: client モードはローカルのOpenAPIスキーマに基づいて検証するため、カスタムリソースの定義や、Mutating/Validating Admission Webhookによる動的な検証は行いません。これらを検出するには kubectl apply --dry-run=server を使用する必要があります。

  • RBAC権限不足: client モードでは関係ありませんが、server モードで dry-run を行う場合、APIサーバーに対する適切なRBAC権限が必要です。

5.2. kubectl のバージョン差異による問題

kubectl クライアントのバージョンが、ターゲットKubernetesクラスターのAPIバージョンと大きく異なる場合、--dry-run=client のスキーマ定義が古く、存在しないフィールドを許可したり、新しい必須フィールドの欠落を見逃したりする可能性があります。 常に最新の kubectl クライアントを使用し、可能であればクラスターと同じマイナーバージョンに合わせることが推奨されます。

5.3. スクリプトの実行権限エラー

validate_manifest.sh スクリプトの実行時に「Permission denied」などのエラーが発生する場合、以下の点を確認してください。

  • スクリプトファイルに実行権限があるか: chmod +x validate_manifest.sh

  • マニフェストファイルに読み取り権限があるか。

  • jq, curl, kubectl, mktemp コマンドが PATH 環境変数に含まれており、実行可能であるか。

6. まとめ

kubectl --dry-run=client は、Kubernetesマニフェストの基本的な健全性を効率的かつ安全に検証するための不可欠なツールです。本記事で解説したように、安全なBashスクリプト、jq を用いた出力解析、そしてCI/CDパイプラインや systemd を活用した自動化により、開発初期段階でのエラー検出を強化し、Kubernetes環境の信頼性向上に大きく貢献します。 常に最小権限の原則に従い、systemd サービスなどで実行する際には専用ユーザーを設定することで、セキュリティリスクを最小限に抑えることを忘れないでください。より高度な検証が必要な場合は、--dry-run=server やOPA (Open Policy Agent) などのポリシーエンジンとの組み合わせも検討しましょう。

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

コメント

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