はじめに
CIU(CyberAgent group Infrastructure Unit)で IaaS 基盤の開発・運用をしている市野と近藤です。
今回は、Cycloud の新基盤の全貌に迫る連載シリーズの第四回として、IaaS(Infrastructure as a Service)レイヤーの設計と実装について解説します。
第一回でご紹介したとおり、新リージョンでは「利用者に負担を強いることなく、半永久的に最新のハードウェアとサービスを提供し続けられる仮想マシン基盤」を目指しています。本記事では、その根幹を支える IaaS レイヤーをご紹介します。
IaaS 編で扱う範囲
本記事では以下のテーマを扱います。
- 全体構成: コントロールプレーンと CN(Compute Node)の役割分担
- IaC とデプロイメント: IaaS のコンポーネントをどのようにコード化し、デプロイしているか
- ライブマイグレーション: VM を無停止で CN 間移動する仕組み
- 仮想ネットワーク: OVS-DPDK と独自の DHCP / メタデータ サービス
全体構成
新リージョンの IaaS レイヤーは OpenStack を中心に構成されています。OpenStack は役割で大きく2つに分けられ、それぞれ Kubernetes と CN 上で稼働します。
- Kubernetes: keystone、nova-api、neutron-server、cinder-api などのコントロールプレーン
- CN: nova-compute、neutron-openvswitch-agent などの実際に CN を操作するコンポーネント
この2つは、構築・運用の方法が明確に異なります。コントロールプレーンは Kubernetes 上で、CN は Ansible でそれぞれ管理しています。
CN を Ansible 管理にしたのは、既存リージョンの構成が抱えていた課題への反省からです。既存リージョンでは、OpenStack のコントロールプレーンと CN を同じ Kubernetes クラスタに同居させていました。しかし、この構成は次の2つの運用課題を抱えていました。
- 稼働中の VM がある CN のカーネル更新が難しい: CN 上では利用者の VM が動いているため、ホストのカーネルを更新するには VM の退避が必要になり、更新の自由度が低くなります。
- K8s と CN でカーネル要件が衝突する: K8s が利用するコンテナランタイムが要求するカーネルバージョンと、CN 側のカーネルの互換性が取れなくなりました。両者が同居しているため、K8s を更新しようとすると CN のカーネル更新も迫られ、上記の難しさと相まって、最終的に K8s クラスタ自体をアップデートできない状況に陥りました。
旧リージョンでは、コントロールプレーンと CN を1つの Kubernetes クラスタに同居させていました。

第一回で掲げた「すべてのコンポーネントが更新可能であること」という目標に対して、この同居構成は明確な障害でした。そこで新リージョンでは、CN を Kubernetes から切り離し、Ansible で直接プロビジョニングする物理サーバとして管理する構成に変更しました。コントロールプレーンと CN のライフサイクルを分離することで、それぞれを独立して更新できるようにしています。この使い分けが、新リージョンの IaC 設計の出発点です。]

また CN の起動方式も見直しました。旧リージョンのブログや発表をご覧になった方はご存じかもしれませんが、既存リージョンではディスクレスブート(ネットワーク経由での OS ブート)を採用していました。しかし、ローカルに保存したログはメモリ上に保存されるため、再起動で消えてしまいます。たとえ、ログ転送を行っていても、障害発生時には回収できないログがあり、原因調査の妨げになっていました。新リージョンではローカルディスクから起動する構成へと変更し、障害時にもログが手元に残るようにしています。
IaC とデプロイメント
新リージョンでは、OpenStack のコントロールプレーンを Kubernetes 上のコンテナとして、CN を Ansible で構成管理された物理サーバとして動かしています。管理ツールが2つに分かれたことで、IaC の設計には特有の課題が生まれました。本章では、その課題をどう解いたかにフォーカスしてご紹介します。
課題1: K8s マニフェスト管理 Helm vs Kustomize
コントロールプレーンの K8s マニフェスト管理には、当初 Helm charts の採用も検討しました。しかし最終的に、旧リージョンでの運用知見をふまえて Kustomize を採用しました。
旧リージョンで Helm charts を運用した際、次の課題がありました。
- 生成されるマニフェストが予測しにくい: 本番環境と開発環境の間に、変数の差し替えだけでは吸収できない差分があると、Helm chart 内に
ifやforのロジックが入り込みます。結果として、helm template を実行するまで、最終的に得られる K8s マニフェストが読み取りにくくなっていました。 - レビュー・編集の負荷が高い: ロジックが増えるほど、変更の影響範囲を追うのが難しくなり、レビューと編集の双方に負荷がかかっていました。
Kustomize は、base で共通のマニフェストを定義し、overlays でクラスタ固有の差分をパッチとして上書きする、宣言的な構成です。テンプレートロジックを持たないため、生成結果が予測しやすく、差分もレビューしやすくなります。
kustomize/
nova/
base/ # 全クラスタ共通の定義
overlays/
prd-openstack01/ # 本番クラスタ固有の差分
stg-openstack01/ # ステージング固有の差分
stg-openstack02/
この base/overlays 構成は、第一回で述べた「マシンファミリーごとに OpenStack クラスタを分割する」戦略とも相性がよく、共通部分を base に集約したまま、クラスタ追加時には overlays の差分を書くだけで再現性高く立ち上げられます。
課題2: K8s と CN に分かれた設定の二重管理問題
OpenStack の設定項目は膨大です。しかも nova.conf のように、コントロールプレーン側の設定と CN 側の設定を整合させなければならないものが数多くあります。
CN を Kubernetes から切り離したことで、設定は K8s 側(Kustomize)と CN 側(Ansible)の2系統で管理することになりました。単純に考えれば、同じ設定を2箇所で書き、両者を手作業で突き合わせることになります。設定項目の多さを踏まえると、この二重管理は運用を著しく煩雑にすることが予想されました。加えて、課題1 で採用した Kustomize はパッチベースの仕組みで、Ansible や Helm のように任意の値をテンプレートへ差し込む機能を持ちません。nova.conf へ機密情報を埋め込むにも、別の手段が必要でした。
この課題を、設定テンプレートの単一ソース化と、各ターゲットでのテンプレーティングによって解決しました。中核となるのが内製ツール config-generator です。
config-generator による設定の単一ソース化
config-generator は、設定テンプレートの単一ソースから各ターゲット向けの設定を生成する内製ツールです。common_templates/ 配下のテンプレートを1つのソースとして、CN 向け(Ansible)と K8s 向け(External Secret)の設定を機械的に生成します。
config-generator/
common_templates/ # 設定の単一ソース(nova, neutron, keystone, ...)
src/ # 生成スクリプト(Python + Jinja2)
output/
ansible/ # CN 向け(Jinja2 テンプレート)
external_secrets/ # K8s 向け(Go template)
生成されるテンプレートの記法はターゲットごとに異なり、CN 向けには Jinja2、K8s 向けには Go template で出力されます。同じパラメータ体系から複数フォーマットへ展開するため、K8s と CN で設定がずれることを構造的に防げます。テンプレートに不足している変数を検出する機能も備えており、設定漏れを早期に発見できます。
共有される設定値を1箇所で管理できる点もメリットです。整合させる必要があるのは機密情報だけではありません。たとえば keystone のエンドポイントは nova や neutron など複数のサービスから参照されますが、これを共通の変数として一度定義しておけば、各サービスのテンプレートから同じ値を参照できます。機密・非機密を問わず、共有される値を単一ソースで扱えます。
機密情報の注入は External Secret(Go template)と Ansible(Jinja2)でテンプレーティングする
前述のとおり、Kustomize 単体では設定ファイルへ値を差し込めません。そこで K8s 側では、External Secrets Operator のテンプレーティング機能を利用しました。この機能は Go template で記述できます。config-generator が Go template 形式で生成した設定テンプレートを configMapGenerator で ConfigMap として持ち、ExternalSecret の spec.target.template.templateFrom でそれをテンプレーティングしながら、Secret Manager 由来の機密情報を注入して最終的な Secret を生成します。
# nova の ExternalSecret(抜粋)
spec:
target:
name: nova-etc
template:
templateFrom:
- configMap:
name: nova-etc # config-generator 由来の nova.conf テンプレート
items:
- key: nova.conf
data: # Secret Manager から取得する値
CN 側は、Ansible の Jinja2 が同じ役割を担い、同じ config-generator の単一ソースからテンプレートを生成します。これにより、機密情報を Git 上のマニフェストに置くことなく、K8s と CN の双方で設定を一貫して生成できます。
さらに工夫したのが、Secret Manager から取得する値そのものの扱いです。この値も、K8s 側と CN 側で同じように参照できる必要があります。そこで、機密情報を Secret Manager へ構造化データとして保存し、それを既存の vars にマージして使う構成にしました。設定値(vars)は機密でない項目のみを持ち、機密情報は同じツリー構造で Secret Manager 側に置きます。
# vars: 機密でない設定値だけを定義(例: nova)
nova:
database:
xxx: yyy
# Secret Manager: 同じツリー構造で機密情報だけを保存
nova:
database:
xxx: yyy
構造化した secret を既存の vars へ再帰的にマージすることで、テンプレートからは設定値と機密情報を区別なく nova.* のキーで参照できます。
# config-generator の共通テンプレート(nova.conf)
connection = mysql+pymysql://{{ nova.database.username }}:...
こうすることで、Jinja2 でも Go template でも、機密情報を通常の vars と同じように扱えます。設定値と機密情報を区別なくテンプレートから参照できるため、当初から構想していたテンプレーティングの仕組みとも自然に噛み合いました。
ここまでの設定生成の流れを図にすると、次のようになります。

VM のライブマイグレーション
さて、ここまでのセクションでは IaaS レイヤーの運用や管理面のお話をしてきましたが、続いては VM 基盤としての機能や設計についてご紹介していきます。まずは、VM のライブマイグレーションについてのお話です。
ライブマイグレーションとは
ライブマイグレーションは、稼働中の VM を停止させずに別のホストへ移動させる機能です。ライブマイグレーションを利用することで、次のような運用を VM を止めることなく行えます。
- CN のメンテナンス(OS 再起動やハードウェア交換)の際に、VM を別のホストへ逃がす
- CN 間で vCPU / RAM 等のリソース負荷を調整する
VM を止められない、あるいは止めるための調整コストが高いワークロードにとっては、運用の柔軟性を大きく左右する重要な機能です。
仕組み
ライブマイグレーション機能の中心は、QEMU / libvirt による pre-copy 方式です。移行元の VM を動かしたまま VM メモリのページを移行先へ反復コピーし、コピー中に書き換えられたページ(dirty page)をトラッキングして再送します。未転送のメモリデータ量が十分小さくなったところで一瞬だけ VM を止め、最後のメモリ差分とその他 VM の実行状態を移し替えて移行先で VM の実行を再開します。最後のデータコピー時には VM が瞬断するため、実際にはごく短時間のダウンタイムが発生します。
パフォーマンスチューニング
ライブマイグレーションにおいては多くのパラメータが存在し、私たちの環境でもライブマイグレーションのパフォーマンスを向上させるための様々なチューニングを行っています。その中からいくつかのチューニングの工夫について紹介します。
(下記は OpenStack Nova 経由での設定の解説になります: https://docs.openstack.org/nova/latest/configuration/config.html)
まず初めにライブマイグレーションの帯域上限についてです。
# 約 50Gbps
live_migration_bandwidth = 5960
デフォルトではライブマイグレーションのデータ転送に使用できる帯域が実行時に動的に推定されますが、それではライブマイグレーションが過剰に帯域を消費してしまい、ストレージネットワーク等の他の通信に影響を及ぼしてしまう危険性があります。そこで上記の様に帯域上限を設定をすることでライブマイグレーションが帯域を食い潰してしまわないように制御することができます。
続いて、ライブマイグレーション時の並列データ転送に関する設定です。
live_migration_parallel_connections = 8
デフォルトでは単一の TCP セッションでデータ転送を行いますが、QEMU / libvirt のライブマイグレーションでは TCP セッション1つに対して1つの OS スレッドを払い出すため、高帯域なネットワークにおいては単一の TCP セッションではパケットを処理するための CPU リソースが足りず、利用可能な帯域を全て使いきれない場合があります。そのような場合に使用する TCP セッションを増やして並列でデータ転送を行うことで、マイグレーションにかかる時間を短縮できる場合があります。私たちの環境で検証を行った結果、今回は上記のような値に落ち着きましたが、適切な設定値は環境によって異なることが想定されるため、それぞれの環境において検証を行うことが重要です。
ハイパーバイザの仮想ネットワーク構成
データプレーンに OVS-DPDK を採用
新リージョンでは、ハイパーバイザ上での仮想ネットワークのデータプレーンに OVS-DPDK を採用しました。
一般的な OVS では NIC からのパケット受信に際する割り込みやポーリングを起点に、カーネルデータパスでパケットが処理されます。構成によっては VM とのパケットの受け渡しの際にカーネルとユーザ空間をまたぐパケットコピーが発生するなどしてオーバーヘッドが多くなり、スループットの頭打ちを招いてしまう場合もあります。また、パケット処理を担うカーネルスレッドやユーザ空間の OVS プロセスは他のプロセスと同様に CPU スケジューリングの影響を受けるため、ホストの負荷状況によって処理のタイミングが揺らぎ、レイテンシが不安定になるという問題もあります。
OVS-DPDK は、DPDK (Data Plane Development Kit) を OVS のデータパスとして使うことで、これらの問題を緩和します (https://docs.openvswitch.org/en/latest/topics/dpdk/pmd/)。ユーザ空間で動作する PMD (Poll Mode Driver) スレッド が NIC のキューを常時ポーリングしてパケットを取り込むため、割り込み処理やカーネルデータパスをバイパスし、ユーザ空間だけでパケットを処理することができます。さらに PMD スレッドをそれ専用に確保した CPU コアにピニングすることで、他のプロセスとの CPU スケジューリングの競合による影響を抑えることができ、高いスループットと安定した低レイテンシを実現できます。
そのような OVS-DPDK の利用を踏まえて、今回採用した仮想ネットワークは下図の様になります。

本構成では 最大 100Gbps の NIC 2枚を LACP/balance-tcp の active-active 構成で使い、最大 200Gbps の物理帯域を実現しています。LACP は OVS ボンディングで管理しており、一番外側の OVS ブリッジとして用意している br-phy のポートに接続されます。
この構成のポイントは、VM 面の通信と CN 面の通信 (SSH、ストレージ、ライブマイグレーション等) を同じ NIC を共用しながら OVS のデータパスで分離している点です。
VM への ingress 通信は NIC で受け取ったのちに br-phy → br-gw → br-ex → br-int の OVS ブリッジを経由して vhost-user-client のポートで受け取り、VM に到達することができます。VM からの egress 通信も同様の経路を逆順にたどり、最終的に br-phy、NIC を通って外部へ出ていきます。
CN 面の通信は2つの NIC から SR-IOV (Single Root I/O Virtualization) の VF (Virtual Function) をそれぞれ1つずつ払い出し、2つの VF で Linux でのボンディングを組んでいます。こちらのボンディングは NIC でのボンディングとは異なり active-standby の構成で組んでいますが、その理由としては NIC でのボンディングで LACP を使っているため VF でも LACP の active-active 構成にしてしまうと LACP の通信が二重になってしまい予期しない動作不良を引き起こしてしまうリスクがあること、また active-standby にすることでハイパーバイザ面の通信の最大帯域が NIC 1枚分の 100Gbps になってしまうが、ハイパーバイザ面での通信には 100Gbps もあれば十分である見積もりだった、という事情がありました。
また、その VF の Representor は OVS ポートとして br-phy の OVS ブリッジに接続することで、ハイパーバイザ面への ingress 通信が NIC や OVS データパスを経由して VF Representor に入り、Representor に入ったものがそのまま VF から出てきて Linux ボンディングのインターフェースで扱うことができます。ハイパーバイザ面からの egress 通信も同様で、Linux ボンディングのインターフェースを経由して VF に入った通信がそのまま VF Representor を通して OVS データパスに入り、また br-phy や NIC を経由して外部へと出ていくことができます。
こちらの仮想ネットワーク構成や OVS-DPDK の詳細については CODT (Cloud Operator Days Tokyo) 2026 にてセッションを公開しておりますので、そちらも是非ご覧ください!
- https://cloudopsdays.com/on-demand-sessions-2026/
- https://event2026.cloudopsdays.com/
- 200GbE時代に再考するハイパーバイザネットワーク設計
独自DHCP・メタデータサービス
新リージョンではセキュリティ向上施策の一環として、テナント間ネットワークを分離する VPC の仕組みを導入しております。しかし、その VPC の制約により各テナントの VM から undercloud (プライベートクラウドの管理面) で稼働している DHCP やメタデータのサーバにアクセスする経路がありませんでした。もちろん、undercloud のネットワークから各テナントネットワークへの経路を都度設定すれば疎通は可能なのですが、そうするとせっかくテナント間のネットワークを分離しているのに、undercloud にさえ入れば全てのテナントネットワークに侵入できうるような事態になってしまう可能性もあります。
そのようなリスクを防ぐため、私たちは OVS のフロールールを活用した独自のDHCP・メタデータサービスを開発しました。こちらがそのサービスの概要図となっております。

CN 上の OVS データパスで VM (qemu プロセス) からのパケットを捕捉し、特定の通信のみを経路中の OVS ブリッジで曲げて dhcp-gw や metadata-gw といった CN 上のサービスに渡します。それらのサービスはパケットの中身を解析し、必要な情報を undercloud で稼働している dhcp-api や metadata-proxy といったサービスに渡します。この時、 gw サービスから undercloud への通信は VM のテナントネットワークではなく undercloud 面へ疎通できる経路がある CN 面のインターフェースから出ていくため、各テナントネットワークに undercloud への経路を用意することなく、必要な通信のみ VM と undercloud 間での通信を実現することができます。
こちらの独自DHCP・メタデータサービス の詳細についても CODT 2026 にてセッションを公開しておりますので、そちらも是非ご覧ください!
おわりに
本記事では、新リージョンの IaaS レイヤーについて、Kustomize / Ansible を利用したコントロールプレーンと CN の管理と工夫、また VM のライブマイグレーションといった機能や、OVS-DPDK を用いた仮想ネットワークの構成についてご紹介しました。
こうした基盤を「一度作って終わり」にせず、継続的に改善・更新し続けていくことを新リージョンの目標として掲げて目指していきます。
また、本文中でもいくつかご紹介しましたが、CIU の IaaS チームから Cloud Operator Days Tokyo 2026 へ5本ほどセッションを出しておりますので、ぜひご覧ください。
- https://event2026.cloudopsdays.com/
- OVSとLinuxネットワークで実現するHVの透過的プロキシとセキュアなVPCネットワーク
- kagentとMCPで実現するKubernetes-nativeなAIアラート自動応答システム
- Cinder Backupを活用したユーザー負担の少ないクロスリージョンボリューム移行システム
- 200GbE時代に再考するハイパーバイザネットワーク設計
- Open vSwitch と eBPF で実現する透過 L3DSR
次回予告
次回は「Cycloud 新基盤の全貌 第五回: ComputeController 編」をお届けします。本記事で紹介した IaaS レイヤーの OpenStack を利用者からどう抽象化しているのか、その中核となる ComputeController の仕組みに迫りますので、乞うご期待ください!
連載記事一覧
本シリーズでは、各チームが新基盤構築における技術的挑戦を公開しています。他のレイヤーの知見については、ぜひ連載の他の記事も併せてご覧ください。
- Cycloud 新基盤の全貌 第一回 新リージョン基盤の全体像
- Cycloud 新基盤の全貌 第二回 HW 編
- Cycloud 新基盤の全貌 第三回 NW 編
- Cycloud 新基盤の全貌 第四回 IaaS 編
- Cycloud 新基盤の全貌 第五回 ComputeController 編
- Cycloud 新基盤の全貌 第六回 LB 編
- Cycloud 新基盤の全貌 第七回 KaaS 編
- Cycloud 新基盤の全貌 第八回 FrontEnd 編
各レイヤの Cycloud の新基盤に関して、より詳細な仕様や設計思想を知りたい方は、上記各チームの Developers Blog 記事をぜひご一読ください。

