はじめに
京都大学大学院情報学研究科修士1年の吉川知輝です。
2025年9月16日から10月10日までの約4週間、CIU NW チームにて就業型インターンシップに参加しました。 今回参加させていただいたチームでは、サイバーエージェントのプライベートクラウド「Cycloud」のネットワーク設計・構築・運用を行っています。 本記事では私がインターン中に取り組んだネットワーク自動化のためのコントローラー開発について紹介します。
背景
Cycloud では、プロジェクト単位でのネットワークの論理的な分離を行う VPC (Virtual Private Cloud) の機能の開発を進めています。 各プロジェクトが独立したネットワーク環境を持ち、他のプロジェクトから隔離された状態でリソースを利用できるようにすることで、より柔軟かつ安全なクラウド運用を実現することを目的としています。 このため、新たに VPC が作成された場合、ネットワーク分離を行うためにルーターに VRF (Virtual Routing and Forwarding) 等の設定を入れる必要があります。
プライベートクラウドのサーバーを直接収容する Clos 構成のネットワーク機器は、HPE Juniper Networking の Apstra System によって管理されています。 Apstra はデータセンターファブリック全体を一元管理・運用することを目的としたライフサイクル自動化ソリューションであり、ネットワークの設計から構築、運用までを包括的にサポートします。 一方で、VPC を実現するための PE ルーターの設定自動化には、Apstra には以下のような課題がありました。
- 運用中の機器を後から Apstra の管理下に追加できない
- 手動による設定変更や部分的な構成更新の運用が難しい
- 管理対象のネットワーク OS (NOS) が限られている
これらの理由から、VPC の作成・削除に伴い PE ルーターに必要な設定(VRF、Route Distinguisher、Route Target、インターフェースやポリシーなど)を自動的に投入するため、専用のコントローラーを自作する方針を検討しました。
Cycloud のリソース管理システムである「Networking」(以降 Networking)には、VPC のライフサイクル(作成・更新・削除)や IP アドレス空間の割り当てを管理する機能が備わっています。 この Networking の情報をもとに、PE ルーターの設定投入を自動化することが今回の取り組みの目的でした。
コントローラー
要件
今回の開発における要件は大きく以下の4点に整理されます。
- Cycloud における VPC ライフサイクルと連動すること
Networking を情報源とし、VPC の作成・更新・削除に伴いルーターへの必要な設定(VRF、Route Distinguisher、Route Target、インターフェース、ポリシーなど)を自動的に反映できる仕組みが求められました。 - 安全性と整合性の担保
複数台のルーターを使い All-Active で冗長化を行っているため、各ルーター間で不整合が生じないコンフィグの投入が必要です。 また、ネットワークの変更はサービス全体に大きな影響を及ぼすため、投入する設定が正当であるかを検証できる仕組みが必要です。設定差分の可視化、事前検証、失敗時のロールバックなどが必須要件として挙げられました。 - 柔軟性と運用親和性
Apstra のような完全自動化とは異なり、障害対応などでの人手による一時的な設定変更や、段階的な構成追加といったケースにも対応できる柔軟さが求められました。また、既存の Cycloud 運用フローと整合的であることも重要です。 - マルチベンダ対応の拡張性
今回は Juniper MX への設定投入を前提としていますが、将来的には他ベンダ機器にも拡張可能であることが求められました。そのため、特定の製品や実装に依存せず、標準化された手法での制御が前提とされています。
これらの要件を満たすことで、Cycloud におけるネットワーク運用の効率化と安全性を両立しつつ、将来的な拡張にも対応できる基盤を整えることができます。
使用技術
NETCONF
NETCONF (RFC6241) は、ネットワーク機器の設定・取得を標準化された RPC で行うプロトコルです。SSH をトランスポートとし、XML 形式でやり取りする点が特徴で、get-config や edit-config などの RPC を通じて機器の構成管理が可能です。また、YANG によるデータモデル定義を前提とするため、構成要素のスキーマ検証やマルチベンダー対応を実現できます。
ルーターへの設定投入を自動化するにあたり、複数の選択肢を検討しました。代表的な候補として、REST API、Ansible、OpenConfig/gNMI などがありましたが、それぞれに課題がありました。
- RESTCONF
Junos をはじめ各ベンダーは REST API を提供していますが、基本的にはベンダー固有の仕様に依存します。複数ベンダー機器を対象にすると、機能差分を埋めるために個別実装が必要となり、拡張性に欠けます。 - Ansible
構成管理ツールで、内部的には NETCONF を用いてネットワーク機器を操作します。junos_vrf モジュールなどによって一部の操作は冪等性を保ちつつ自動化可能ですが、サポートされているパラメータが限定的であり、プロトコル設定や詳細なルーティングオプションなど柔軟な制御はできません。最終的には冪等性を保証できない junos_command に頼らざるを得ず、本要件には適合しませんでした。 - OpenConfig/gNMI
OpenConfig はマルチベンダーを意識したデータモデルを定義しており、gNMI は高速な通信手段を提供します。しかし、OpenConfig モデル自体はベンダー実装の差異を吸収しきれず、結局はネイティブな設定を扱う必要が残ります。また、Cycloud で必要となる VRF や詳細なルーティング設定の一部は OpenConfig モデルに定義がなく、現実的には Junos Native 設定を扱う必要があり煩雑になる可能性があります。
これらの比較を踏まえ、最終的に以下の理由により NETCONF を採用しました。
- マルチベンダー対応性
標準化されたプロトコルであり、Juniper だけでなく他ベンダー機器にも拡張可能です。将来的なマルチベンダー展開を見据えた際に有用です。
- 柔軟かつ詳細な制御
YANG モデルに基づいた構成管理が可能であり、VRF や Route Target といった基本要素だけでなく、ベンダー固有の拡張設定も扱うことができます。これにより、Cycloud 特有の要件に合わせたきめ細やかな設定投入が可能になります。 - 安全性を担保する仕組み
ネットワークの変更はサービス全体に大きな影響を及ぼすため、投入する設定が正当であるかを検証できる仕組みが必要です。NETCONF では candidate コンフィグを用いた差分確認や事前検証、エラー時のロールバックといった基本的な安全機構が実装可能であり、設定の不整合を未然に防ぎつつ確実に反映することができます。今回の開発でもこれらの仕組みを活用し、投入前に差分を確認したうえで反映することで、安全性と整合性を担保しました。 - 実装のシンプルさとエコシステム
NETCONF は基本的に「SSH 上で XML による RPC をやり取りする」というシンプルな仕組みであり、既存の豊富なライブラリを活用することで実装負荷を抑えられます。また、利用実績が多く運用ノウハウも蓄積されている点も安心材料でした。
以上の理由から、今回の要件に最も適合する技術として NETCONF を採用しました。
アーキテクチャ概要
今回開発したコントローラーのアーキテクチャは以下のようになっています。

コントローラーは Networking を情報源として変更を検知し、コンフィグを生成・検証したうえで複数ルーターへ同期的に反映します。また、Prometheus/Grafana を用いた監視基盤と連携し、状態の可視化やアラート通知も行います。
①変更検知
コントローラーは Networking の API を一定時間ごとにポーリングし、VPC の追加・削除といった変更を検知します。差分を確認し、新しい VPC が検出された場合には処理をトリガーします。現状は VPC ID と IP アドレスを基準とした検知に対応していますが、同様の仕組みでその他の情報の変更にも対応することができます。
②コンフィグ生成
検知された差分に基づき、ルーターへ投入する設定 (Desired Config) を生成します。形式は NETCONF の XML で、追加された VPC に対しては groups と apply-groups を作成、削除された VPC については apply-groups から除去します。
生成されるコンフィグの例を以下に示します。新しい VPC に対応する VRF を作成し、BGP EVPN や RD/RT といった設定を含んだグループを定義し、それを apply-groups で適用しています。
生成 rpc 例
<rpc>
<edit-config>
<config>
<configuration>
<groups>
<name>tenant-vpc-1756194623580504469-controller-v0.0</name>
<routing-instances>
<instance>
<name>vrf-vpc-tenant00-test</name>
<instance-type>vrf</instance-type>
<routing-options>
<graceful-restart>
</graceful-restart>
<multipath>
</multipath>
<auto-export>
</auto-export>
</routing-options>
<protocols>
<evpn>
<ip-prefix-routes>
<advertise>direct-nexthop</advertise>
<encapsulation>vxlan</encapsulation>
<vni>3100</vni>
</ip-prefix-routes>
</evpn>
</protocols>
<route-distinguisher>
<rd-type>10.255.253.9:3100</rd-type>
</route-distinguisher>
<vrf-target>
<community>target:99:100</community>
</vrf-target>
</instance>
</routing-instances>
</groups>
<apply-groups operation="create">tenant-vpc-1756194623580504469-controller-v0.0</apply-groups>
</configuration>
</config>
</edit-config>
</rpc>
このように「groups」で VPC 単位の設定をまとめ、「apply-groups」で対象ルーターに適用することで、差分管理が容易になります。
③compare 取得
生成したコンフィグはすぐには commit せず、まず各ルーターの Candidate Configuration に投入します。その後、ルーター側で以下のコマンドにより差分を取得します(実際には RPC を用いてコントローラから実行しています)。
show | compare | display xml
これにより「投入したい設定」と「現在の設定」の差分を XML 形式で確認できます。この処理は全ルーターに対して実行することで、常に整合性が保たれるように設計しました。
④コンフィグ差分検知
取得した差分をコントローラー側で検証し、生成した Desired Config と一致しているかを確認します。この段階で不整合や想定外の差分が見つかれば処理を中断し、commit を行いません。 これにより、人手による緊急対応や既存設定の影響で意図しない変更が加わることを防止しています。
⑤同期デプロイ
この部分は本開発の中でも最も重要であり、同時に設計上の難所でもありました。 複数のルーターに設定をデプロイする際に不整合が生じると、場合によってはユーザーの通信を妨げる恐れがあります。そのため、要件のひとつである「安全性を担保する仕組み」を十分に検討し、慎重に設計する必要がありました。
初期実装では、すべてのルーターで検証が成功した場合のみ同期的に commit を実行し、1台でも失敗した場合は全ルーターでロールバックを行うという方式を採用しました。 さらに、連続して3回失敗が発生した場合には Polling を停止し、アラートを発報して運用者の介入を求めるようにしていました。 この方式では複数台のルーター間で不整合が生じることはなく、既存トラフィックへの影響を確実に防ぐことができます。 しかし、1台でもルーターが停止していると他のルーターへの設定反映もすべて止まってしまい、新規 VPC の操作ができなくなってしまいます。結果として、複数台で冗長化している意味が薄れてしまうという問題がありました。
そこで新たな方式として、ステート差分に基づいて投入コンフィグを決定する仕組みを検討しました。 コントローラーは次の2種類の内部ステートを保持します。
- コントローラーのステート:Networking API のレスポンスから得た「現在の VPC の状態」
- ルーターのステート:各ルーターに「デプロイ済みの VPC の状態」として記録された情報
この方式の基本的なルールを以下に示します(図2)。
- コントローラーは30秒ごとにAPIリクエストを送信し、VPCの状態を監視してコントローラー内部ステートを更新する
- コントローラーはユーザーが作成済みのVPC情報と、各ルーターにデプロイ済みのVPC情報(内部ステート)を保持する
- コントローラーは内部ステートの差分を検出すると、その差分に基づき投入すべきコンフィグを生成し、各ルーターへデプロイを行う(デプロイ成功時にルーターのステートを更新)
- 何らかの理由でデプロイに失敗した場合は「deploy error」として扱い、該当ルーターのステートは変更しない
- デプロイ失敗後、ルーターが復旧すると、次回Polling時にステート差分が再検出され、自動的に再デプロイが実行される

この方式では、たとえ一部または全てのルーターへのデプロイが一時的に失敗しても、コントローラーが Polling を継続し、差分をもとに再試行を行います。 これにより、「ルーターのメンテナンスや一時的な障害を考慮しなくてもよい」「ルーター間に依存関係が存在しない」といったシンプルで堅牢な動作が可能になります。
一方で、この方式にもリスクがあります。 更新・作成時に一部のルーターへのデプロイが失敗すると、一時的に設定の不整合が生じる可能性があります。 例えば図3のように、Router1 の SSH プロセスがダウンした場合、Router1 には設定を投入できない一方で、他のルーターには反映されるため不整合が発生します。 この状態でフォワーディング先の変更などが行われると、Router1 のみに旧設定が残り、一部 VPC の通信断が発生する危険があります。 同様に、BGP ピアフラップのような短期の障害でも起こり得ます。デプロイ単位は Polling 間隔の30秒であるため、即時復旧したとしても次のデプロイまで通信断が発生します。

この問題への対策として、VPC への変更に限り、初期実装の同期デプロイ方式を再利用することにしました。 つまり、重要な構成変更ではすべてのルーターを同期させて commit を行う一方で、通常の変更ではステート差分方式を適用することで、冗長性と安全性の両立を図っています。
このように、2つの方式の特性を組み合わせることで、障害耐性と運用柔軟性を兼ね備えたデプロイ処理を実現しました。 今回の実装を通じて、システムを「止めない」ことと「安全に保つ」ことのバランスをどう設計するかという、実運用における設計の本質を学ぶことができました。
監視基盤
監視は Prometheus を中心に構成し、Grafana や Alertmanager と連携させています。 Prometheus はコントローラーからメトリクスを Pull し、Grafana で可視化、Alertmanager でアラート発報を行います。エラーやデプロイ失敗時には Webhook 経由で通知され、運用者が即時に対応できる仕組みとしました。
コントローラー自体がメトリクスを生成するよう実装しており、処理の詳細な挙動を観測可能にしています。例えば以下のようなメトリクスを提供しています。
- API リクエストの状態
vpc_controller_api_request_active(ポーリングが稼働中か停止中か)
vpc_controller_api_requests_total(API リクエスト総数、成功/失敗別カウント) - コンフィグ投入処理
vpc_controller_config_push_duration_seconds(投入処理の所要時間、ヒストグラム)
vpc_controller_config_pushes_total(投入成功回数)
vpc_controller_config_push_failures_total(投入失敗の要因別カウント) - ルーターごとの結果
vpc_controller_router_operations_total(compare や commit ごとの成功/失敗数)
vpc_controller_router_failures_total(ルーター単位の失敗回数、検証エラーなど) - VPC 管理状況
vpc_controller_vpcs_total(現在管理している VPC 数)
vpc_controller_vpcs_added_total/vpc_controller_vpcs_removed_total(追加/削除件数)
実際の出力例(一部抜粋)は次のとおりです。
# HELP vpc_controller_api_requests_total Total number of API requests
# TYPE vpc_controller_api_requests_total counter
vpc_controller_api_requests_total{endpoint="cycloud",status="failure"} 1
vpc_controller_api_requests_total{endpoint="cycloud",status="success"} 61
# HELP vpc_controller_config_push_duration_seconds Duration of configuration push operations
# TYPE vpc_controller_config_push_duration_seconds histogram
vpc_controller_config_push_duration_seconds_bucket{operation="add",le="10"} 3
vpc_controller_config_push_duration_seconds_sum{operation="add"} 16.757672749999998
vpc_controller_config_push_duration_seconds_count{operation="add"} 3
これらのメトリクスを用いることで、「API の安定性」「設定投入の所要時間」「ルーターごとの失敗傾向」「VPC 数の推移」といった運用上重要な指標を可視化できるようになりました。結果として、コントローラーの自動化処理を継続的に監視・評価できる仕組みを実現しました。

まとめ
Cycloud における VPC ライフサイクル連動のネットワーク設定自動化に向けて、NETCONF を用いたコントローラーを開発しました。 VPC の変更検知からルーター設定の生成・検証・投入までを自動化し、差分検証やロールバック機構を備えることで、実運用に耐えうる安全性と整合性の高い仕組みを構築することができました。
特に、複数ルーター間での不整合を防ぎつつ、障害発生時にも継続してデプロイを試みるステート差分方式によるデプロイ設計は、本開発の大きな成果のひとつです。同期デプロイと非同期デプロイの両方を組み合わせることで、可用性と信頼性を両立し、運用負荷を大幅に軽減できる仕組みを実現しました。
また、Prometheus 連携によるメトリクス出力や Grafana での可視化を通じて、コントローラー自体の状態を継続的に監視・分析できるようになり、自動化処理を可視化して改善できる基盤が整いました。
今後はマルチベンダ対応の拡張、設定差分検知の高度化、より多様なネットワーク設定項目への対応などに取り組むことで、より柔軟で拡張性のあるネットワーク自動化プラットフォームへと発展させていくことができると考えています。
終わりに
今回のインターンを通じて、ネットワークの自動化における「現場の運用実態に即した仕組みづくり」の重要性を実感しました。
単に技術的に正しいだけでなく、既存フローや運用と調和させることが、実際に使われるシステムには欠かせません。
また、プロトコルやツールを比較検討し、自分たちの要件に最適な選択を行う過程を経験できたことや、インフラとソフトウェアが密接に関わる開発において仕様設計・実装・検証のそれぞれで異なる視点を持つことの大切さを学べたことは、今後の開発・研究においても大きな財産になると感じました。
サポートしていただいたメンターの方や CIU チームの皆さま、人事の皆さまには大変お世話になりました。 技術的なサポートだけでなく、設計の考え方やチーム開発の進め方など、多くの学びを得ることができました。ありがとうございました。