· 840 words · 4 min read

2. 設計原則#

あるネットワーク自動化チームが6ヶ月かけて、本当に誇りに思えるシステムを構築した。構造化データモデルからインテントを取得し、テンプレートエンジンでデバイス設定を生成し、ポリシーライブラリに照らして変更を検証し、完全なロールバック機能を備えたNETCONF経由でプッシュする。アーキテクチャ的には盤石だった。経営陣へのデモも好評だった。そしてネットワーク運用チームに引き渡した。

導入は一向に進まなかった。オペレーターはCLIを使い続けた。理由を尋ねると、答えは一致していた。「実行する前に何が起きるかわからない」「何か問題が起きたとき、何が起こったのか把握できない」「出力の読み方がわからない」。自動化チームは技術的には印象的なものを作り上げたが、運用面では不透明だった。ドライランモードも、人間が読めるような変更プレビューも、オペレーターが認識できる言葉で書かれた監査証跡も存在しなかった。システムはまだ信頼を得ていないのに信頼を求めるブラックボックスだった。6ヶ月分のエンジニアリングの成果は使われないまま放置された。

この結果はほとんどのチームが認めるよりもはるかによく起きる。自動化はバグや設計の欠陥だけで失敗するわけではない。それに依存しなければならない人々が信頼しないために失敗する。ここでは、ネットワーク自動化を信頼性高く、スケーラブルで、安全なものにする基本的な設計原則を探っていく。これらは抽象的な理論ではない。導入されて真の価値をもたらす自動化と、無視されて最終的に放棄される自動化の違いだ。

これらの原則の多くは他のソフトウェアプロジェクトにも当てはまる。しかしネットワーク自動化は重要なインフラを支えるという独自の特性を持つ。ネットワークエンジニアは慎重さ、精度、手動検証に基づくモデルを使ってこれらのシステムを数十年にわたって構築・保守してきた。今、私たちは彼らに根本的に異なるモデルを採用するよう求めている。それには信頼が必要だ。

2.1 信頼を築く#

具体的な原則に入る前に、信頼について話しておこう。信頼はネットワーク自動化を成功させるための礎だ。それなしには、導入はほぼ不可能になる。

なぜ信頼がこれほど重要なのか?なければ、ネットワークエンジニアはあなたの自動化を採用しないからだ。自動化が置き換える手動プロセスと少なくとも同等の信頼性(さらにその他のメリット)を提供すると信じてもらう必要がある。

さらに難しいのは、自動化システムを構築するエンジニアが深いネットワーク経験を持っていない場合が多いことだ。だから自動化は、ネットワークエンジニアチームにとって安全で、信頼でき、カスタマイズと管理がしやすいという強く明示的な特性を埋め込むことで補完しなければならない。

信頼できる自動化の重要性は、Autocon3でのDamien GarrosのプレゼンテーションBuilding Trustworthy Network Automationに着想を得ている。

シンプルにまとめると、必要な4つの基本特性は以下の通りだ。

  • Predictable(予測可能): 一貫した決定論的な結果。エンジニアは「実行」を押す前に何が起きるかを知る必要があり、毎回同じ動作が得られなければならない。
  • Reliable(信頼性): エラーを適切に処理する。障害から回復する。予期しない状況下でも、規模が大きくなっても、操作が安全に完了する(またはロールバックする)ことを保証する。
  • Usable(使いやすさ): 過度な複雑さなしにエンジニアが動作を検証、理解、制御できるインターフェース。ガードレール付きで。
  • Understandable(理解可能): ブラックボックスであってはならない。インテント、ステップ、結果、判断を、人間の信頼を築く形で公開しなければならない。
graph BT
  %% ===== Middle Layer =====
  subgraph L2[**特性**]
    direction LR
    B1[予測可能]:::layer2
    B2[信頼性]:::layer2
    B3[使いやすさ]:::layer2
    B4[理解可能]:::layer2
  end

  %% ===== Top Layer =====
  subgraph L1[" "]
    direction TB
    A[信頼]:::layer1
  end

  %% ===== Connections: Behavior → Outcome =====
  B1 --> A
  B2 --> A
  B3 --> A
  B4 --> A

  %% ===== Styling =====
  classDef layer1 fill:#ffcccc,stroke:#b8860b,stroke-width:2px,color:#000;
  classDef layer2 fill:#ffe6cc,stroke:#4682b4,stroke-width:1.5px,color:#000;

AI/ML技術がネットワーク自動化の領域に参入するにつれて、予測可能性または決定論的な動作はますます重要になっている。これらの技術は一定のランダム性をもたらすからだ。

これらの特性は交渉の余地のないものであり、後付けではない。自動化を使用し依存するネットワークエンジニアがこれらを認識する必要がある。

多くのネットワーク自動化ソリューションを構築してきた。よく設計されたソリューションがネットワークオペレーターに信頼されないという理由で無視されたり放棄されたりするのを見るほど、フラストレーションを感じることはない。これらの原則がその結果を避ける助けになる。

では、これらの特性を踏まえて、それらを支える原則を探っていこう。

2.2 設計原則#

信頼を土台として、信頼できる自動化に必要な特性を支える設計原則を探っていける。これらは自動化を信頼性高く、予測可能で、スケーラブルなものにする。

完全なリストははるかに長くなる可能性がある(後でソフトウェアエンジニアリングの原則を紹介する際に拡張する)。しかし、すべてのネットワーク自動化ソリューションが組み込むべき6つの基本原則がある。

  • Idempotency(冪等性): 同じ操作を何度実行しても最終状態は同じ。副作用を減らし、曖昧さをなくし、自動化をより理解しやすく安全に繰り返せるものにする。
  • Transactional(トランザクション性): 変更は完全に完了するか安全に失敗するか。部分的、不整合、半適用の状態はない。予測可能性に不可欠で、ネットワーク全体のロールバックを可能にする。
  • Intent-Driven(インテント駆動): さまざまな条件下でのシステムの望ましい状態を定義する。予測可能性を高め、認知負荷を減らし、システムをより使いやすくする。
  • Dry Run対応: 実行する前に何をするかを示す。人間がアクションを検証し、結果を視覚化し、ネットワークに影響が出る前に問題を検出できるようにすることで、自動化をより使いやすく信頼されるものにする。
  • Versioning(バージョン管理): データとロジック両方のバージョン管理をサポート。時間を前後に移動し、以前の状態を回復し、複数の状態を並行して維持する。予測可能性を強化し、信頼性を高める。
  • テスタブル(Testable): 本番環境で変更を実行する前に適切なテスト環境が不可欠。信頼性を高め、エンジニアがシステムの動作を理解する助けになる。

これらの原則はネットワークに限定されず、あらゆるITドメインの自動化に当てはまる。しかし変更が重大な運用リスクを伴うネットワーキングでは、特に重要になる。

これら6つの原則は、安全で予測可能な信頼できるネットワーク自動化の基盤を形成する。後で紹介するより高度なコンセプトへの土台となる。大規模で複雑なインフラ全体に自動化を拡大するとき、さらに重要性が増す。

graph BT
  %% ===== Bottom Layer =====
  subgraph L3[**原則**]
    direction LR
    C1[冪等性]:::layer3
    C2[バージョン管理]:::layer3
    C3[トランザクション性]:::layer3
    C4[テスタブル]:::layer3
    C5[ドライラン]:::layer3
    C6[インテント駆動]:::layer3
  end

  %% ===== Middle Layer =====
  subgraph L2[**特性**]
    direction LR
    B1[予測可能]:::layer2
    B2[信頼性]:::layer2
    B3[使いやすさ]:::layer2
    B4[理解可能]:::layer2
  end

  %% ===== Top Layer =====
  subgraph L1[" "]
    direction TB
    A[信頼]:::layer1
  end

  %% ===== Connections: Foundation → Behavior =====
  C1 --> B1
  C1 --> B4

  C2 --> B3
  C2 --> B2

  C3 --> B1
  C3 --> B2

  C4 --> B2
  C4 --> B4

  C5 --> B3
  C5 --> B4

  C6 --> B1
  C6 --> B3

  %% ===== Connections: Behavior → Outcome =====
  B1 --> A
  B2 --> A
  B3 --> A
  B4 --> A

  %% ===== Styling =====
  classDef layer1 fill:#ffcccc,stroke:#b8860b,stroke-width:2px,color:#000;
  classDef layer2 fill:#ffe6cc,stroke:#4682b4,stroke-width:1.5px,color:#000;
  classDef layer3 fill:#ccffcc,stroke:#228b22,stroke-width:1.5px,color:#000;

これらの設計原則のそれぞれにはより多くの文脈が必要だ。論理的な依存関係を反映した順序で探っていく。まず何を達成したいかを定義し、それを安全かつ正確に実行し、最後に機能することを検証する。

2.2.1. インテント駆動(Intent-Driven)#

なぜインテントから始めるのか? 自動化の実行方法を議論する前に、を達成しようとしているかを理解する必要がある。インテント駆動設計は、他のすべてが構築される基盤だ。

自動化を始めるよくあるユースケース:単純なアクションを実行するスクリプトやプレイブック。FQDNとインターフェース名を指定してインターフェースをアップまたはダウンさせる。しかしこれは問題を生む。そのインターフェースを次に扱う人は、そのDesired Stateが何かを知らない。アップであるべきかダウンであるべきか?

この問題は手動と自動化の両方の操作に影響する。しかし自動化では問題が悪化する。特に多くのアドホックな変更が加えられた場合、現在の状態からネットワークインテントを自信を持って推測することはできない。実際のネットワーク設定はIntent-Drivenロジックの結果であり、その信頼できる記録ではない。

インテントは変動性とカスタマイズのニーズに応じて異なるレベルで現れる。シンプルな環境ではより少ない可変データで済み、テンプレートに頼れる。他のデータはクロスチームのレビューが必要かもしれないが、規約とガードレールに従って更新できるものもある。

インテントは単純にネットワークのActual Stateだという主張をする人もいるかもしれない。「設定を見ればインテントがわかる」と。これは技術的にはインテントだが、比較できる独立したソースがなければ、元の実際のインテントと一致していて状況によって変更されていないことを証明できない。ネットワーク設定はインテントの出力であり、インテントそのものではない。

したがって、Intent-Drivenデータの品質が自動化の品質を直接決定する。このコンセプトは、第4章で詳しく説明するSource of Truth (SoT)(SoT)と密接に関連している。

Infrastructure as Code(IaC): インテント駆動自動化はInfrastructure as Code (IaC)の基盤だ。ネットワークインフラの定義をソフトウェアコードのように扱う。IaCによってバージョン管理、コードレビュープロセス、テスト、インフラの変更をソフトウェアの変更と同じように扱う能力が得られる。これはネットワーク自動化とソフトウェアエンジニアリングのベストプラクティスを橋渡しする。IaCはテンプレート、インベントリ、インテントをバージョン管理下のファイルとして保持する。変更はレビューされ、テストされ、追跡される。場当たり的なCLI編集として適用されることはない。

インテントを構築した上で、次の原則は何を望むかがわかったら、それを安全かつ一貫して実行できることを保証する。

2.2.2. 冪等性(Idempotency)#

冪等性が重要な理由: 冪等性は繰り返し実行が同じ結果をもたらすことを保証する。自動化は事故で、リトライメカニズムで、または設計上、何度も実行されることが多いため不可欠だ。冪等性がなければ、各実行が予測不可能な変更をもたらす可能性がある。

Idempotencyとは、同じ操作を何度実行しても最終状態が同じで、意図しない副作用がないことを意味する。

例えば、自動化されたACLプロビジョニングで、あるルールを定義した場合に期待されること:

  • ルールが存在しない場合、特定の位置に追加される。
  • ルールがすでに存在する場合、重複して追加しない。
  • 後で別のルールが追加された場合、以前のものはそのままで並び替えられない。

当然のことのように聞こえるが、現実はより複雑だ。システムは冪等性を確保するためのロジックを実装しなければならない。例えば、以下を確認する必要がある:

  • ACLの現在の状態は?
  • ルールはすでにその一部か?
  • そうでなければ、どんな差分を適用する必要があるか?

冪等性がなければ、設定が予測不可能な順序で適用され、再現性に影響する。

冪等性はネットワーク自動化のさまざまな次元に適用される。例えば、DHCPや識別子リクエストと結果のマッピングを理解するIPAMシステムを通じてIPアドレスをリクエストする場合:

図1: 冪等性の例(Damien GarrosのAutocon3トークより)

後で読む通り、冪等性を達成するためには、ImperativeモデルではなくDeclarativeモデルを優先して使用する。ステップではなく最終状態を定義する。これはimperativeモードが不可能だということではなく、より複雑だということだ。

冪等性は単一の実行内での一貫性に焦点を当てる。トランザクション原則は、変更が複数のシステムにわたってアトミックに適用されることを保証し、部分的または不整合な状態を防ぐ。

2.2.3. トランザクション性(Transactional)#

トランザクション性が重要な理由: ネットワーク変更は複数のデバイスに同時に影響することが多い。トランザクション性がなければ、途中での失敗がネットワークを不整合な状態に残す。一部のデバイスは更新済みで他は未更新。複数のアクター間の調整が本質的に複雑な分散システムでは特に問題になる。

Transactionalはデータベースでは一般的なコンセプトで、複数の変更が一貫性を維持するためにアトミックに適用される。ネットワーク(分散システム)では、トランザクション性はさらに複雑だが、新しい問題ではない。2006年にNETCONFRFC 6241)はネットワーク全体のコミットを導入し、複数のデバイスにわたってグローバルに変更を適用するか、検証が失敗した場合は完全にロールバックする。このAtomic Operationは一部のデバイスは更新されたが他はされていないという部分的な状態を防ぐ。これはトラブルシューティングの悪夢だ。ただし、すべてのプラットフォームがNETCONFをサポートしているわけではなく、統合の複雑さは大きく異なる。理論上は解決された問題でも、実際の実装はインフラに依存する。

トランザクション的な動作を提供することで、部分的または壊れた操作(トラブルシューティングが困難で、システムを予測不可能な状態に残す)を防ぎ、自動化への信頼が損なわれないようにする。一部のデバイスが変更を適用し他が適用していないネットワークは、完全にロールバックされたネットワークよりも悪い。

では一般的に、ネットワークにトランザクション性をどう適用できるか?これは技術の組み合わせだ:

  • NETCONF: 分散管理の調整をサポートするネットワーク管理機能。しかしサポートは非常に限定的。
  • データベースバックのトランザクション: ACID特性を持つデータベースに設定変更を保存し、いずれかのデバイスが失敗した場合のRollback機能を持つ調整されたバッチで適用する。
  • 変更通知キュー: すべての意図した変更を捕捉し、グループとして検証し、いずれかのデバイスが失敗した場合の調整されたRollbackメカニズムで実行する。
  • 二相コミットパターン: まずすべてのデバイスで変更を準備し(フェーズ1)、その後同時にコミットし(フェーズ2)、フェーズ2がいずれかのデバイスで失敗した場合はRollbackする。
  • トランザクションログ: 部分的な操作を手動または自動で元に戻すのに十分な詳細を記録した変更試行のログ。

分散環境のすべてのメカニズムはシームレスなロールバックを提供するためにロールバック機能を必要とすることに注目してほしい。以前の状態に移行するために(プラットフォームの内部または外部から)有効化できるコミットまたはスナップショットが必要だ。これは常に利用可能とは限らない。真のアトミックコミットが利用できない場合は、検証済みの「準備」ステージを実装し、調整されたコミットまたは段階的なロールアウトを使ってリスクを低減する(ネイティブのアトミック性が利用できない場合のみ使用する)。

この原則は自然にVersioningと結びつく。何かがうまくいかないとき、現在どの状態にいるかを正確に知り、既知の良い状態にロールバックできる必要がある。

2.2.4. バージョン管理(Versioned)#

バージョン管理が重要な理由: すべての変更はリスクを伴う。バージョン管理によって、何が変わったか、いつ変わったか、誰が変えたかを正確に知り、必要な場合に元に戻す能力が得られる。規模が大きくなっても安全な運用の基盤だ。

歴史的に、ネットワークエンジニアリングは設定バックアップによって変更を管理してきた。ロールバック目的で使用されるスナップショット。しかし、バックアップにはコンテキストがないため、ロールバック後の変更後の状態を調整することは非常に複雑だ。

ソフトウェアエンジニアリングでは、GitのようなVersion Control System (VCS)が標準的な慣行だ(何らかの形のVCSがない環境で働いたことはない)。これらのシステムは以下を可能にする:

  • 容易なコラボレーション: 複数の開発者がコードに貢献し、異なるブランチで作業を進められる。
  • タイムトラベル: 何がいつ変わったかを理解するために過去の特定の時点に戻れる。
  • アトミックなグループ化: 複数のファイル変更を単一のユニットとしてまとめられる。

Versioningをネットワーク自動化に適用すると大きなメリットがある:

  • 監査性と追跡可能性: 誰が何をいつ変えたかを簡単に追跡でき、システムを透明にする。
  • クロスチームコラボレーション: 変更のレビューを促進し、チームベースの自動化開発を可能にする。
  • Atomic Operation: 複数のファイルにわたる関連する変更を一緒に適用でき、部分的または不完全な状態を防ぐ。
  • CI/CD統合: コードの変更が検出されるたびに、自動化されたパイプラインがテストと検証をトリガーできる。

設定テンプレートはバージョン管理の恩恵を受けるデータの典型的な例だ。単一のテンプレート変更がネットワーク全体のすべての派生設定に影響するため、バージョン管理が不可欠になる。一般的に、すべてのデータはバージョン管理された形式で保存されるべきだ。あらゆる種類のデータをモデル化したバージョン管理されたYAMLまたはJavaScript Object Notation (JSON)ファイル、またはより複雑な関係を持つデータが一般的だ。

GitOps: バージョン管理をさらに進化させた新興パターン。Gitリポジトリが唯一の信頼できる情報源となり、コントローラーがGitのDesired StateとネットワークのActual Stateを継続的に比較し、ドリフトを自動的に修正する。特にクラウドネイティブおよびKubernetes統合環境で、ネットワーク自動化での採用が進んでいる。

バージョン管理は履歴と監査証跡を提供する。次の原則は変更がデプロイ前に正しく機能することを検証することを保証する。

2.2.5. テスタブル(Testable)#

テスタブルが重要な理由: 規模が大きくなるとエラーが増幅される。1台のデバイスに影響するプレイブックのバグは対処可能だ。同じバグが1万台のデバイスに適用されれば災害だ。テストは本番環境にデプロイする前のセーフティネットだ。

ネットワークではテストが特に困難だ。ネットワーク全体を所有していない場合が多く(インターネットBGPピアリングを考えてみてほしい。反対側は所有していない)、または規模が法外(何千ものスイッチを持つデータセンターファブリックのテストを想像してほしい)。実際のテストシナリオを再現することはほぼ不可能か、費用がかかりすぎる。

だからといって選択肢がないわけではない。さまざまな状況下で自動化の動作とネットワーク状態を検証する複数のレベルでテストを実装できる。

テストピラミッドが有用なフレームワークを提供する:

graph BT
  %% ユニットテスト(基底)
  U1["ユニットテスト<br/>(データ品質、ロジック)"]:::unit

  %% 統合テスト
  I1["統合テスト<br/>(シミュレーション環境)"]:::integration

  %% エンドツーエンドテスト(頂点)
  E1["エンドツーエンドテスト<br/>(ラボ、検証)"]:::enduser

  %% リンク
  U1 --> I1
  I1 --> E1

  %% スタイリング
  classDef unit fill:#a6e3a1,stroke:#3b7a57,stroke-width:2px,color:#000;
  classDef integration fill:#89b4fa,stroke:#1e3a8a,stroke-width:2px,color:#000;
  classDef enduser fill:#f9e2af,stroke:#b8860b,stroke-width:2px,color:#000;
  • Unit Test(ユニットテスト) はモックや模擬システムを使って、データ品質、基本的なロジック、特定の動作を分離して検証する。素早く実行でき、根本的なエラーを早期に発見する。
  • Integration Test(統合テスト) はシミュレートされた(簡略化された)環境にサードパーティシステムを導入する。さまざまな自動化コンポーネントが相互作用しシミュレートされたネットワークフレーバーと連携し、統合ポイントを検証できる(例えば、ネットワークデバイスのApplication Programming Interface (API)またはSecure Shell (SSH) Command Line Interface (CLI)インターフェースを模擬する)。
  • End-to-End Test(エンドツーエンドテスト) は仮想化ネットワーク環境や本番ネットワークの一部をシミュレートするラボを使って、本番に近いシナリオで動作を検証する(このトピックについては第9章で深く掘り下げる)。

AIコードアシスタントはテスト生成にますます役立っている。何をテストすべきかを明確に述べられれば、これらのツールは包括的なテストスイートを素早く作成する助けとなる(そして一見では気づかないロジックの欠陥を発見することもある)。

重要な洞察:自動化は継続的なテストが必要で、システムが成長しても何も壊れないことを確保する。開発の遅い段階で導入されたリグレッションは、ユニットテスト中に発見されたものよりはるかにコストがかかる。自動化が拡大するにつれ、これは避けられない。

高度なテスト戦略:

  • カオスエンジニアリング: 意図的に障害(デバイスの停止、ネットワーク遅延)を注入して、自動化とモニタリングが適切に処理することを検証する(NetflixはこのアプローチをChaos Monkeyで普及させた)。
  • プロパティベーステスト: 常に真でなければならない特性を定義し(例:「BGPは常に30秒以内に収束すべき」)、テストフレームワークにそれらを検証するシナリオを生成させる。

最後に、変更をデプロイする前に、オペレーターは何が起こるかを把握する必要がある。

2.2.6. ドライラン対応(Dry-Run Friendly)#

ドライラン機能が重要な理由: これまでのすべての安全策があっても、人間は自動化が実行する前に何をするかを理解する必要がある。ドライラン機能は信頼と行動を橋渡しする。変更が行われる前に、オペレーターに何が変わるかを正確に示す。

どんな重大な決断においても、実行前に行動計画を理解することが重要だ。家を建てるとき、工事を承認する前にどのようになるかを確認したいと思う。同様に、ネットワークエンジニアリングでも、デプロイ前に実行計画をレビューする変更管理プロセスに慣れている。

ネットワーク自動化では、変更の頻度と範囲が大幅に増加する可能性がある。何が実行されるかを事前にオペレーターに明確に見せることは、信頼を築き適切なレビューを可能にするために不可欠だ。

このDry Run機能を提供するツールがあるが、必要であれば独自のものを作ることもできる:

  • Ansible: --check--diffフラグが変更内容を表示する。
  • Terraform: terraform planコマンドが現在の状態とDesired Stateの差分を表示する。
  • カスタムネットワークAPI: 「ドライラン」またはプレビューモードを公開するものもある。

この可視性がどのようなものかの例:

Ansible差分出力

- description: Uplink to CoreSwitch1
+ description: Uplink to CoreSwitch2
  mtu: 9216

Terraformプラン出力

~ description = "Uplink to CoreSwitch1" -> "Uplink to CoreSwitch2"
  mtu          = 9216

カスタムネットワークAPIプレビューレスポンス

{
  "operation": "PATCH",
  "path": "/interfaces/Gi0-1",
  "changes": [
    {
      "field": "description",
      "current_value": "Uplink to CoreSwitch1",
      "proposed_value": "Uplink to CoreSwitch2",
    }
  ],
  "mtu": 9216
}

ドライランは自動化を「なるようになれ」というアプローチから、意図的でレビュー可能なプロセスへと変える。

高度なドライランのコンセプト:

  • 影響分析: 変更内容を示すだけでなく、ビジネスへの影響を分析して伝える(例:「これにより一時的にトラフィックの10%が影響を受ける」)。
  • 段階的ロールアウト: まず一部のデバイスに変更を展開し、影響を検証してから全体にデプロイすることで、規模でのドライランを実装する。
  • ネットワークシミュレーション: 本番ネットワークのレプリカに対してドライランを実行するためにネットワークテストツールと組み合わせる。

2.3. アーキテクチャ上の意思決定パターン#

基本原則を超えて、理論と実際の実装を橋渡しする重要なコンセプトと考慮事項がある。これらのパターンは自動化アーキテクチャについて戦略的な決定を下す助けになる。

2.3.1. 宣言的 vs. 命令的(Declarative vs. Imperative)#

宣言的アプローチと命令的アプローチの選択は根本的だ。それぞれにユースケースに応じた強みとトレードオフがある。インフラ設定の管理には2つのアプローチがある:

  • Declarative(宣言的) 自動化は望ましい最終状態を定義し、システムがそれをどう達成するかを決定する。例:「インターフェースGi0/1のMTUを9000にしたい」。自動化エンジンが現在の状態を判断し、必要な変更のみを適用する。何を、つまり望ましい成果に焦点を当てる。
  • Imperative(命令的) 自動化は実行する正確なステップを指定する。例:「インターフェース設定を表示し、パースし、差分を計算し、この順序でこれらの正確なCLIコマンドを送信する」。どのように、つまり具体的なアクションに焦点を当てる。

宣言的アプローチは自然にIdempotencyDry Run機能、Transactionalな動作をサポートするが、それをサポートするインフラとシステムが必要だ。

命令的アプローチは精密な制御を提供するが、冪等にするのが難しく、意図しない副作用が起きやすい。ただし、対象システムが宣言的な機能を持たない場合は唯一の選択肢かもしれない。

主なトレードオフ:宣言的アプローチの方が拡張性が高い。利用可能な場合、複雑なワークフローを実装する複雑さは一定にとどまるが、命令的アプローチはワークフローが複雑になるにつれて複雑さが指数関数的に増大する。

ほとんどの現代の自動化フレームワーク(TerraformAnsible、Kubernetes、またはYet Another Next Generation (YANG)ベースのツール)はDeclarativeモデルに向かいながら、必要に応じてImperativeのフォールバックを許容する(例:Ansibleのrawモジュール、直接Command Line Interface (CLI)、Netmiko)。

Ansibleのようなツールはモジュールタイプに応じて両方の方法で機能できる。ネットワーク固有のモジュール(cisco.ios.ios_interfacesなど)は宣言的で、ansible.netcommon.cli_commandは命令的コマンドを実行する。以下の例では両方のアプローチを確認できる:

- name: AnsibleにおけるImperativeとDeclarativeアプローチ
  hosts: switches
  gather_facts: no
  vars:
    interface_name: GigabitEthernet0/1
    new_description: Uplink to CoreSwitch2
  tasks:
    - name: Imperative - 正確なコマンドを実行
      ansible.netcommon.cli_command:
        command: |
          configure terminal
          interface {{ interface_name }}
          description {{ new_description }}
          no shutdown
          end
      # このタスクを繰り返すと重複が追加され冪等性が失われる

    - name: Declarative - 望ましい状態を定義
      cisco.ios.ios_interfaces:
        config:
          - name: "{{ interface_name }}"
            description: "{{ new_description }}"
            enabled: true
        state: merged
      # このタスクを繰り返しても安全で、望ましい状態に収束する

宣言的アプローチでは、ロジックを外部システムにオフロードしていることに注意してほしい。場合によってはそれが利用できない場合もある。前の例で、宣言的なフレーバーを提供するために必要なロジックを実装したAnsibleモジュールcisco.ios.ios_interfacesをどのように活用しているかに注目してほしい。

宣言的アプローチはより安全で予測可能だが、特定のデバイスに対するモジュールサポートが必要だ。

2.3.2. ミュータブル vs. イミュータブルインフラ(Mutable vs. Immutable Infrastructure)#

コンセプト: インフラ(ネットワーク)をその場で変更できるようにするか、変更が必要な場合にインフラを完全に置き換えるか?

  • ミュータブルインフラ: デバイスにSSHで接続して設定を直接変更する(またはNETCONF、gNMI、何らかのApplication Programming Interface (API)経由で変更する)従来のアプローチ。変更はその場で適用される。
    • 利点:あまり破壊的でなく、オーバーヘッドが低い。
    • 欠点:状態の追跡が難しく、Configuration Driftリスクが高まる。
  • イミュータブルインフラ: 実行中のインフラを変更しない。代わりに、望ましい変更を加えた新しいインフラを作成してトラフィック/接続を切り替える。クラウド(コンテナ、VM)で多く使われるがネットワーキングではあまり一般的でない。
    • 利点:状態が予測可能で検証しやすく、ドリフトを排除する。
    • 欠点:オーケストレーションが必要で、回復がより複雑で、リソースのオーバーヘッドが高い。

ネットワーク自動化では、通常ハイブリッドな状態にある。設定はミュータブルで(その場で変更する)が、イミュータブル性の原則が設計を導くべきだ。すべてをバージョン管理し、変更を追跡し、必要に応じてゼロから再構築できるようにする。

2.3.3. グリーンフィールド vs. ブラウンフィールド(Greenfield vs. Brownfield)#

技術的な用語ではないが、ネットワーク自動化ソリューションを開発する際の2つの異なるシナリオを理解するのに役立つ:

  • Brownfield(ブラウンフィールド) 環境はレガシーシステム、手動プロセス、不整合な設定、属人的な知識を持つ既存の環境だ。自動化が意図されていなかった複雑さを自動化しているため難しい。不整合な設計、データ不足、レガシー技術、人間の習慣、トラフィックの制約。しかし最も一般的な環境だ。
  • Greenfield(グリーンフィールド) 環境は自動化ファーストの設計でゼロから構築される。すべての原則をクリーンに実装できる。初日からバージョン管理、宣言的インテント、クリーンなデータモデル、包括的なテスト。理想的だがまれだ。

なぜブラウンフィールド環境がこれほど複雑なのかを少し掘り下げてみよう…

  • 不整合なネットワーク設計(一貫性があったとしても、もはや完全に実装されておらず、例外の集まりになっている)。
  • クリーンで信頼できるデータの欠如。ネットワーク自体か古いスプレッドシートが参照先。
  • 異なるベンダーや世代のネットワークデバイスの一部は宣言的アプローチの実装を制限する(CLIを超えた)現代のネットワーク管理インターフェースをサポートしていない。
  • 運用文化と変化への恐れ。人が最優先であり、採用前に信頼を獲得する必要があることを忘れてはならない。
  • 自動化はクリーンな切り替えなしにライブトラフィックと共存しなければならない。エラーの余地は極めて小さい。

しかし、こうしたケースでも希望はある。以下の3つのアプローチがこれらのシナリオへの着手を容易にする:

  1. 部分的グリーンフィールドアプローチ: 新しいインフラを自動化しながら、レガシーシステムを段階的にリファクタリングする。最大の複雑さから始めることなく進捗を示す。
  2. 段階的なターゲット選択: 自動化しやすく素早い成果をもたらすネットワークの部分に焦点を当てる:
    • いくつかの管理機能(AAA、NTP、SNMP)の設定ドリフトと修復の追加
    • 単一のデバイスタイプのインターフェースプロビジョニングの自動化
    • 拡張前に単一のサブシステムを標準化する
  3. モメンタムの構築: 小さな成功のひとつひとつが自動化の価値を示し、資金調達と拡大への信頼を築く

2.3.4. デバイスの多様性とサービス抽象化#

すべてのネットワークデバイスやサービスが同じように動作するわけではない。異なるベンダー、モデル、さらにはソフトウェアバージョンが独自のインターフェース、機能、制限を持つ。自動化はこの異質性を戦略的に対処しなければならない。

2つの主要なアプローチ:

  • ベンダー固有の自動化を受け入れる: 再現性を損なわずに各ベンダーの独自機能に合わせた自動化を書く。利点:最初はシンプルで、デバイスの強みを活かす。欠点:サイロを生み、要件が変わった場合の移行が難しい。
  • 抽象化する: 一般的な操作を標準化するベンダーに依存しない抽象化レイヤーを作成する。利点:ポータビリティ、統一されたインターフェース。欠点:複雑さが増し、デバイス固有の機能が失われる可能性がある。

ベストプラクティス:レイヤードアプローチ ほとんどの成熟した運用では両方を使う。下位にベンダー固有のドライバー(デバイスタイプごとに1つのレイヤー)を置き、その上に共通の抽象化レイヤーを持つ。両方の戦略の利点が得られる。

実世界の例:DMVPNの代替構築 ネットワークベンダーはハブスポークVPNのスケーラビリティのためにDMVPN(Dynamic Multipoint VPN)を提供している。代替として、多くのシンプルなポイントツーポイントVPNトンネルを設定する方法がある。自動化なしではこれは煩雑だが(そのプロトコルが存在する理由だ)、自動化を使って何千ものトンネルを管理することは実現可能で(そして極端に複雑ではなく)、プロトコルの洗練ではなくオーケストレーションを通じた同様のスケーラビリティを提供する。事実上すべてのプラットフォームが基本的なVPNトンネルをサポートしているからだ。プロトコルの依存性を自動化の抽象化に置き換えた。多くの場合、より良いトレードオフだ。

重要な原則:実装の詳細(特定のデバイスがどのように動作するか)を達成したい最終目標から分離する。これはベンダー独立性を可能にし、システムについて推論することをシンプルにする。

2.3.5. ツール優先設計という誤解#

ツールは不可欠だが、良い設計の代替にはならない。一般的な誤り:ツールを購入して自動化の問題を解決してくれることを期待する。ツールは重要だが、既存のアーキテクチャと設計を増幅する。優れた設計の自動化戦略に平凡なツールを組み合わせたものが、最高のツールを持つ設計の悪い戦略を上回る。

設計とアーキテクチャは戦略であり、先に来るべきだ。ツールは実装の詳細だ。ツールを選択する前に要件の理解、アーキテクチャの設計、原則の定義に時間を投資する。分散アーキテクチャが適切な場合もある。他の場合は、成果と複雑さの観点でシンプルでより有能なソリューションがニーズに合う。唯一の公式はないが、自分の選択を認識して意図的に行う必要がある。

ツールは魔法の箱ではないことも覚えておこう。常に自分のロジックを持ち込む必要がある。カスタマイズとドメイン固有の設定は避けられない。

第3章では、ツールを評価する際に考慮すべき主要な構成要素を示す参照アーキテクチャを探る。

2.3.6. 購入 vs. 構築(Buy vs. Build)#

よくある戦略的な問い:既製品のソリューションを購入するか、カスタム自動化を構築するか、それともハイブリッドアプローチを使うか?

シンプルな原則:できるときは購入し、必要なときだけ構築する。直感に反するが、構築は購入よりも高くつくことが多い。しかし必要なものを購入できるとは限らない。

意思決定を評価する際:

  • 購入: 製品がニーズに近く、アーキテクチャをサポートし、コストベネフィット分析が有利な場合に使う。
  • 構築: 要件が独自で、専門知識があり、既製品のソリューションが原則に合わない場合に使う。

これは本質的に設計上の決定であり、調達上の決定ではない。どれだけのカスタマイズと制御が本当に必要かということだ。

実際には、ほとんどの組織はハイブリッドアプローチを使う。戦略的なコンポーネント(オーケストレーションプラットフォーム、CI/CDシステム、データストレージ)は購入し、ドメイン固有の自動化(テンプレート、ワークフロー、検証ロジック)は構築する。ドメイン固有のレイヤーは自分たちで所有しなければならない。汎用のレシピが必要な成果を提供することはめったにない。

オープンソースソリューションを評価する際は拡張性を検討する。フレームワークを再利用して、その上にカスタムレイヤーを構築することが多い。例えば、コアツールをカスタムデータモデルで拡張するネットワークインテントを保存するデータソースなど。また、オープンソースでも、必要に応じてサポートとエンタープライズエディションを利用してセーフティネットを追加できることを忘れてはならない。

2.3.7. 自動化のガバナンス#

何を自動化するかを誰が決めるか?自動化ロジックへの変更を誰が承認するか?本番の何千ものデバイスに対してジョブテンプレートを実行することを誰が承認できるか?これらの問いにはクリーンな技術的な答えはほとんどないが、自動化が重要な規模に達する前に組織的に答えなければならない。

統制されていない自動化は手動操作とは異なるクラスのリスクをもたらす。手動でエラーを犯すエンジニアは1台のデバイスまたは1つのセッションに影響する。プレイブックテンプレートでエラーを犯す自動化エンジニアはスコープ内のすべてのデバイスに同時に影響する可能性がある。影響範囲は自動化の能力とともに拡大する。

この文脈でのガバナンスとは4つのことを定義することだ:

  • スコープの境界: 自動化の成熟度にかかわらず自動化の対象となる操作と人間の実行が必要な操作。BGPポリシー変更、ルーティングプロトコルの変更、セキュリティポリシーの更新は、残りのスタックが自動化されていても人間が関与し続けるかもしれない。自動化がそれらを実行できないからではなく、エラーの結果が十分大きいためループに人間を必要とするからだ。

  • ロジック承認プロセス: 自動化ロジックへの変更(新しいプレイブック、変更されたテンプレート、SoTの更新されたデータモデル)は、ソフトウェアのコードレビューに相当するレビュープロセスを経るべきだ。ここでの規律はソフトウェアエンジニアリングを反映する。本番で動くコードへの変更は本番に到達する前にレビューが必要だ。自動化コードも同様だ。

  • 実行の承認: 誰がどのジョブをどのスコープに対してどの条件下でトリガーできるか。これは実行レイヤー(第5章)とプレゼンテーションレイヤー(第8章)のロールベースのアクセスコントロールに直接マッピングされる。ガバナンスモデルはポリシー文書だけでなく、ツールのアクセスコントロールで表現されなければならない。

  • 監査と説明責任: 自動化は手動の変更管理が生成するのと同じ監査証跡を生成しなければならない。実行イベントは変更チケット、承認者、実行した自動化ロジックの特定のバージョンに追跡可能でなければならない。規制された環境ではこれは任意ではない。

ガバナンスはそれ自体のための官僚主義ではない。組織が自動化への信頼を段階的に拡大するメカニズムだ。リスクが低く、可逆的で、よく理解された操作から始めて、自動化が実績を積むにつれてスコープを拡大することは、自動化を完全に阻止するか、ガードレールなしにデプロイするかのどちらよりも効果的だ。

2.3.8. これらの原則が重要な理由:失敗から学ぶ#

自動化は投入されたものを増幅する。クリーンでよく設計されたプロセスはより効率的で信頼性が高くなる。しかし、設計の欠陥、悪いデータ、誤ったロジックも拡大され、より大きな問題をより速く生み出す。

Metaの障害事例

2021年10月、Meta(旧Facebook)は数時間にわたってシステムをオフラインにしたグローバルネットワーク障害を経験した。原因は何か?自動化が設定ミスを増幅した。定期的なトラフィックシフトの際、自動化システムが不完全なポリシー検証に基づいてグローバルな変更を行った。設定がネットワーク全体にカスケードし、グローバルに伝播した単一障害点を生み出した。

根本原因はバックボーンルーターへの誤った設定変更で、データセンター間の通信を中断させた。このカスケード障害はサービスをグローバルに停止させ、内部ツールにも影響を与え、診断と解決を複雑にした。Metaは問題が悪意のある活動によるものではなく、ユーザーデータは侵害されていないと明らかにした。しかし、この障害は自動化戦略における重大なギャップを浮き彫りにした:

  • 冪等性の欠如: 現在の状態を確認せずに変更を適用
  • トランザクション性の欠如: 一部のデバイスは変更を受け、他は受けなかった(部分的な失敗)
  • 不十分なテスト: シナリオが本番前に発見されなかった
  • ドライラン機能の欠如: プレビューや検証なしに変更を適用
  • 不十分なバージョン管理: 問題のある変更を素早く特定してリバートできなかった
  • 不十分なオブザーバビリティ: 障害を十分早く検出できなかった
  • グレースフルデグラデーションの欠如: 影響範囲の封じ込めなしにグローバルに変更がカスケード
  • 責任の不明確さ: 自動化に対する明確な意思決定階層がなかった

原則へのマッピング:6つのコア設計原則はそれぞれこれらの失敗の一つに直接対処する。これらがあれば良いというオプションの特性ではなく、不可欠なセーフガードであることを示している。

教訓: 混乱を自動化してから後で修正しようとしてはいけない。代わりに:

  1. 理解して検証できるプロセスから始める
  2. 各ステップから学びながら段階的に自動化する
  3. すべての自動化の失敗を学習の機会として扱う
  4. セーフガードを組み込む:レート制限、ロールバックメカニズム、オブザーバビリティ、影響範囲の封じ込め
  5. 一つの領域での失敗がグローバルにカスケードしないよう懸念事項を分離する

これが第1章で紹介したPeople、Process、Technologyアプローチとどのように結びつくかに注目してほしい。

探ってきた原則(Intent-DrivenIdempotencyTransactionalVersioning、テスタブル、Dry Run機能)はこれらの失敗モードに直接対処する。オプションの機能ではなく、最初から組み込まれなければならない不可欠なセーフガードだ。

2.4. ソフトウェアエンジニアリングの原則#

ネットワーク固有の設計原則に加えて、より広範なソフトウェアエンジニアリングの原則が保守可能でスケーラブルな自動化システムの構築に重要な役割を果たす。ソフトウェアエンジニアリングのバックグラウンドがあれば、これらのほとんどを認識するだろう。ここでの価値は、それらがネットワーク自動化に具体的にどのように適用されるかを見ることにある。

12すべてがこのドメインで同じ重みを持つわけではない。4つは重要インフラ自動化に固有の失敗モードに対処する。最小驚き原則(予期しない動作をする自動化は2.1節で確立された運用上の信頼を根付く前に破壊する)、防御的でロバストなプログラミング(ネットワークは自動化が設計上予測しなければならない部分的で非決定論的な方法で失敗する、例外として処理するのではなく)、早期に失敗し、見えるように失敗する(早期の障害検出はデバイス全体に拡大する前に影響範囲を封じ込める)、懸念事項の分離(第3章のNAFフレームワークが直接具体化する構造的原則 — インテント、実行ロジック、プレゼンテーションを分離することは一般的なグッドプラクティスではなく、ブロックを独立して進化させ続ける特定の構造だ)。残りの8つの原則は標準的なソフトウェアの衛生だ:正しく、重要で、知る価値があるが、ネットワーク自動化が具体的に失敗するか成功するかの理由ではない。

Robert C. Martinの「Clean Code」と「Clean Architecture」からインスピレーションを得て、2つのカテゴリに整理する:

  • クリーンコード原則: 読みやすく、保守しやすく、正確な自動化ロジックを書く方法。
  • クリーンアーキテクチャ原則: コンポーネントが独立して、テスト可能で、進化可能なままでいられるようにシステムを構造化する方法。

ネットワーク自動化への適用に焦点を当てると、Ken CelenzaによるこのNetwork to Codeブログシリーズにこれらの原則の良い例を見つけることができる。

2.4.1. クリーンコード原則#

このセクションでは、ソフトウェアコンポーネントをどのように構築するかに焦点を当てる。

読む人のためにコードを書く

書くコードは将来何度も読まれる。自分自身(デバッグのとき)や他の人によって。そして彼らは元のコンテキストを持っていない可能性が高い。意味のある名前、コメント、構造を通じてコードで意図を明確に表現する(コメントは使いすぎないよう注意し、慎重に使う)。自動化コードは機械への命令だけでなく、人間のためのドキュメントの一形態だ。

DRY - 繰り返しを避ける(Don’t Repeat Yourself)

自動化コードベース全体でロジックを重複させない。代わりに、共通パターンを再利用可能なテンプレート、関数、ワークフローに抽出する。

10の異なるプレイブックにデバイス固有の設定ロジックを書く代わりに、差異を変数にした共有テンプレートを作成する。バグを減らし、更新を容易にする。この原則はデータにも適用される。継承とポリモーフィズムを活用した適切なデータ構造を使い、よりスケーラブルで再利用可能なデータモデルを作成する。

DRYに違反すると、1箇所の修正が他の5箇所での修正を必要とし、必ず1つを見落とす。

単一責任原則(SRP)

各モジュール、関数、ワークフローは変更の理由が1つであるべきだ。ネットワーク自動化では:

  • 設定テンプレートのレンダラーがデバイス発見も行うべきではない
  • 検証ワークフローが変更も実行すべきではない

各コンポーネントが単一の責任を持つと、失敗が分離され、テストがシンプルになり、変更のリスクが減る。もちろん、これらの関数をすべてつなぐ合成関数(またはオーケストレーション)が存在する。

早期に失敗し、見えるように失敗する(Fail Fast, Fail Visible)

できるだけ早く問題を検出し、明確に表示する。自動化では:

  • 入力時にすぐにデータを検証する(デプロイまで待たない)
  • Dry Run出力を明示的かつ明確にする
  • 曖昧なエラーコードではなく完全なコンテキストで失敗をログに記録する
  • 何か問題が起きたらすぐにオペレーターに警告する

早期に問題を発見すると影響範囲と応答時間が減る。

セキュリティ

暗号化、認証、最小権限、監査証跡は、後から追加するのではなく、最初から自動化システムに組み込まれなければならない。

ネットワーク自動化では:すべての変更が監査可能で、認証情報はハードコードされず、アクセスコントロールは最小権限の原則に従うべきだ。完全なネットワークアクセスを持つ単一の自動化システムはセキュリティ上の時限爆弾だ。

セキュリティとコンプライアンスの考慮事項については第12章で深く掘り下げる。

最小驚き原則(Principle of Least Astonishment)

自動化はユーザーが期待する方法で動作すべきだ。予期しない、または直感に反する動作は信頼を損なう。

例えば、自動化タスクの名前が「deploy_interface」であれば、オペレーターはインターフェースを作成することを期待する。削除ではない。予期しない動作はユーザーをフラストレーションさせ、ミスを引き起こす。

防御的でロバストなプログラミング(Defensive and Robust Programming)

リトライ、Circuit Breakerパターン、Compensation Logic、フォールバックメカニズムを組み込む。分散システムは失敗する。それに備えて設計する。デバイスが一時的に到達不能な場合は、即座に失敗するのではなく指数バックオフでリトライする。変更が途中で失敗した場合はロールバックプランを持つ。

これらのパターンは第7章(オーケストレーション)で具体的に登場する。SagaのCompensationパターンが部分的なワークフロー失敗を処理し、リトライ/バックオフロジックが回復力機能に組み込まれる。
「送るものは保守的に、受け入れるものはおおらかに。」 Postelの法則(RFC 761)

ネットワーク自動化では:

  • 保守的な送信: APIやデバイスに送るデータが厳格なスキーマとコントラクトに準拠していることを確保する。
  • おおらかな受け入れ: さまざまなバリエーション(例:整数または変換による文字列としての属性)を処理する準備をして、異なるシステムバージョンとの相互運用性を最大化する。

この原則はクリーンコードとアーキテクチャを橋渡しする。統合ロジックの書き方とシステムインターフェースの構造の両方に影響する。

2.4.2. クリーンアーキテクチャ原則#

次に、ネットワーク自動化ソリューションのコンポーネントがどのように組み合わさるかを規定する原則を探る。

KISS - シンプルに保つ(Keep It Simple, Stupid)

シンプルな方が理解しやすく、テストしやすく、保守しやすい。設計、実装、アーキテクチャで過剰エンジニアリングを避ける。シンプルさはバグを減らし、保守性を高め、可読性を改善し、システムの拡張やデバッグを容易にする。

シンプルは単純を意味しない。過剰エンジニアリングや早まった抽象化なしに要件を満たす最も直接的なアプローチを選ぶことを意味する。

ネットワーク自動化では、(可能な場合)複雑な命令的スクリプトよりも直接的なDeclarativeアプローチを優先し、明確さ、小さな構成可能なコンポーネント、予測可能な動作、他の人(将来の自分も含む)が簡単に理解できるソリューションを優先することを意味する。

懸念事項の分離(Separation of Concerns)

データ(設定)、ロジック(ワークフロー)、プレゼンテーション(API/UI)を明確に分離する。これにより密な結合が防がれ、各レイヤーの独立した進化が可能になる。

ネットワーク自動化では:

  • データレイヤー: 構造化された形式で保存されたネットワークインテント
  • ロジックレイヤー: 自動化エンジンと検証ルール
  • プレゼンテーションレイヤー: オペレーター向けのAPI、CLI、ダッシュボード

この分離により、基礎となるロジックに影響を与えることなくオペレーターが自動化とやり取りする方法を変えられる。この分離はNAFの構成要素に直接マッピングされる。データレイヤーはSource of Truth(第4章)、ロジックレイヤーは実行(第5章)、オブザーバビリティ(第6章)、オーケストレーション(第7章)にまたがり、プレゼンテーションレイヤーは第8章だ。第3章でNAFフレームワーク全体を紹介する。

オブザーバビリティ(Observability)

自動化は自身の動作を測定し、失敗を検出し、修正アクションをトリガーするために計装されなければならない。測定できないものは最適化できない。技術的なメトリクスとビジネス指向のもの(例:自動化イニシアティブのROI)の両方を追跡する。

第6章では、ネットワーキングで気にする異なる種類のオブザーバビリティデータ(メトリクス、ログ、トレース、ネットワークフロー、アラートなど)と、それらをすべてのレベルで有用な情報を提供するためにどう活用するかを説明する。

オブザーバビリティがなければ手探りで進む。自動化が正しく機能しているのか、単に機能しているように見えるだけなのかがわからない。覚えておいてほしい:自動化システム自体も失敗し、監視が必要だ。ネットワークを計装するのと同じくらい徹底的に自動化ツールを計装する。

拡張性(Extensibility)

将来を見据えて設計する。新しいベンダー、新しい技術、新しい要件が登場する。アーキテクチャは完全な書き直しを必要とせずにこれらに対応できるべきだ。

実際には:ベンダー固有のドライバーにはプラグインアーキテクチャを使い、ネットワークトポロジーについてのハードコードされた前提を避け、実装が進化しても安定したインターフェースを維持する。

最小結合、最大凝集(Minimal Coupling, Maximal Cohesion)

システムがどのように通信するかについて明確なコントラクトを定義する:スキーマ、検証ルール、後方互換ポリシー。これらのコントラクトはコンポーネントの独立した進化を可能にする。

ネットワーク自動化では、オーケストレーションシステムがよく定義されたREST APIを通じてデバイスドライバーと通信する場合、APIコントラクトが維持される限り、どちらのレイヤーも独立して進化できる。

すべてのシステムには常にAPIファースト設計でアプローチする。APIを先に設計する(実装ではなく)。これによりシステムを独立して開発でき、他のコンポーネントを壊さずに交換できる。


これらの高度な原則は、大規模(および小規模)組織全体で自動化をスケールさせることについて議論する後の章でより深く探る。今は、これらの原則が先に探った設計原則を補完することを理解しておこう。合わせて、規模でも信頼性が高く保守可能なネットワーク自動化の基盤を形成する。

2.5. まとめ#

この章では、信頼がネットワーク自動化を成功させる基盤であることを確立した。信頼は4つのコア品質から生まれる:Predictable(予測可能)、Reliable(信頼性)、Usable(使いやすさ)、Understandable(理解可能)。

これらの品質は6つの基本設計原則によって支えられる:

  1. インテント駆動(Intent-Driven): 何を達成するかを、どう達成するかより先に定義する
  2. 冪等性(Idempotent): 繰り返し実行が一貫した結果をもたらす
  3. トランザクション性(Transactional): 変更は完全に完了するか安全に失敗するか。部分的には決してない
  4. バージョン管理(Versioned): 完全な履歴と監査証跡ですべての変更を追跡する
  5. テスタブル(Testable): 本番環境にデプロイする前に動作を検証する
  6. ドライラン対応(Dry-Run Friendly): 実行前に変更をプレビューする

これらのコア原則を超えて、アーキテクチャ上の意思決定パターン(宣言的 vs. 命令的、グリーンフィールド vs. ブラウンフィールド、デバイス抽象化)とソフトウェアエンジニアリング原則(クリーンコードとクリーンアーキテクチャ)が、実際のシステムでこれらのパターンを運用化する。

これらの原則は抽象的な理論ではない。使用するツールやフレームワークに具体的な実装がある。本書の残りを通じて、アーキテクチャ的思考(第3章)がこれらの原則をより大きなシステムにどう適用するか、そして構成要素(第4〜9章)がそれらをどう運用化するかを見ていく。

主要な要点:

  • ツールではなく原則から始める
  • 複雑さではなくPredictableな結果のために設計する
  • 継続的に測定して改善する

これを一貫して行えば、信頼は自然についてくる。そして信頼があれば組織全体に自動化を拡大する能力が得られる。

自動化を信頼できるものにする原則を理解した。第3章アーキテクチャ的思考)では、これらの原則をスケーラブルなシステムにどう構造化するかを見ていく。組織とともに成長しても扱いにくくならない自動化をどう設計するかを学ぶ。ここで学んだ原則を体系的に適用するための実践的でアーキテクチャ的な視点だ。

💬 Found something to improve? Send feedback for this chapter