Test Everything: データセンター仮想化と自動テストの取り組み

こんにちは。Necoプロジェクトの池添(@zoetro)です。

Necoプロジェクトでは、自社データセンター上のインフラ構築の仕組みを開発しており、サーバーのプロビジョニング、Kubernetesクラスタの構築、Kubernetes上で動くアプリケーションのデプロイ、各種ソフトウェアやOSのアップグレードなどをすべて自動化しています。

blog.cybozu.io

このプロジェクトでは「データセンターの機能をすべてテストすること」を設計方針のひとつとしており、データセンターをまるごと仮想化してテストし、人の手を介することなく成果物の継続的インテグレーションとデリバリーを実現しています。 最初にこの方針を決めたとき、チーム内でも議論がありました。本当にデータセンターをまるごと自動テストできるのか?QAチームの手動テストをおこなわずに品質を保証することができるのか?など多くの疑問が湧きました。

私自身もプロジェクト開始時には半信半疑だったのですが、現在ではテストを自動化することが当たり前になっており、日々たくさんのテストを書いて不具合を検出しています。 本記事では、我々がどのようにデータセンターをまるごと仮想化し、自動テストの仕組みを構築していったのかを紹介します。

手動テスト vs. 自動テスト

Necoプロジェクトでは非常にたくさんのOSSを利用しています。 これらのOSSは進化が速く、例えばKubernetesは3ヶ月に1度リリースされて数多くの変更がおこなわれます。 各種ソフトウェアのアップグレードをおこなう前にはリリースノートのチェックもおこないますが、実際にはリリースノートに記述されていない破壊的変更も存在するためテストは必須です。 このような状況でバージョンアップのたびに手動でテストをしていたのではとても間に合わないでしょう。 また、重大な脆弱性が見つかった場合にはゆっくりとテストしている時間もありません。

さらに、サーバーのプロビジョニングやKubernetesクラスタ構築の仕組みをテストするためには、ネットワークやストレージ、LinuxカーネルからKubernetesが提供する機能まで幅広い知識が必要となります。 ここで開発とテストを分離してしまうと、開発者はテストを考慮した設計や実装をしにくくなり、テスト担当者はキャッチアップするのに多くの時間を要するため非効率となってしまうでしょう。 そこで、開発者が自分たちでテストを書いて品質に対して責任をもつことがもっとも効率的であると言えます。

以上のことから、開発者がテストを自動化し継続的デリバリーの仕組みを実現することは、我々のプロジェクトでは必須条件であると考えました。

データセンターをまるごとテストする難しさ

インフラのテストの難しさの1つがテスト環境を用意することです。

Necoプロジェクトでは、大規模なKubernetesクラスタに適したネットワークを実現するために、BGPをベースとしたネットワークを構築し、CNIプラグインも自作しています。 そのため、データセンターと同じネットワーク構成の環境を用意しないとテストすることができません。 また、分散システムの耐障害性をテストするためには最低3ラックの構成が必要となり、ネットワーク機器やサーバーのコストを考えると複数のテスト環境を用意することは難しいでしょう。

そこで、データセンターをソフトウェアで仮想化して1台のサーバー上でインフラ構築のテストを実施することにしました。 まず仮想データセンターを簡単に構築できるようにするために、placematというツールを開発しました。 placematを利用するとVMやコンテナを利用して任意の構成の仮想データセンターを立ち上げることができます。Necoプロジェクトでは下図のような仮想データセンターをテストに利用しています。

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

  1. Boot Server(管理用サーバー)およびCompute Server(計算用サーバー)を仮想マシンとして起動します。この時Boot ServerのOSにはUbuntuを利用し、Compute ServerはOSのない状態で起動します。
  2. 次にネットワークスイッチを模擬するためのコンテナを立ち上げます。スイッチはBGPリフレクタ、DHCP Relay、NTPサーバー、Webプロキシサーバーなどの多くの機能を持っていますが、複数のソフトウェアを組み合わせてそれらの機能を実現しています。
  3. ip linkコマンドでveth(Virtual Ethernet)を作成したり、iptablesの設定をおこなってネットワークの構成を模擬します。ネットワークの冗長化も実現しています。

この仮想データセンターに対して、自動テストを実行していくことになります。

テストシナリオ

仮想データセンターに対して、具体的にどのようなテストシナリオを流しているのか解説していきます。

まず、Boot Server上にnecoというツールをセットアップします。 このツールはBIOSやネットワークの設定、bird, chrony, serfなどのシステムソフトウェアのセットアップ、etcd, Vault, sabakan, CKEなどインフラ構築自動化ツール群のセットアップをおこないます。

sabakanは、我々が開発しているサーバーのプロビジョニングツールです。 各Compute Serverがsabakanに問い合わせてCoreOSでネットブートし、必要なシステムソフトウェアのセットアップをおこないます。

CKEも我々が開発しているツールで、Kubernetesクラスタの構築および運用を自動化しています。 CKEはsabakanがプロビジョニングしたCompute Server上にKubernetesクラスタを構築します。このときCNIプラグインやCoreDNSや各種ポリシーなど、Kubernetsクラスタの立ち上げに必要なアプリケーションのデプロイや設定をおこないます。 ここでKubernetesクラスタが正しく構築できていることをチェックします。

ここからサーバー故障、サーバー追加、OSや各種ソフトウェアのアップグレード、全台電源停止状態からの復旧などのテストをおこないます。 さらに、構築したKubernetesクラスタ上に継続的デリバリの仕組みを構築し、ロードバランサーや証明書自動発行、モニタリングなどのアプリケーションのデプロイや、アップグレードの動作確認を実施します。

このような一連のテストを1日に何回も実施しています。

テストサイズの定義

仮想データセンターを利用したテストの実施には現在のところ約1時間程度かかっています。 このテストにむやみにテストケースを増やしてしまうと、テスト時間はすぐに増大してしまいます。

そこで我々はテストピラミッドの考え方を取り入れてテストサイズを定義し、仮想データセンターを利用したテストが増大しないように注意しています。

Googleの事例では、Large Test, Middle test, Small Testのような分類がおこなわれています。 これに倣って我々は以下のようなテストの分類をおこないました。

Single-Host Test、Multi-Host Test、Data Center Testの図解

  • Data Center Test: データセンターを丸ごと仮想化し、本番と同じ構成で試験する
  • Multi-Host Test: 複数台のホスト上で複数のコンポーネントを組み合わせて試験する
  • Single-Host Test: 1台のホスト上で1つのコンポーネントの機能を試験する

上位のテストはシステム全体が正しく動くことを確認できるメリットがありますが、実行時間が長くメンテナンスコストも大きいため、できる限り小さく保つ必要があります。 下位の層のテストで網羅する範囲を増やし、どうしてもテストできない項目だけ上位の層でテストすることが望ましいとされています。 我々も、各ソフトウェアの機能は出来るだけ下位の層でテストをおこなうようにしています。

これまでに検出した不具合

テストの自動化により、これまでに数多くの不具合を検出することができています。 これまでに検出できた不具合の一例を以下に示します。 いずれももし本番発生していたらと思うとゾッとするような不具合ばかりです。

  • BGPで複数経路の設定をおこなった場合に、送信パケットの送り元IPアドレスがNICのIPアドレスではなく別のものになる問題
  • etcdの先頭のメンバーがクラッシュしたときに、etcdに接続できなくなる問題
  • サーバー再起動後にCNIプラグインのアップグレードをすると、アドレスプールが解放されてしまう問題
  • argo-cdのアップグレードによりアプリケーションの適用順序が変わり、デプロイに失敗する問題
  • CoreOSのアップデートによりrkt fetchが動かなくなる問題

テストしていないものは動かない

「データセンターすべての機能をテストすること」を方針として掲げていますが、現実には仮想化されたデータセンターではテストできない(しにくい)部分もあります。 しかしこれまでの経験上、テストできない(しにくい)からと言ってテストしていない機能は、本物のデータセンターで動かしたときにほぼ確実に問題が発生しました。

例えばBMCによる電源管理、Redfishによるハードウェアモニタリング、OMSAによるBIOSセットアップなどは仮想データセンターに含めていなかったため、それらを利用した機能を本物のデータセンターで構築したときに正しく動きませんでした。

これらの問題が発生した後は、BMCを模擬してサーバーの電源管理がおこなえるような仕組みを作ったり、モックサーバーを作って本物と同じようなレスポンスを返すようにしたり、出来るだけ本番環境と近くなるような仕組みをテストに組み入れています。 またCloud DNSやLet’s Encryptなどの外部サービスを利用している部分は、本物を使ってテストするようにしています。 このように、仮想データセンターと実際のデータセンターの差異を出来るだけ小さくしていくことが重要だと感じています。

まとめ

Kubernetesとそれに関連するOSSの進化はとても速いため、手動で試験をしていては更新に追いつけずあっという間にメンテナンスできない状態になりかねません。 すべての機能試験を自動化するのは大変で、我々の開発工数の半分近くはテストに費やしています。 しかし現実にKubernetes中心のシステムを運用し、維持発展させていくためには自動テストは不可欠です。 我々の取り組みがひとつの参考となれば幸いです。