Nov 1, 2025 · 1146 words · 6 min read

5. Execution#

Playbookは何カ月も完璧に動作していた。ラボの10台のアクセススイッチに対してエンドツーエンドで2分、毎回クリーンな結果。チームが800台のスイッチの全インベントリにロールアウトすることを決めたとき、誰も問題を予想しなかった。最初の600台のデバイスは問題なく更新された。そしてジョブが遅くなった。そして止まった。RADIUSサーバーが突然150件の同時SSH認証リクエストを受け取り、接続を拒否し始めた。Ansibleは150台のデバイスの実行途中でハングした。エンジニアがジョブを強制終了した。

次に来たのがより難しい問題だった。600台のデバイスのどれが更新されて、どの150台がそうでないか、誰にも分からなかった。実行状態が記録されていなかった。Playbookを再実行して、冪等性が助けてくれることを願った。その時は助かった。しかしこのインシデントは重要なことを明らかにした。実行レイヤーはラボ向けに設計されており、ネットワーク向けではなかった。速度、並列処理、エラー境界、状態追跡、何も考慮されていなかった。自動化は機能していた。実行アーキテクチャが機能していなかった。

多くの人はネットワーク自動化を「同じデータを使って、人間としてCLIに接続せずに、ネットワークで何かをする」と考える。ネットワーク自動化を始める多くの人がそこから始めると思う。そしてそれが Execution ブロックの行うことだ。しかし本書全体で見てきたように、ネットワーク自動化はこの最初のステップより大きく、Executionはアーキテクチャ内のひとつのコンポーネントに過ぎない。

Execution ブロックは最も危険な操作(設定変更や再起動など)のためにネットワークと直接やり取りする。だからこの章を飛ばさないこと。正しく行うことが重要だ。

この章では、このブロックが提供するゴールと柱、それを達成するために必要な内部機能について解説する。

5.1. 基本原則#

5.1.1. コンテキスト#

Executionはどのようにアクションを実行するかを定義する。何を行うかはIntentブロックから、いつ行うかはOrchestrationから来る。

初期のネットワーク自動化プロジェクトでは、特定のデバイスとインターフェース名に対してインターフェースをバウンスするスクリプトが最初の成果となることがある。その旅は、はるかに洗練されたシステムへと成長する可能性がある。

5.1.2. ゴール#

実行システムが実際に行うべきことは何か? 5つのことが重要だ。

  1. 適切なデータを準備する。 何かを実行する前に、何を実行するか(インテント)、どこで実行するか(どのデバイスに)、どのようにアクセスするか(認証情報、接続の詳細)を知る必要がある。これはSource of Truth(第4章で詳述)からインベントリを取得し意図された状態をフェッチすることを意味し、時には現在の状態を把握するためにオブザーバビリティデータをクエリすることも含む。この統合なしでは、実行エンジンはただ盲目的にコマンドを実行するだけだ。精神的健康のために、それは避けること。

  2. 今すぐでも後でも、必要なときに開始する。 即時の実行が必要なこともある。エンジニアが「デプロイ」をクリックして、すぐに実行されることを期待する。また、実行を待機させるべき場合もある。メンテナンスウィンドウ中にデプロイする、デバイスがオンラインになるまで待つ、オブザーバビリティからのイベントに反応する、などだ。システムは同期と非同期の両方のトリガーをサポートする必要がある。

  3. 時間の経過とともに状態を追跡する。 ネットワーク全体の操作は瞬時ではない。数時間かけて数百台のデバイスにデプロイすることがある。どのデバイスが成功したか? どれが失敗したか? どれがまだ保留中か? 状態管理はまた冪等性(同じタスクを2回実行しても同じ結果)、ロールバック(行ったことを元に戻す)、再開(失敗後に中断した場所から再開)を可能にする。状態追跡なしでは、すべての実行が一発勝負のギャンブルになる。

  4. スケールで確実に実行する。 5台のデバイスで動くスクリプトは500台ではしばしば壊れる(または劣化する)。並列実行、エラー処理、リトライ、レート制限、ドライラン機能が必要だ。システムは部分的な失敗を適切に処理し、何が問題だったかを明確にフィードバックし、ネットワークを未定義の状態に放置しないこと。操作によって異なる戦略が必要だ。高速で並列なものもあれば、低速でシリアルなものもある。

  5. あらゆるネットワークデバイスやプラットフォームで動作する。 ネットワークにはおそらくCisco、Arista、Juniper、クラウド Application Programming Interface (API)、Linuxボックス、ファイアウォール、ロードバランサーがある。それぞれが異なるプロトコルを使い、異なる操作パターンを持つ。実行レイヤーはそれらすべてへのアダプターが必要で、残りの自動化が違いを気にしなくてもよい共通インターフェースを持つ。

これらのゴールを念頭に置いて、実際に必要なアーキテクチャ機能は何か?

5.1.3. 柱#

各ゴールは特定の機能に対応する。

  1. データ統合レイヤー。 実行エンジンは孤立して存在しない。Source of Truth(インベントリ、認証情報、インテント)、オブザーバビリティシステム(現在の状態、ヘルスメトリクス)、そして潜在的に他のシステム(チケット、変更管理、承認ワークフロー)へのプログラム的なアクセスが必要だ。これは Application Programming Interface (API) クライアントの実装、認証の安全な処理、データの適切なキャッシング、実行開始前に必要なものがすべて揃っているかの検証を意味する。

  2. 柔軟なトリガーメカニズム。 実行を開始する複数の方法が重要だ。同期トリガーには Representational State Transfer (REST) Application Programming Interface (API)(直接呼び出し)、Webhook(外部システム統合)、リモートプロシージャ呼び出しが含まれる。非同期トリガーにはイベントリスナー(オブザーバビリティアラート、デバイス状態変化、外部イベントへの反応)、スケジューラー(cronのような定期実行またはワンタイムスケジュールタスク)、メッセージキューコンシューマーが含まれる。基本的なチェイニングも役立つ。ひとつの実行が完了して別の実行をトリガーする。

  3. 状態管理インフラ。 これは「デバイスがこの設定を持っているか」を超えたものだ。実行状態(どのタスクが実行中、保留中、完了、失敗しているか)、望まれる状態(何が設定されるべきか)、実際の状態(何が設定されているか)が必要だ。これには永続ストレージ、アトミック操作のトランザクションサポート、並行競合を防ぐロックメカニズム、明確な状態モデルが必要だ。インフラは複数の実行ワーカー間で状態が共有される分散シナリオを処理しなければならない。

  4. 堅牢な実行エンジン。 これがシステムの中核だ。命令型ワークフロー(コマンド1を実行し、次にコマンド2、そして3)と宣言型アプローチ(デバイスをこのように見せて、ステップは自分で考える)の両方をサポートする。エンジンは並列処理(複数のデバイスに同時またはバッチで実行)を処理し、指数バックオフを伴うリトライロジックを実装し、ドライラン機能(実際に行わずに何が起きるかを予測)を提供し、詳細な実行ログを取得し、部分的な失敗を適切に処理する。エラー処理が重要だ。何かが失敗したとき、すべてを中断するか、他のデバイスで続行するか、リトライするか?

  5. プロトコル抽象化レイヤー。 ネットワークデバイスは異質な混在だ。Secure Shell (SSH) を使って Command Line Interface (CLI) コマンドを期待するものもある。NETCONFRESTCONF を使うものもある。現代のデバイスはストリーミングテレメトリと設定のために gRPC Network Management Interface (gNMI) をサポートする。クラウドプラットフォームは Representational State Transfer (REST) APIを公開する。実行システムはこれらすべてへのアダプターが必要で、上位レイヤーのロジックに統一されたインターフェースを提示する。このレイヤーは接続プーリング、セッション管理、認証、コマンドのフォーマット、レスポンスのパースを処理する。良い抽象化は、自動化全体を書き直すことなく新しいデバイスタイプのサポートを追加できることを意味する。

5.1.4. スコープ#

Executionブロックは計画と実行の間に位置する。Intent(何を設定するか)とOrchestration(いつ・どのように行うか)から指示を受け取り、変更を実現するためにネットワークデバイスと直接やり取りする。

スコープ内:

  • サポートされるプロトコルでネットワークデバイスに接続する
  • 設定変更、運用コマンド、ファイル転送、再起動を実行する
  • 実行状態を管理し進捗を追跡する
  • エラー、リトライ、ロールバックを処理する
  • Orchestrationにフィードバックを提供する

スコープ外:

  • 何を設定するかを決定する(それはIntentの仕事)
  • 複雑なマルチステップワークフローの調整とトリガーのタイミング決定(それはOrchestrationの仕事)
  • 実行結果の長期保存と分析(それはObservabilityの仕事)

Executionは車のエンジンだと考えてほしい。動力と運動を提供するが、どこへ行くかいつ曲がるかを決めない。それらの決定はマップ(Intent)に従うドライバー(Orchestration)から来る。

5.2. 機能#

5つの主要な機能領域が連携して、ネットワーク状態を安全かつ確実に変更する。

  1. Data Integration: 上流システムからインベントリ、認証情報、インテント、オブザーバビリティデータを取得する
  2. Triggering: 同期または非同期メカニズムで実行を開始する
  3. State Management: 実行の進捗を追跡し、冪等性とロールバックを可能にする
  4. Engine: 適切な並列処理とエラー処理でタスクを実行するコアロジック
  5. Network Adapter: 多様なネットワークデバイスと通信するためのプロトコル固有のインターフェース

これらのコンポーネントはパイプラインを形成する。Data Integrationが入力を提供し、Triggeringがプロセスを開始し、EngineがNetwork Adapterを使ってタスクを実行し、State Managementが全体を通じてすべてを追跡する。

graph LR
    subgraph ゴール
        G1[適切なデータを適切な場所に]
        G2[必要なときに開始する]
        G3[時間の経過とともに状態を追跡する]
        G4[スケールで確実に実行する]
        G5[あらゆるデバイスやプラットフォームで動作する]
    end

    subgraph 柱
        P1[データ統合レイヤー]
        P2[柔軟なトリガーメカニズム]
        P3[状態管理インフラ]
        P4[堅牢な実行エンジン]
        P5[プロトコル抽象化レイヤー]
    end

    subgraph 機能
        F1[Data Integration]
        F2[Triggering]
        F3[State Management]
        F4[Engine]
        F5[Network Adapter]
    end

    G1 --> P1 --> F1
    G2 --> P2 --> F2
    G3 --> P3 --> F3
    G4 --> P4 --> F4
    G5 --> P5 --> F5

内部アーキテクチャは以下のようになる。

graph TD
    A[Data Integration] --> C[Engine]
    B[Triggering] --> C[Engine]
    C --> E[State Management]
    E --> C
    C --> D[Network Adapter]
    classDef component fill:#e1f5ff,stroke:#4a90e2,stroke-width:2px;
    class A,B,C,D,E component;

5.2.1. Data Integration#

何かを実行する前に、データが必要だ。実行エンジンは何を行いどこで行うかを理解するために複数のソースから情報を取得する。

5.2.1.1. インベントリ#

インベントリデータはターゲットデバイスを定義する。これは第4章で説明したが、最低限必要なものは以下の通りだ。

  • ターゲット: デバイスに到達するためのIPアドレスまたはFQDN
  • プラットフォーム/OS: デバイスタイプ、ベンダー、OSバージョン(使用するプロトコルとコマンドを決定する)
  • 認証情報: ユーザー名/パスワード、Secure Shell (SSH) キー、Application Programming Interface (API) トークン、証明書パス
  • 接続パラメータ: Secure Shell (SSH) ポート、タイムアウト値、Application Programming Interface (API) エンドポイント
  • メタデータ: サイト場所、ロール(スパイン/リーフ/エッジ)、環境(本番/ステージング)

インベントリデータはSource of Truthから来るべきだ。ファイルの使用は非常に小さな環境でのみうまく機能する。実行エンジンは実行時にSource of Truthの Application Programming Interface (API) をクエリするか(またはトリガー時にOrchestrationを経由してデータを受け取る)。一部のシステムは設定可能なリフレッシュ間隔でパフォーマンスのためにインベントリをキャッシュするか、関連情報とともにトリガーを組み合わせたイベント駆動のインベントリを活用する。

インベントリファイルやログには絶対に認証情報を保存しないこと。シークレット管理システム(HashiCorp Vault、AWS Secrets Manager、CyberArk)を使用し、実行時に認証情報を注入する。Source of Truthはその機密データへのポインターを提供し、実行時に取得するべきだ。実行エンジンは複数の認証情報ソースとデバイスごとの認証情報オーバーライドをサポートすべきだ。

5.2.1.2. 意図されたデータ#

意図されたデータは設定または変更したい内容だ。これはIntentまたはSource of Truthブロックから来て、以下のものが含まれる場合がある。

  • 設定成果物: APIで直接使用できる構造化データ、またはCLIコマンドセットとして表現できる、デプロイ可能な成果物。
  • コマンド: デバイス操作のために実行する特定の Command Line Interface (CLI) コマンドまたは Application Programming Interface (API) 呼び出し。
  • ファイル: アップグレード用のソフトウェアイメージ、インポート用の設定ファイル。

実行エンジンはインテントデータを自分でフェッチすべきか、それともOrchestrationがそれを渡すべきか? どちらも機能する。インテントを直接フェッチすることはExecutionをSource of Truthに結合するが、データが常に最新であることを確保する。インテントをパラメータとして受け取ることはExecutionをより汎用にするが、Orchestrationがデータフェッチを処理する必要がある。

私の推奨は、設定成果物を直接消費することだ。Intentブロックは、状態を表す構造化データ(VLAN設定、ルーティングポリシー、ACL)で設定テンプレートをレンダリングする独自のロジックで設定成果物を生成する責任を持つべきだ。

設定成果物は生成された瞬間からExecutorに消費される瞬間の間に古くなる可能性がある。事前生成された成果物がキャッシュされた後にSoTデータが変更された場合、Executorは古い設定を適用する可能性がある。陳腐化ウィンドウは最後のSoTコミットから実行トリガーまでの時間だ。キャッシュからではなくトリガー時に成果物をフェッチする自動化では、このウィンドウは最小限だ。スケジュールに基づいて成果物を事前レンダリングして後で使用するためにストアするパイプラインでは、このウィンドウは数時間に成長することがある。データの新鮮さが重要な場合、OrchestratorまたはExecutionのトリガーは常にキャッシュされたファイルからではなく、SoTから最新の成果物を取得すべきだ。

5.2.1.3. 観測データ#

オブザーバビリティの検証は通常Orchestrationに属し、続行するかどうかを決定できる。Orchestrationがまだ存在しないシンプルなケースでは、Executionがこの役割を取り込むことができる。

オブザーバビリティデータが実行フローの近くで使用されるユースケースをいくつか示す。

  • 実行前検証: デバイスに到達可能か? アップグレードのために十分なディスクスペースがあるか? 中断される可能性のあるアクティブセッションがあるか?
  • グレースフルデグラデーション: スイッチを再起動する前に、オブザーバビリティをクエリして冗長接続があるかを確認する。なければ、遅延または中断する。
  • 条件付きロジック: 特定の条件が満たされた場合にのみ設定を適用する(CPUがしきい値以下、アクティブアラームなし、時刻がウィンドウ内)
  • 容量のドレイン: ドレイン操作を実行する前に、SLOを壊さずに変更を吸収するのに十分な容量があることを確認する。

これにはオブザーバビリティシステムとの統合が必要だ。実行エンジンは現在のメトリクスのために Application Programming Interface (API) をクエリし、デバイスの状態を確認し、準備完了シグナルを待つかもしれない。Orchestrationもこの統合を行い、新鮮さとリスクに基づいて実行をゲートすることができる。

一般的なパターン: AnsibleやNornirの「ネットワークヘルスチェック」モジュールやデータ収集タスクのようなツールは、実行の前後にオブザーバビリティクエリを実行し、予期しない変更を検出するために結果を比較する。「ビフォー/アフタースナップショット」アプローチは、気づかれないまま通過する可能性のある後退を検出する。

5.2.2. Triggering#

Executionは自然に開始しない。何かがそれをトリガーしなければならない。現代の実行システムは複数のトリガーメカニズムをサポートする。

同期(即時、ブロッキング):

  • Representational State Transfer (REST) Application Programming Interface (API) 呼び出し: 外部システムまたはユーザーが Application Programming Interface (API) エンドポイントを呼び出し、実行が動作し、レスポンスに結果が含まれる。シンプルで直接的。
  • Webhook: 外部システム(Term "git" not found、チケット、CI/CD)がイベント発生時にHTTPリクエストを送信する。一般的なパターン: Term "git" not found プッシュが設定デプロイをトリガーする。
  • Command Line Interface (CLI) コマンド: エンジニアが実行を直接呼び出すコマンドを実行する(ansible-playbookterraform apply、カスタムスクリプト)。これらのCLIコマンドはこれらのツールが提供する軽量なプレゼンテーションレイヤーの一部だ(第8章で詳述)。

非同期(遅延またはイベント駆動):

  • イベントリスナー: オブザーバビリティ(デバイスダウン、しきい値超過)、メッセージキュー、外部システムからのイベントに反応する。Ansible Event-Driven Automation(EDA)はこのパターンを明示的に構築した。イベントをリッスンし、ルールにマッチし、自動的にPlaybookをトリガーする。
  • メッセージキュー: タスクがキュー(RabbitMQ、Kafka、AWS SQS)に送信され、ワーカーがそれらを取得して実行する。バッファリング、優先度キューイング、レート制限を可能にする。

適切なアプローチはユースケースによる。即時の変更(本番問題の修正)には同期トリガーが必要だ。リアクティブ自動化(アラートへの対応)はイベントリスナーを使用する。スケールの考慮事項も重要で、第11章で扱う。

トリガーは通常Orchestrationから来るが、それが存在しない場合、他のブロックが直接Executionをトリガーできる。例えば、人間が公開するタスクとしてプレゼンテーションレイヤーから直接トリガーしたり、Source of Truthブロックからトリガーしたりする。

重要な考慮事項: 何が実行として数えられるか? 私にとって、実行は単純なタスク以上のものだ。複雑なワークフローを必要としない複数の連鎖タスクを含むことができる(それはOrchestrationの仕事だ)。境界は曖昧になる(また)。例えば、このシーケンスはまだひとつの実行フローとなりうる。ファームウェアのアップグレード、デバイスの再起動を待つ、動作の確認、インベントリの更新。しかし人間の検証やより広い検証に基づく条件分岐が必要な場合は、Orchestrationブロックに属する。

5.2.3. State Management#

状態管理は実行のどこにいるか、そして賢い決断を下せるよう世界がどのように見えるかを追跡することだ。主に2つのカテゴリーがある。

  • 実行状態(自動化自体を追跡する):

    • どのデバイスが処理されたか?
    • どのタスクが成功、失敗、または保留中か?
    • タスクが一時的なエラーで失敗した場合、リトライできるか?
    • 実行が中断された場合、中断した場所から再開できるか?
  • 実際のインフラ状態(ターゲット設定の状態を追跡する):

    • 現在何が設定されているか?

2つのアプローチがある。

  • ステートレス/エージェントレス(例: Ansible)。 各実行は独立して動作する。実行間に永続的な状態はない。すべての実行は最初から始まる。現在の状態を収集し、差分を計算し、変更を適用する。操作がシンプル(状態データベースが不要)だが、非効率(毎回すべてを再検出する)で、組み込みのロールバックがない。

  • ステートフル(例: Terraform)。 システムは最後にデプロイされたものを追跡する永続的な状態ファイルを維持する。各実行時に、望まれる状態(設定)を記録された状態(前回デプロイしたもの)と実際の状態(デバイス上にあるもの)と比較する。これにより正確な変更計画、効率的な実行(異なるものだけを変更)、ロールバック(以前の状態に戻す)が可能になる。しかし今や守り、ロック、複数のオペレーター間で同期する状態ファイルが存在する。

トランザクション実行は「ベストエフォート」より強い安全保証が必要な場合の次のステップだ。トランザクションは複数のデバイス変更を単一のユニットにグループ化する。すべてが適用されて検証されるか、システムが以前の状態にロールバックするかのどちらかだ。これには3つのことが必要だ。

  • 明確な境界(どの操作がトランザクション内にあるか)
  • 変更前の状態の耐久性のある記録(ロールバック用)
  • 原子性を壊す並行変更を防ぐロックまたはリースメカニズム

実際には、すべてのデバイスがネイティブのコミット/ロールバックをサポートしているわけではないため、ほとんどのネットワーク自動化は厳密なACIDセマンティクスではなく「トランザクション的な」動作を使用する。それでも、スナップショットを取得し、候補設定を使用し(サポートされている場合)、排他ロックを適用し、ロールバックパスを実行フローの第一級の部分にすることで、トランザクションを近似できる。

課題は? 状態の同期と共有だ。複数の人やシステムがネットワークデバイスを変更すると、状態が古くなる。Terraformはリモート状態ストレージとロックでこれに対処する。Ansibleはステートレスであることで問題を回避するが、効率性を犠牲にする。中間の方法: 現在の状態を一時的にキャッシュし、各操作前に検証し、一時的な不一致が許容可能な「結果整合性」パターンを構築する。

5.2.3.1. 冪等性#

冪等性とは、同じ自動化を複数回実行しても同じ結果を得ることを意味する。VLAN設定を一度適用するとVLANが作成される。再度適用しても何も変わらない(VLANはすでに存在する)。これは信頼性に不可欠だ。実行が途中で失敗した場合、重複を作ったり物事を壊したりすることなく安全に再実行できる。

ツールが冪等性を実現する方法:

  • 組み込みモジュール(例: Ansible): ほとんどのAnsibleモジュールは設計上冪等だ。ios_vlanモジュールはVLANを作成する前にそれが存在するかを確認する。すでに正しい設定で存在する場合、Ansibleは「ok」(変更なし)と報告する。これにはモジュール作成者が確認ロジックを実装する必要がある。

  • 状態比較(例: Terraform): Terraformは望まれる状態と現在の状態を比較し、差分を計算し、差分のみを適用する。設定を変更せずにterraform applyを2回実行すると、2回目は何もしない。

  • 宣言型API(例: NETCONF/YANG): 一部のプロトコルはネイティブで冪等性を処理する。merge操作を伴うNETCONFの<edit-config>は本質的に冪等だ。既存の設定に設定をマージし、必要に応じて作成または更新する。

  • 手動確認(例: 生のスクリプト): PythonやGoスクリプトを書く場合、自分で冪等性を実装する。現在の状態をクエリし、望まれる状態と比較し、差分がある場合にのみ変更を行う。

冪等性は見た目より難しい。VLANが存在しても設定が間違っている場合は? 更新すべきか(トラフィックを中断する可能性がある)、それとも競合を報告すべきか? 一時的な失敗(デバイスが一時的に到達不能)はどうか? リトライロジックは「操作はすでに完了している」(冪等成功)と「操作が失敗した」(本物のエラー)を区別しなければならない。

完全な冪等性はオーバーヘッドを追加する。すべての操作は最初に現在の状態をクエリする必要がある。大規模デプロイでは、これが遅くなる。一部のチームは「ほぼ冪等」(99%の時間機能する)を「完全に冪等」(常に機能するが、動作が遅い)の代わりに受け入れる。

冪等性は宣言型アプローチの要件だ。誰かが冪等性を提供し、全員のために複雑さを隠す負担を引き受けなければならない。

5.2.4. Engine#

実行エンジンは、タスク(「これら50台のスイッチにこのVLANを設定する」)を受け取り、安全かつ効率的に実行するコアロジックだ。これはOrchestrationではない。Orchestrationブロックは時間と依存関係にわたって複数の実行タスクを調整する。エンジンはただひとつのタスクをうまく実行するだけだ(または単純なタスクの連鎖)。

エンジンが行うこと:

  • タスク定義(何をする、どのデバイスに)を受け取る
  • それをアトミック操作(デバイスごとのアクション)に分解する
  • 適切な並列処理(シリアル、並列、バッチ)で操作を実行する
  • エラー、リトライ、ロールバックを処理する
  • 進捗と結果を報告する

実行エンジンは100台のルーターを並列で設定するかもしれないが、ビジネスロジックに基づいていつ設定するか、どの設定を適用するか、結果に基づいて次に何をするかは決定しない。それらはOrchestrationの懸念事項だ。Executionは作業馬であり、Orchestrationは職長だ。

ただし、実行エンジンは単純なチェイニングをサポートすることが多い。「タスクAを実行し、次に同じデバイスでタスクBを実行する。」それは基本的なシーケンシングであり、完全なOrchestrationではない。複雑なワークフロー(外部承認を待つ、結果に基づいて分岐する、複数のシステム間で調整する)が必要な場合は、本物のOrchestrationレイヤーが必要だ(第7章で詳述)。

5.2.4.1. 言語#

実行ロジックをどのように定義するか? 異なる言語スタイルには異なるトレードオフがある。

スタイル強みトレードオフ
ドメイン固有言語(DSL)Ansible(YAML)、Terraform(HCL)参入障壁が低い、インテントが自己文書化、組み込みの実行セマンティクス柔軟性が限られる、複雑なシナリオでのデバッグが難しい、条件ロジックが不自然になることがある
汎用プログラミングNornir(Python)、カスタムPython/Goスクリプト完全な柔軟性、強力なデバッグツール、ライブラリの再利用が容易スキル要件が高い、維持するコードが多い、チーム間の標準化が少ない

多くのチームは一般的なパターンにDSL(Ansible)を使用し、複雑なエッジケースにはカスタムコード(Pythonモジュール、プラグイン)に切り替える。これはアクセスしやすさと能力のバランスを取る。人的要因が通常どのアプローチが勝つかを決める。詳細は第13章で扱う。

5.2.4.2. 命令型対宣言型#

命令型: どのように行うかを、ステップバイステップで指定する。

宣言型: 最終状態がどうあるべきかを指定し、ツールが方法を考える。

簡単に言えば、フィットする場合は宣言型を優先する。

違いを見るよい方法はAnsibleを見ることだ。Ansibleは両方をサポートしている。

  • 命令型Ansible:

    - name: Create VLAN 100
      cisco.ios.ios_command:
        commands:
          - vlan 100
          - name Engineering

    どのコマンドを実行するかをAnsibleに文字通り指示している。VLANが存在する場合でも、これは実行される(モジュールによっては冪等かもしれないが)。

  • 宣言型Ansible:

    - name: Ensure VLAN 100 exists
      cisco.ios.ios_vlans:
        config:
          - vlan_id: 100
            name: Engineering
        state: merged

    望まれる状態を記述する。Ansibleがどのコマンドを実行するかを考える。VLAN 100が正しい名前ですでに存在する場合、Ansibleは何もしない。

アプローチ強みトレードオフ
宣言型本質的に冪等; インテントが読みやすい; ツールがエッジケースを処理するためオペレーターのミスが少ないモジュール/プロバイダーの品質に大きく依存; 実行パスへの制御が少ない; 内部が抽象化されているとトラブルシューティングが難しい
命令型各ステップへの完全な制御; 実行フローが明示的; ほぼすべての環境でCLIアクセスで動作するより多くのコードとテスト作業; 冪等性はあなたの責任; エッジケースが蓄積するにつれ長期的なメンテナンスが急増

ほとんどのチームは可能な場合は宣言型を使用し、必要な場合は命令型を使用する。ただし覚えておこう。宣言型は他の誰かが負担を引き受けることを意味する。外から見てシンプルに見えても。

5.2.4.3. シリアル対並列#

タスクを実行するための2つの選択肢がある。

  • シリアル実行: デバイスを1台ずつ処理する。デバイス1を設定し、完了を待ち、デバイス2を設定するなど。安全(失敗がすぐに見えて停止できる)だが遅い(100台のデバイス = 1台の100倍の時間)。

  • 並列実行: 複数のデバイスを同時に処理する。デバイス1〜10を一度に設定し、次に11〜20など。

flowchart TD
    subgraph シリアル
        S1[デバイス1] --> S2[デバイス2] --> S3[デバイス3]
    end
    subgraph 並列
        P0[開始] --> P1[デバイス1]
        P0 --> P2[デバイス2]
        P0 --> P3[デバイス3]
    end

Nornirが存在する理由: Ansibleは元々シリアルだった。スケールのあるネットワーク自動化では、これは非常に遅かった。Ansibleはstrategy: freeと後にforksを追加して並列処理を可能にしたが、本質的にはシーケンシャル実行のために設計されている。Nornirは最初から並列処理を念頭に置いて構築された。デフォルトでスレッディングを使用して複数のデバイスに同時に実行する。これにより大規模なデバイス数では10〜100倍高速になる。

並列実行の考慮事項:

  • コントロールプレーンへの影響: 1000台のデバイスに同時にアクセスすると、管理ネットワーク、データソース、認証システム、またはデバイスのコントロールプレーンに過負荷がかかる可能性がある。
  • 依存関係の処理: デバイスが互いに依存している場合(リーフの前にスパイン)、順序付けが必要だ。純粋な並列処理は機能しない。
  • エラーの影響範囲: 自動化にバグがある場合、並列実行は気づく前に多くのデバイスにデプロイする。シリアル実行はデバイス1で失敗し、デバイス2〜100を傷める前に停止する。

私の推奨: バッチ処理を伴う並列実行を使用する。デバイスを10〜50のグループ(私はかつて「ウェーブ」と呼んでいた)で処理し、続行する前に各バッチの成功を確認する。これにより速度と安全性のバランスが取れる。デプロイ戦略の詳細は第10章で扱う。

5.2.4.4. ドライラン(プランモード)#

ドライランは実行エンジンの「プラン」フェーズだ。デバイスに触れることなく変更をシミュレートし、具体的な差分とリスクを表示する。良いドライランは現在の状態を取得し、実行される正確なデバイスレベルの操作を計算し、前提条件(到達可能性、スキーマ、依存関係の順序)を検証する。それは高速で決定論的かつ再現可能であるべきで、レビュアーがそれを信頼できるようにする。

例(レビュー可能な変更を持つAWS VPCのTerraformプラン):

Terraform will perform the following actions:

  # aws_vpc.main will be created
  + resource "aws_vpc" "main" {
      + cidr_block           = "10.10.0.0/16"
      + enable_dns_support   = true
      + enable_dns_hostnames = true
      + tags = {
          + "Name" = "core-vpc"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

これがレビュアーが承認するものだ。クラウドに触れることなく変更される正確なリソースと属性。

実際には、ドライランが承認を意味のあるものにし、ロールバックを減らす。人間に何が起きるかの明確なビューを与え、エンジンに安全でない一貫性のない変更を早期に拒否する機会を与える。プラットフォームが候補設定またはコミットチェックをサポートしている場合、エンジンはそれらを使用すべきだ。そうでなければ、ドライランは計算された差分と事前チェックであり、保証ではない。

私の経験では、ドライラン機能の提供は、ネットワークエンジニアの賛同を得るために自動化プロジェクトの初期段階で非常に便利だ。後になると、その重要性は薄れる。

5.2.4.5. 回復力#

ネットワーク実行は本質的に信頼性が低い(ほとんどの分散システムと同様に)。デバイスが再起動し、接続が不安定になり、コントロールプレーンが過負荷になる。Intentブロックのような他の依存関係も一時的な問題を抱えることがある。回復力のある実行はこれらを適切に処理する。

リトライロジック:

  • 一時的な失敗(接続タイムアウト、一時的なCPUスパイク)は指数バックオフを伴うリトライをトリガーすべきだ
  • リトライ可能なエラー(タイムアウト)と永続的なエラー(認証失敗、構文エラー)を区別する
  • 無限ループを避けるためにリトライ試行を制限する

タイムアウト戦略:

  • 接続タイムアウト: 諦める前にデバイスのレスポンスをどれだけ待つか
  • タスクタイムアウト: 完全な操作が実行できる時間(スタックしたデバイスでのハングを防ぐ)
  • グローバルタイムアウト: ジョブ全体の最大実行時間

エラー処理:

  • フェイルファスト: 1台のデバイスが失敗したらすべてを中断する(安全だが非効率)
  • 継続する: 失敗をログに記録し、他のデバイスで続行する(効率的だが損害を広げる可能性がある)
  • しきい値ベース: デバイスの10%以上が失敗したら停止する(バランスが取れている)

ロールバック機能:

  • 変更前に設定スナップショットを取得する
  • 実行が失敗した場合、自動的にスナップショットを復元する
  • ドライランモードをサポートする: 実際に変更せずに何が変わるかを表示する

サーキットブレーカー:

  • デバイスが一貫して失敗する場合、それを不健全とマークして一時的にスキップする
  • 停止したデバイスへの接続を繰り返し試みる時間の無駄を防ぐ

チェックポイント:

  • 定期的に進捗を保存する
  • 実行がクラッシュした場合、最初からやり直すのではなく最後のチェックポイントから再開する

これらすべてを構築するのは難しい。ほとんどのチームは基本的なリトライロジックから始め、本番環境での失敗に直面するにつれて複雑さを増していく。

ひとつの有用なパターン: 「安全モード」を第一級の実行状態として扱う。意図された設定をレンダリングし、現在の設定をパースし、ファクトを収集し、検証ゲートをパスした後にのみ(merged/replaced/overridden)適用する。これにより本番に触れる前の決定論的なチェックポイントが得られる。

5.2.5. Network Adapter#

ネットワークデバイスは異なるプロトコルを使用する。Network Adapterレイヤーはこれらの違いを抽象化し、上位レイヤーが Secure Shell (SSH) 経由でCiscoスイッチと話しているのか、Representational State Transfer (REST) Application Programming Interface (API) 経由でAristaスイッチと話しているのかを気にしなくてもよくなる。

5.2.5.1. インターフェース#

異なるデバイスは異なる管理インターフェースをサポートする。

インターフェース説明ライブラリ/ツールの例典型的な用途
Secure Shell (SSH) / Command Line Interface (CLI)最も汎用的だが構造化が最も少ない(テキスト入出力)Netmiko(Python)、Paramiko(Python)、scrapli(Python)、scrapligo(Go)レガシープラットフォーム、ベンダー固有の運用コマンド
NETCONF / RESTCONF構造化されたモデル駆動管理(YANGベース)ncclient(Python)、scrapli-netconf(Python)、nemith/netconf(Go)宣言型設定と標準化されたデータモデル
gRPC Network Management Interface (gNMI) / gNOI設定/状態と運用RPCのgRPCベースインターフェースpygnmi(Python)、gnmic(Go CLI)、openconfig/gnmi(Go)ストリーミングテレメトリと現代の運用ワークフロー
Representational State Transfer (REST) APIsHTTP/JSONまたはXML API、多くの場合プラットフォーム固有requests/httpx(Python)、net/http + OpenAPI生成クライアント(Go)コントローラーとクラウド/ネットワークプラットフォームAPI
JSON-RPC / ベンダーgRPC特定のネットワークOSで使用される構造化RPCパターンArista eAPI(JSON-RPC)、ベンダーgRPC SDK構造化ペイロードを持つ高速リモートプロシージャ実行

一部のライブラリは複数のプラットフォームにわたる共通インターフェースで抽象化レイヤーを提供する。

  • NAPALM(Network Automation and Programmability Abstraction Layer with Multivendor support): ベンダー間で統一されたAPIを提供するPythonライブラリ。
  • Pybatfish: デバイストランスポートライブラリではないが、実行安全性のための強力な補完ツールだ。実用的なパターンは「NAPALMまたはAnsibleでプラン/適用し、変更前後のネットワーク動作をpybatfishで検証する」だ。

なぜ抽象化レイヤーを使用するのか? CiscoとJuniper用に異なるコードを書く代わりに、NAPALMがひとつのAPIを提供する。get_facts()を呼び出すと、NAPALMはそれがCisco IOSデバイス(Secure Shell (SSH) 経由)、Arista EOS(eAPI経由)、Juniper Junos(NETCONF 経由)のどれであっても、デバイスのファクトを取得する方法を考える。トレードオフは、抽象化がベンダー固有の機能を隠すことだ。一般的な操作(設定の取得、設定のプッシュ、ファクトの取得)では素晴らしい。より高度な操作やエキゾチックなベンダー機能では、実装されていない可能性が高いためネイティブインターフェースに戻る。

5.2.5.2. 操作#

ネットワーク実行は設定管理だけではない。

操作タイプカバーする内容注記
設定変更フル設定/スニペット/宣言的状態をプッシュ; マージ/置換/削除モード最も一般的な操作タイプで、ツールによるサポートが最も充実
ゼロタッチプロビジョニング(Zero Touch Provisioning (ZTP))初回ブート時の自動オンボーディングDHCP + ブートストラップサーバー(TFTP/HTTP/HTTPS)とデバイスサポートが必要
ファイル転送イメージのアップロード、ログ/バックアップのダウンロード一般的なプロトコル: SCP、SFTP、TFTP、HTTP
デバイス操作再起動/リロード、運用コマンド(ping/traceroute)、バックアップday-2操作と修正に一般的
ロールバック設定を以前の既知の良好な状態に戻す一部のプラットフォームでのネイティブロールバック; その他ではバックアップ復元

各操作タイプは独自のエラーモードを持ち、特定の処理が必要だ。ソフトウェアアップグレードには事前チェック(十分なディスクスペースはあるか?)、事後チェック(デバイスは正しく起動したか?)、ロールバックプラン(アップグレードが失敗した場合、古いイメージをリロードする)が必要だ。結果はOrchestrationに判断のために公開されるべきで、Executionはローカルのガードレールとリトライを処理できる。

検証とレンダリングの場所: Source of TruthはインテントとオプションでPreレンダリングされた設定を所有する。Executionはデバイスレベルの安全チェックと運用検証(到達可能性、事前/事後チェック)を所有する。Orchestrationはいつ検証するか、結果で何をするか(承認、一時停止、ロールバック、またはエスカレーション)を決定する。シンプルなルールが必要な場合: ワークフローを変更する検証はOrchestrationに属する。デバイスアクションを変更する検証はExecutionに属する。

5.2.6. ソリューション#

ネットワーク実行のためのツールは多数存在し、それらを比較することでトレードオフを理解できる。

ツール実行モデルと強み最適な対象主な制限
AnsibleDSL(YAML)、エージェントレス、大きなモジュールエコシステム、サーバー/ネットワーク混在の自動化に強い素早い成果と広いプラットフォームサポートを求めるチーム大規模ではチューニングが必要; 複雑なロジックはYAMLで維持が難しくなる
Terraform宣言型IaC(HCL)、強力な差分/プランエンジン、ステートフルワークフロー、優れたクラウド統合インフラにTerraformを標準化しているチームネットワークプロバイダーの成熟度はまちまち; 状態管理が運用オーバーヘッドを増やす; day-2 opsには弱い
SaltPythonベースでエージェントまたはエージェントレスのオプションがあり、イベント駆動アーキテクチャ、優れたスケール特性既存のSaltショップまたはイベント量の多い運用ネットワーク自動化コミュニティが小さく、オンボーディングが急峻
NornirPythonファーストフレームワーク、スレッド並列処理、高度な柔軟性、デバッグが容易で高速カスタムまたはパフォーマンスに敏感なニーズを持つPython対応チーム既製コンポーネントが少ない; より多くのエンジニアリングの所有権が必要
カスタムPython/Goドメイン固有ロジックへの最大の制御と設計の自由エッジケース、内部プラットフォーム、高度に特化したワークフローすべてを所有する: 標準、信頼性パターン、テスト、ライフサイクルサポート
ベンダーコントローラーベンダーネイティブワークフローを持つインテント+ポリシーコントローラー(例: Cisco Catalyst Center、Aruba Central、Juniper Mist)強力なコントローラーAPIを持つ単一ベンダーエコシステムに標準化するチームマルチベンダー環境ではパターンの移植性が低い

多くのチームはユースケースとネットワークインフラによって複数のツールを使用する。

5.2.7. ゼロタッチプロビジョニング#

ゼロタッチプロビジョニング(ZTP)は、デバイスが初めて起動し、デバイスへの人間の介入なしに自動的に完全な設定を取得・適用する独自の実行パターンだ。データフローはday-2操作とは構造的に異なり、名前付きのアーキテクチャパターンとして扱う価値がある。

ZTPフロー

flowchart LR
    A[デバイス起動<br/>設定なし] --> B[DHCPが管理IPと<br/>ブートストラップURLを割り当て]
    B --> C[デバイスがサーバーから<br/>ブートストラップ設定を取得]
    C --> D[デバイスがSoTと管理<br/>ネットワークに認証]
    D --> E[Orchestratorが新しいデバイスを検出し<br/>フルプロビジョニングジョブをトリガー]
    E --> F[ExecutorがSoTから<br/>フルインテントを適用]

重要な洞察は、ブートストラップステップが意図的に最小限であることだ。デバイスを管理ネットワークに接続し、認証できるようにするだけの設定で十分だ。フルプロビジョニングはその後、標準のExecutorジョブとして実行され、Source of Truthから完全なインテントを取得する。これはZTPが別個のプロビジョニングシステムを必要とするのではなく、day-2操作と同じ実行パイプラインを再利用することを意味する。

一般的なZTPパターン

パターン仕組みトレードオフ
DHCP + 静的ファイルDHCPがデバイスごと(MACまたはシリアルでマッチ)の静的設定ファイルを指す実装がシンプル; SoTから取得しない; スケールで壊れる
DHCP + 動的生成ブートストラップサーバーがSoTにクエリし、リクエスト時にデバイス固有の初期設定を生成するday zeroからSoT駆動; デバイスが起動する前にSoTにデバイスが登録されている必要がある
OSイメージ + 設定デバイスがブート中にOSイメージと設定の両方をダウンロードする(OSプロビジョニングが必要なデバイスに必要)ベアメタルまたはファクトリーリセットデバイスを処理; ブートストラップサーバーの複雑さが増す

ZTPはシーケンスの依存関係を導入する。デバイスは物理的に起動する前にSource of Truthに登録されていなければならない。そうでなければ、ブートストラップサーバーには設定を生成するデータがない。キャンパスシナリオでは、これはServiceNow-Nautobot同期で処理される。スイッチがServiceNowに資産として追加された場合(サイトに到着する前)、Nautobotは場所、ロール、ベンダーを持つデバイスレコードを自動的に作成する。スイッチが起動すると、SoTはすでに準備完了だ。

5.2.8. ハイブリッドとクラウド実行#

Executorはますます2つの根本的に異なる環境に同時に対応する必要がある。従来のネットワークデバイスとクラウドネイティブプラットフォームだ。これらの環境は異なるAPIパラダイム、認証モデル、障害モードを持つ。それらを同一に扱うと脆弱な自動化につながり、完全に別のシステムとして扱うと作業が重複し一貫性のない操作が生まれる。

乖離の問題

次元ネットワークデバイスクラウドプラットフォーム
APIスタイルSSH、NETCONF、gNMI(ステートフル、長期接続)REST/HTTP(ステートレス、短期リクエスト)
認証モデル共有認証情報(ユーザー名/パスワード、SSHキー)一時トークン、サービスアカウント、インスタンスロール(AWS SigV4、Azure AD、GCPサービスアカウント)
操作完了通常同期(セッション終了前にコマンドが成功または失敗)しばしば非同期(APIが「受け付けました」を返し、最終状態のポーリングが必要)
障害の曖昧さNETCONFセッションの切断は明確な失敗クラウドAPIのタイムアウトは変更を適用したかもしれないし、しなかったかもしれない; クエリで確認する必要がある
冪等性アプローチデフォルトで命令型; 宣言型は慎重なモジュール設計が必要ほとんどのプラットフォームでネイティブに宣言型(Terraform、CloudFormation、Pulumi)

推奨アーキテクチャ

Intent(SoT)とOrchestrationを統一した状態に保つ。キャンパススイッチにVLANを作成する同じビジネスリクエストが、AWSにセキュリティグループを作成する必要があるかもしれない。Source of Truthは両方を保持する。Orchestratorは両方を調整する。Network Adapterレイヤー(5.2.5)でのみ実行パスが分岐する。ひとつのアダプターはキャンパススイッチに対してNETCONF/Ansibleを処理し、別のアダプターはクラウド環境に対してTerraformまたはクラウドプロバイダーAPIを処理する。

これはクラウドAPIの変更とネットワークデバイスの変更の影響範囲が同じ承認と監査証跡によって管理されることを意味する。プロトコルが完全に異なっても、これが正しいアーキテクチャの成果だ。

シークレット管理戦略は、長期のネットワークデバイス認証情報と短期のクラウドトークンの両方に対応しなければならない。クラウドプラットフォームでは、認証情報はジョブ開始時に生成され、保存されない。ほとんどのクラウドプロバイダーはこれのためのメカニズムを提供している(AWSインスタンスプロファイル、Azureマネージドアイデンティティ、GCPワークロードアイデンティティ)。ネットワークデバイスの認証情報はVaultに残り、実行時に注入される。Executorは対象タイプに関係なく、ジョブ実行間に認証情報を保持すべきではない。

5.2.9. セキュリティの考慮事項#

Executorはアーキテクチャ内でネットワークへの書き込みアクセスを持つコンポーネントだ。設定をプッシュし、サービスを再起動し、ファームウェアをアップグレードし、数百台のデバイスのルーティングポリシーを同時に変更できる。これにより、ほぼどのコンポーネントよりも重要なセキュリティ態勢が必要で、しかしアーキテクチャ観点からは最も軽視されることが多い。侵害されたまたは誤設定されたExecutorはデータ漏洩リスクではなく、ネットワーク障害リスクだ。

認証情報管理

ネットワークデバイスの認証情報はPlaybook、テンプレート、ジョブ定義、バージョン管理に絶対に現れてはならない。パターンは簡単だ。シークレットを専用のシークレットマネージャー(HashiCorp Vault、AWS Secrets Manager、CyberArk)に保存し、実行時にExecutorの環境に注入する。Executorはジョブ開始時に認証情報をフェッチし、永続的に保持しない。

これはまた認証情報のローテーションが運用上安全になることを意味する。デバイスのパスワードが定期的なスケジュールでローテーションされる場合、Executorは次の実行で新しい認証情報を取得し、デプロイや再設定は必要ない。

操作ごとの最小権限

すべての実行が同じレベルのアクセスを必要とするわけではない。読み取り操作(ファクトの収集、ドライランチェック、デプロイ前検証)は読み取り専用の認証情報を使用すべきだ。書き込み操作は変更タイプにスコープされた認証情報を使用すべきだ。VLAN変更をデプロイするジョブはBGP設定の変更を許可する認証情報を保持すべきではない。ネットワークプラットフォームがロールベースのアクセスをサポートしている場合(Aristaのロール、Ciscoの権限レベル、NETCONFのアクセス制御)、単一の侵害されたセッションの影響範囲を制限するために使用する。

キャンパスの例では、AristaスイッチでのVLANデプロイジョブはVLANとインターフェース設定を許可するが、ルーティングプロトコル設定や管理プレーン設定には触れられないロールを使用することを意味する。

関心の分離

誰が実行をトリガーできるか、誰が自動化ロジックを変更できるかは、異なるアクセス制御を持つ異なるロールであるべきだ。VLANデプロイジョブを承認・起動するオペレーターは、それを実装するAnsibleロールやPlaybookテンプレートを変更するアクセスを必要とせず、持つべきでもない。AWXとAAPでは、これはロール割り当てで強制される。「ジョブランチャー」は事前承認されたジョブテンプレートを起動できる; 「プロジェクトエディター」は基礎となる自動化ロジックを変更できる。

この分離は自動化が高影響の操作に使用される場合に最も重要だ。800台のスイッチにわたるファームウェアアップグレードを開始する人物は、アップグレードPlaybookを書いた人物であるべきではない。または少なくとも、本番使用のために利用可能になる前に、第2のレビュアーがPlaybookを承認すべきだ。

監査証跡の要件

すべての実行イベントは、何が起きたかを再現するのに十分な詳細でログに記録されなければならない。誰がジョブをトリガーしたか、どのジョブテンプレートが使用されたか、どのデバイスがターゲットとなったか、どのパラメータが渡されたか、各デバイスでの結果はどうだったか、タイムスタンプはいつか。ログは組織に適用されるコンプライアンス期間中保持されなければならない。規制対象産業での変更管理では通常12〜24カ月だ。

ほとんどのエンタープライズ環境でこれは任意ではない。変更管理プロセスは変更チケットから特定の実行イベント、特定のデバイス変更セットへのトレース可能な記録を必要とする。後からではなく最初からExecutorにこの監査証跡を設計すること。

自動化インフラのネットワークセグメンテーション

ExecutorとそのコントロールプレーンMichael(AWX、Ansible制御ノード)は管理ネットワークセグメントに配置すべきだ。デバイスへの実行トラフィックは、Executorが変更しているかもしれない同じデータプレーンではなく、利用可能な場合はアウトオブバンド管理ネットワークを経由して流れるべきだ。ジョブをトリガーするインバウンドアクセスには認証が必要で、信頼されていないネットワークからは到達可能であるべきではない。

避けるべき実用的な障害モード: 本番ユーザーVLANから到達可能なExecutorは、そのVLAN内の侵害されたホストがネットワーク変更をトリガーできる可能性があることを意味する。管理プレーンのアクセスは管理プレーンのネットワークに属する。

5.3. 実装例#

5.3.1. ユースケース: 異種混在キャンパスネットワークへの自動VLANデプロイ#

第4章のキャンパスネットワークを継続する。VLANサービス定義(そのID、サブネット、ベンダーごとの設定テンプレート、ターゲットスイッチグループ)はSource of Truthに保存されている。この章はExecutionブロックがそのインテントを受け取り、800台のスイッチ全体に確実にデプロイする方法に焦点を当てる。

シナリオ: ビジネスチームが新しいアプリケーション用の新しいVLANをリクエストする。リクエストはチケットシステムを通じて、VLAN ID、名前、キャンパスサイト、承認の詳細と共に来る。ネットワーク運用はArista、HPE、CiscoのアクセスおよびディストリビューションスイッチにこのVLANをデプロイし、接続を確認し、成功を報告する。

要件:

  • 複数のスイッチに並列でVLAN設定をデプロイする
  • 事前条件を確認する(VLANがまだ存在しない、スイッチに到達可能)
  • 何が変わるかを示すドライランを実行する
  • 失敗が発生した場合のロールバック機能を持つ実際のデプロイを実行する
  • デプロイ後の確認を行う(VLANがアクティブ、エラーなし)

5.3.2. ソリューションアーキテクチャ#

実行の詳細に入る前に、アーキテクチャ全体を俯瞰する。

  1. Source of Truth: NetBox(インベントリ、VLAN定義を保存)
  2. Orchestration/Triggering: AWXワークフローテンプレートの調整(APIローンチ、Webhookローンチ、スケジュールローンチ)
  3. Observability: 意思決定のためのリアルタイムデータを提供
  4. Execution:
    • 実行エンジン: Ansibleジョブテンプレート/タスク(事前チェック、ドライラン、デプロイ、確認、ロールバック)
    • Data Integration: Ansible/AWXのNetBoxインベントリプラグイン
    • Network Adapter: Cisco IOS XE、Arista EOS、HPE/ArubaのAnsibleモジュール
    • State Management: フェーズごと+ホストごとの結果のAWXジョブおよびワークフロー状態、失敗パスにはロールバックタスク

このソリューションは説明目的のためのものであり、普遍的な推奨ではない。

5.3.3. 実装フロー#

これはAWXワークフローとして複数のタスクノードで実行される。

  1. NetBoxのVLANインテント変更がWebhook経由でAWXをトリガーする
  2. AWXワークフローが開始し、インベントリ同期(NetBox)を実行する
  3. 事前チェックジョブが到達可能性、既存のVLAN状態、サイトのガードレールを検証する
  4. ドライランジョブが変更を適用せずにベンダー固有のタスクをレンダリングする
  5. 承認ノード(オプション)が本番実行をゲートする
  6. デプロイジョブがベンダー間で並列バッチでVLANインテントを適用する
  7. 確認ジョブが運用状態と意図された状態を確認する
  8. 失敗の場合、ロールバックジョブが影響を受けたスコープのみで実行される
  9. オブザーバビリティが最終検証をサポートするために事前/事後データを収集する
  10. 最終検証が実行され、実行サマリーが公開される
flowchart TD
    A[NetBox VLANインテント変更] --> B[AWXへのWebhook]
    B --> C[AWXワークフロー開始]
    C --> E[NetBoxからインベントリ同期]
    E --> F[事前チェックジョブタスク]
    F --> G[ドライランジョブタスク]
    G --> H[承認ノード]
    H --> I[デプロイジョブタスク]
    I --> J[確認ジョブタスク]
    J --> N[ネットワークデータ収集]
    N --> L[最終検証]
    L --> M[チケットとレポートの更新]

    F -->|失敗| X[停止して検証エラーを返す]
    I -->|失敗したホスト| Y[影響デバイスのロールバックジョブタスク]
    Y --> J
    F --> N

    %% --- Styles ---
    classDef sot fill:#cfe8ff,stroke:#0b5fb3,stroke-width:2px;
    classDef orch fill:#ffe0cc,stroke:#c24b00,stroke-width:2px;
    classDef exec fill:#d7f4e1,stroke:#0f7a3b,stroke-width:2px;
    classDef obs fill:#ffd6d6,stroke:#b22222,stroke-width:2px;

    class A sot;
    class B,C,E,H,L,M orch;
    class F,G,I,J,Y,X exec;
    class N obs;

5.3.4. ソリューションのまとめ#

この実装はすべての主要な実行機能を示している。

  • Data Integration: 動的インベントリを使用してNetBoxからインベントリとインテントを取得する
  • Triggering: AWXワークフローはAPI/Webhook/スケジュールをサポートし、承認ゲート実行も含む
  • State Management: AWXワークフロー/ジョブ状態が進捗と失敗ドメインを追跡; ロールバックパスが明示的
  • Engine: Ansibleが並列実行(forks/バッチング経由で設定)、エラー処理、ドライランを処理する
  • Network Adapter: ベンダーネイティブのリソースモジュールがひとつのインテントを異なるプラットフォームにマッピングする(cisco.ios.ios_vlansarista.eos.eos_vlans、HPE/Arubaコレクションモジュール)
  • Observability: 事前/事後データ収集が最終検証とレポートをサポートする

回復力の機能:

  • 事前チェックが到達不能なデバイスへのデプロイや重複VLANの作成を防ぐ
  • ドライランが適用前に変更を表示する
  • 安全チェックポイントはapply状態(mergedreplacedoverridden)の前にリソースモジュール状態(renderedparsedgathered)を使用する
  • 冪等モジュールが再実行を安全にする
  • デプロイ後の確認が静かな失敗を検出する
  • ロールバック: 専用のAWXロールバックノードがロールバックを影響を受けたデバイスのスコープに限定する

スケールの考慮事項:

  • forks: 50による並列実行が50台のスイッチを同時に処理する
  • より大規模なデプロイ(500台以上のスイッチ)では、グループにバッチ分けし、ワークフロー管理にAnsible Tower/AWXを使用する
  • コントロールプレーンまたは認証システムが負荷を処理できない場合はレート制限を追加する

5.4. まとめ#

Executionブロックはネットワーク自動化が具体的になる場所だ。設定がプッシュされ、デバイスが再起動され、変更が起きる。しかし信頼性の高い実行は Secure Shell (SSH) 経由でコマンドを送ること以上のものだ。

データ統合とトリガーから始まり、状態管理(冪等性、ロールバック、トランザクション的な安全性)、能力あるエンジン(シリアル/並列の選択、ドライラン/プラン、回復力)、ベンダー間のプロトコルの違いを隠すNetwork Adapterレイヤーに依存する。ObservabilityはValidationとガードレールにフィードし、Orchestrationは続行するか停止するかを決定する。ツール自体よりも実行パターンの方が重要だ。データを統合し、意図的にトリガーし、決定論的に実行し、結果を検証し、クリーンなロールバックパスを保つ。

小さく始めて意図的にスケールする。ひとつのワークフロー、ひとつのデバイスクラス、明確な事前/事後チェック。影響範囲が大きくなるにつれてバッチング、レート制限、より強い検証を追加する。Executionは強力でリスクが高い。徹底的にテストし、段階的にロールアウトし、常に監視し、常にロールバックを計画する。

参考文献とさらなる学習#

💬 Found something to improve? Send feedback for this chapter