データセンター仮想化ツール Placemat v2の紹介

こんにちは、Necoチームの鈴木です。

Necoチームでは仮想データセンター構築ツールPlacematを使って、データセンターを丸ごと仮想化し、その上でサーバーのプロビジョニングやKubernetesクラスタ構築、Kubernetes上で動作するアプリケーションのTest Suitesを実行しています。 Placematはプロジェクト初期に開発されたツールで、古いツールに依存していたり、実装方式や設計が洗練されていないなどの課題があっため、4ヶ月前からv2を開発開始し、先日リリースしました。 本記事ではその機能と使い方、今後のCI改善 Placemat on Kubernetesについて紹介します。

特徴

  • シンプルな構成
  • YAMLの設定ファイルで多彩なデータセンター環境を再現可能
  • 多彩なVM設定
  • 仮想BMC

シンプルな構成

Placematはシングルバイナリで構成されています。 使い方もシンプルで、インストールしたバイナリにYAMLの設定ファイルを渡して起動すると、設定に従ってネットワークを構成してVMを起動、終了時にはそれらをクリーンアップします。 CIで自動テストを実行するための環境作りがとても楽になります。aptで依存ライブラリをインストール、debパッケージでPlacematをインストールして起動すれば完了です。

YAMLの設定ファイルで多彩なデータセンター環境を再現可能

下記のリソースをYAMLファイルに定義して組み合わせることで、様々な構成の仮想データセンターを構築することができます。

1: Networkリソースを定義することで、Bridgeネットワークを作成します。VMやスイッチを相互に接続できます。

kind: Network
name: my-net
type: external
use-nat: true
address: 10.0.0.0/22

2: NetworkNamespaceリソースを定義することで、独立したネットワーク領域を作成します。Network Namespace内でbirdなどのアプリケーションを実行することでスイッチの機能をエミュレーションすることができます。

kind: NetworkNamespace
name: my-netns
init-scripts:
  - /path/to/script
interfaces:
  - network: net0
    addresses:
      - 10.0.0.1/24
apps:
  - name: bird
    command:
    - /usr/local/bird/sbin/bird
    - -f
    - -c
    - /etc/bird/bird_core.conf

3: Nodeリソースを定義することでQEMUでVMを起動することができます。後述しますが多彩な設定が可能になっています。

kind: Node
name: my-node
interfaces:
  - net0
volumes:
  - kind: image
    name: root
    image: image-name
    copy-on-write: true
  - kind: localds
    name: seed
    user-data: user-data.yml
    network-config: network.yml
  - kind: raw
    name: data
    size: 10G
  - kind: hostPath
    name: host-data
    path: /var/lib/foo
    writable: false
ignition: my-node.ign
cpu: 2
memory: 4G
smbios:
  manufacturer: cybozu
  product: mk2
  serial: 1234abcd
uefi: false
tpm: true

4: Imageリソースでサーバーの起動ディスクイメージを定義できます。URLを指定してPlacematにダウンロードさせることもできますし、ローカルに保存済みのイメージファイルのパスを指定することもできます。

kind: Image
name: ubuntu-cloud-image
url: https://cloud-images.ubuntu.com/releases/16.04/release/ubuntu-16.04-server-cloudimg-amd64-disk1.img

Necoチームで使っている構成

Necoチームでは以下の構成の仮想データセンターを構築して自動テストに使っています。

仮想データセンターをテストに利用している図

  • Network Namespace、Bridgeをそれぞれ作成し、Vethを作って指定されたBridgeに繋ぐことでネットワークを構成する。そして、それぞれのNamespace内でbird、chrony、squid、dnsmasqをコンテナで起動し、SwitchのBGPリフレクタ、DHCP Relay、NTPサーバー、プロキシサーバーの機能をエミュレーションする。
  • Boot ServerやCompute SeverのVMを起動し、Tap Interfaceを使ってBridgeに繋いで、各RackのToR Switchに接続する。

多彩なVM設定

Nodeリソースは以下のような多彩なVMの設定が可能で、様々なユースケースに対応可能です。

  • プロビジョニング
    • cloud-init、ignitionを使ってサーバーのプロビジョニングを自動化することができ、テスト環境の構築を容易にします。
  • ファイル共有
    • hostPathvolumeを指定することで、virtio-9p-deviceを使ったホスト/ゲスト間のファイル共有が可能です。cloud-initやignitionでvolumeをmountすれば、テストに必要なファイルをホストから渡すこともできます。
  • TPM
    • Trusted Platform Module(TPM)をVMに設定することができます。TPMにディスク暗号化キーを保存するようなユースケースのテストを実行できます。
  • UEFI
    • 旧来のBIOSだけではなく、UEFIも利用することができます。

Quick Start

こちらのExampleを使ってPlacematを実際に動かす方法を紹介します。 動作環境はUbuntu 18.04/20.04になります。VMで動かす場合にはNested Virtualizationを有効にする必要があります。

ここでは以下のようなBootサーバー1台、Workerサーバー2台のClusterを構築していきます。

Exampleの構成

  • BootサーバーはUbuntu20.04のイメージを使って起動し、cloud-initで初期設定してdnsmasq, nginxを起動して、network bootサーバーとして機能する
  • WorkerサーバーはBootサーバーからiPXEをダウンロードし、Bootサーバーから提供されたFlatcar container linuxのイメージを使って起動する

使用する設定ファイルは以下になります。

kind: Network
name: net0
type: external
use-nat: true
address: 172.16.0.1/24
---
kind: Network
name: bmc
type: bmc
use-nat: false
address: 172.16.1.1/24
---
kind: Image
name: ubuntu-image
url: https://cloud-images.ubuntu.com/releases/20.04/release/ubuntu-20.04-server-cloudimg-amd64.img
---
kind: Node
name: boot
interfaces:
  - net0
volumes:
  - kind: image
    name: root
    image: ubuntu-image
  - kind: localds
    name: seed
    user-data: user-data.example.yml
    network-config: network-config.example.yml
cpu: 1
memory: 2G
---
kind: Node
name: worker-1
interfaces:
  - net0
volumes:
  - kind: raw
    name: data
    size: 10G
cpu: 1
memory: 2G
smbios:
  serial: 1234abcd
uefi: false
---
kind: Node
name: worker-2
interfaces:
  - net0
volumes:
  - kind: raw
    name: data
    size: 10G
cpu: 1
memory: 2G
smbios:
  serial: 5678efgh
uefi: false

インストール

以下のコマンドを実行して依存packageとPlacematをインストールします。

# 依存packageをインストール
$ sudo apt-get update
$ sudo apt-get -y install --no-install-recommends qemu qemu-kvm socat picocom cloud-utils freeipmi-tools

# Placematをインストール
$ curl -O -sfL https://github.com/cybozu-go/placemat/releases/download/v2.0.4/placemat2_2.0.4_amd64.deb
$ sudo dpkg -i ./placemat2_2.0.4_amd64.deb

Placematを起動

以下のコマンドを実行してplacematリポジトリをcloneし、exampleのclusterを構築します。

$ git clone https://github.com/cybozu-go/placemat.git
$ cd placemat/examples
$ sudo placemat2 --data-dir ./data --cache-dir ./cache ./cluster.example.yml

以下のログが表示されていれば起動成功です。

placemat2 info: "Start Placemat API server" address="127.0.0.1:10808"

サーバーにログイン

Placematを起動したコンソールとは別のコンソールを開き、以下のコマンドでnode(VM)の一覧を確認します。

$ pmctl2 node list
boot
worker-1
worker-2

続いてbootサーバーにログインします。

$ sudo pmctl2 node enter boot

# ユーザー: ubuntu, パスワード: ubuntu でログインできます。
# ターミナルを終了する時は、Ctrl-qとCtrl-xを続けて押してください。

worker-1にもログインしてみます。bootサーバーからOSイメージをダウンロードしてセットアップを終えるとログインできるようになります。環境によっては時間がかかる場合があります。

# worker-1にログイン
$ sudo pmctl2 node enter worker-1

# ターミナルを終了する時は、Ctrl-qとCtrl-xを続けて押してください。

BMCサーバーを起動

次にBMCサーバーを起動して、IPMI、Redfishを使ってVMを再起動してみます。ここではworker-1のBMCを起動して再起動してみたいと思います。

$ sudo pmctl2 node enter worker-1
$ echo 172.16.1.2 | sudo dd of=/dev/virtio-ports/placemat

# ターミナルを終了する時は、Ctrl-qとCtrl-xを続けて押してください。

PlacematはVMの/dev/virtio-ports/placematにcharデバイスを設定して、BMCアドレスが通知されるのを待機しています。 アドレスが通知されると以下のようなログを出力してBMCサーバーを起動します。

placemat2 info: "creating BMC port" bmc_address="172.16.1.2" serial="1234abcd"
placemat2 info: "BMC USer: Add user" user="cybozu"

ipmipowerコマンドを使ってworker-1の電源状態を取得してみます。

$ ipmipower --stat -u cybozu -p cybozu -h 172.16.1.2 -D LAN_2_0
172.16.1.2: on

続いてRedfishを使って電源状態を取得します。

$ curl -sku cybozu:cybozu https://172.16.1.2/redfish/v1/Systems/System.Embedded.1 | jq .PowerState
"On"

worker-1を再起動

ipmipowerコマンドでworker-1を再起動します。

$ ipmipower --reset -u cybozu -p cybozu -h 172.16.1.2 -D LAN_2_0
172.16.1.2: ok

worker-1のコンソールに入ると再起動してネットワークブートしている様子が確認できます。

$ sudo pmctl2 node enter worker-1
# ターミナルを終了する時は、Ctrl-qとCtrl-xを続けて押してください。

Redfishを使う場合はこちらのコマンドで再起動できます。

$ curl -X POST -H "Content-Type: application/json" -d '{"ResetType":"ForceRestart"}'  -sku cybozu:cybozu https://172.16.1.2/redfish/v1/Systems/System.Embedded.1/Actions/ComputerSystem.Reset

Placematを終了する

Placematを起動したコンソールでCtrl-cを押します。作成したBridgeやNetwork Namespaceなどをクリーンアップして終了します。

今後のCI改善計画 - Placemat on Kubernetes

最近ではRook/CephやMySQL Operator MOCOなど重量級のアプリケーションが稼働を始めたことなどもあって、CIの不安定さや遅さが問題になることが増えてきました。

  • GCP上のNested VMが安定しない。VMが落ちてしまったり、起動してこないなどの不安定な挙動がある。
  • GCPのQuotaに引っかかってしまい、インスタンスを起動できないことがある。
  • GCPの利用料金がかさむ。
  • Nested VMのCPUやIOのボトルネックにより、CIの実行時間が長い。

これらの課題を解決するために、PlacematをKubernetes上で動かしてCIを回すことを計画しています。

github-actions-controllerのイメージ図

  • 自社データセンターのBare Metalサーバー上に構築したKubernetesクラスタ(Staging環境)のPod内で、仮想データセンターを構築する。
  • Github Actionsのself-hosted runnerを使って上記の環境でワークフローを実行する。

Self-hosted runnerをKubernetes Clusterで管理するためのOperatorを絶賛開発中です。 こちらのOperatorが完成したら、KubernetesのPod内に構築された仮想データセンターでワークフローを実行するように、CI環境の移行を進めていく予定です。 事前のPoCではCIの高速化が期待できる結果が出ているため、大幅なCI改善を見込んでいます。