IaaS基盤をテストする環境を作る話

# IaaS基盤をテストする環境を作る話
この記事は [富士通クラウドテクノロジーズ Advent Calendar 2017](https://qiita.com/advent-calendar/2017/fjct) の8日目です。

昨日は @YoshidaY さんの「[gRPCでApache Kafkaを使ってみる](https://qiita.com/YoshidaY/items/aa56b37dd39ff11c3ce0)」でした。メッセージングシステムにIDLと、マイクロサービスの要になりそうな話でしたね。今後どのように活用していくのか、期待しています。

## 前置き
新卒入社3年目の @ntoofu です。普段は弊社IaaSの仮想化基盤より上位レイヤーの面倒を見ています。（弊社のIaaS "ニフクラ" ではVMware製品を基盤に用いていますので、vCenter ServerやNSX等をよく扱います。）
本日のアドベントカレンダーは、「IaaS基盤をテストする環境を作る話」という題のもと、最近の業務で取り組んでいる、IaaS基盤運用にContinuous Integration (CI)を導入する活動の一貫で、テスト環境をどう用意するかについて書きました。まだしっかりとした成果が出ている段階ではないのですが、個人的に注力しており一度まとめて書きたかったので、この場を借りたいと思います。

## IaaS基盤運用でもCIがしたい！
私の担当している業務では、ネットワーク機器やサーバー周りを見ることは少なく、ハイパーバイザー以上の部分を中心に見ています。そのため、管理する対象にはAPIがあることも多かったので、私が入社するよりも前から運用作業や構築作業などの自動化が盛んに行われていました。

しかし、最近ではそういった自動化のプログラムそのものをどのように管理すべきかについて考えることが増えてきました。具体的には大きく以下のような課題があります。

* 手順については自動化できていても、実行そのものは人の手を介しているケースも多く、極力人の手を介さない状態を作り上げたい
* あるバージョンのソフトウェアを対象に作成されたプログラムが、ソフトウェアのバージョンアップに伴い正常に動作しなくなることがあり、事前に洗い出せるようにしたい
* 自動化のプログラムを作成した時のことを知らない人が、時には手直しをしていく必要があるので、簡単かつ安全に修正できるようにしたい

いずれも、達成のためにやるべきことはいくつかあるのですが、共通して重要だと感じるのが「プログラムの動作の安全性を担保すること」であり、そのためにはテスト、ひいてはCIの実践がカギになると考えています。

![IaaS基盤のCI](https://qiita-image-store.s3.amazonaws.com/0/148576/792a0c9d-c662-e0a7-1293-5e3aa22a8491.png)

## なぜ今できていないのか
ではなぜ現時点でIaaS基盤運用の中でCIを実践できていないのでしょうか。弊社のプロダクトの中には開発の中でCIを実践しているものもたくさんあるにもかかわらず、IaaS基盤運用に用いるプログラムは何が違うのでしょうか。

担当しているメンバーの違いによる意識や文化の差などもあるのかもしれませんが、より大きな課題となっているのが、テスト環境の準備が難しいという点だと思っています。

プログラムがある入力に対し期待したAPI等を発行しているかといったレベルでは、モックの利用などのよくある工夫をすればテストは可能です。しかし、結合テストまで視野を広げると、以下のような難しさが出てきます。

* 大抵の場合でESXiのようなハイパーバイザもテスト環境に必要になるため、普通のやり方では物理サーバー用意しないといけない
* テスト環境のデプロイに時間がかかりがち
	* API等の発行先がvCenter Serverのような巨大なコンポーネントであることが多い
	* テストしたいのが例えば監視に使うスクリプトであれば、Zabbixのような監視基盤との連携も気にしなければならないなど、どうしても関連するコンポーネントが多い

## テスト環境を用意するための工夫
こうした難しさを乗り越えるために、以下のような工夫を取り入れながら、テスト環境を楽に（自動で）作れるようにする取り組みをしています。

### nested ESXi の利用
ESXiは、物理サーバーにインストールし、仮想化された環境を提供するのが通常のユースケースです。しかしながら、所謂nested hypervisorという形で、ESXi上のVMに対しESXiをインストールし、更にその上にVMを立ち上げるということが可能です。[^1] [^2]

![nested_ESXi](https://qiita-image-store.s3.amazonaws.com/0/148576/f755a855-5eec-cd3b-c6d4-05e99467ccdc.png)

これにより、テスト対象のコンポーネントであるESXiをVMとして、より柔軟に扱うことができるようになります。

### vSAN, スナップショットの活用
テスト環境に用意する必要のあるコンポーネントは多く、大きいため、一からデプロイしていたのでは、テストの度に何十分も待たされかねません。

そこで、[vSAN](https://www.vmware.com/products/vsan.html)とスナップショット機能を上手く使います。vSANは、複数のESXiが持つローカルストレージを、仮想的に1つの共有ストレージとして扱うことのできる分散ストレージとして使う機能です。

![Virtual_SAN](https://qiita-image-store.s3.amazonaws.com/0/148576/6f56432f-f907-b229-a0f0-c7852cc62d43.png)

前述のnested ESXiについて、vSANを利用し、それらnested ESXi上のVMの実体をnested ESXiのローカルストレージに格納します。そうすることで、nested ESXi上のVMが外部のストレージを直接利用しないため、nested ESXiが外部ストレージをマウントする必要がなくなり、テスト環境の独立性を高めることに貢献できます。そして、nested ESXi上のVMの実体はnested ESXiのローカルストレージにまとまっているため、単純にnested ESXi VMをクローンすることでまとめて複製が可能となります。

次に、スナップショットは、仮想マシンに対し作成され、作成時点から仮想マシンのディスクへの書き込みが差分として保持されることで、スナップショット作成時点に後からロールバックできるようになる機能です。[^3]

![snapshot](https://qiita-image-store.s3.amazonaws.com/0/148576/e0c4dcdc-6de4-0c07-8588-b45602bb650b.png)

これを使うことで、一度テストを実行して変更が加えられた環境を、比較的短い時間で元のきれいな状態に戻すことができます。先ほどのvSANと組み合わせると、nested ESXiのローカルストレージは一つのvmdkファイルとして扱えているので、まるごとこのスナップショットを適用できます。したがって、テスト環境全体をスナップショットにより再初期化できるということになります。

### その他
その他にも、以下のような工夫を取り入れています。

![ネットワーク分離](https://qiita-image-store.s3.amazonaws.com/0/148576/77e1dc55-aad3-5229-a403-d73a8beeaeeb.png)

* ネットワークの分離
	* nested ESXi用VMを同じESXi上に配置し、uplinkを割り当てないvSwitchに接続することで、外部に影響を与えないネットワークを用意する
	* テスト環境内で自由にVLAN ID, IPアドレスなどの割り当てができ、同じテスト環境を複数作成した場合に、環境ごとにVLAN IDやIPアドレスを分ける必要もなくなる
	* 外部からの接続は、テスト環境用の分離されたネットワークと、外部ネットワークの両方に接続した踏み台用のサーバーを用意することで確保する
	* 踏み台用サーバー等においてテスト環境内部向けの権威DNSサーバーを動かすことで、ホスト名に関してもVLAN ID, IPアドレス同様に環境単位で管理できる
* vAppの利用
	* テスト環境内のVMを全てvApp[^4]としてまとめてしまえば、まるごとOVFエクスポートできるため、テスト環境のベースとなるvSphere環境を引っ越すこともできる

![GitLab_CI連携](https://qiita-image-store.s3.amazonaws.com/0/148576/352c13d6-168b-0790-87b8-9eb8e6e7e5fb.png)

* GitLab CIの活用
	* プロキシ環境下にも配置できるCI runnerを分離されたテスト環境用ネットワーク内に配置し、踏み台サーバーで動作させているプロキシ経由でGitLabに接続することで、分離されたネットワーク内にありながらテスト等を実行できる
	* 運用に使うプログラムに対しテストを用意し、分離されたテスト環境内でテストができる
	* テスト環境の再初期化を行うためには、nested ESXi VMを配置している、より下層のESXiを管理するvCenterを操作する必要があるので、そちらのvCenterと疎通できる箇所にもCI runnerを配置し、GitLabのAPIを用いてそちらで再初期化用のジョブを実行する

## 現在の実現状況
冒頭で述べた通り、まだ取り組んでいる途中のため、全てうまく行くと分かっているわけではありません。ですが、現時点でも以下の通り、実現できていること、改善が必要なこと、これから試さないといけないことが見えています。

### 実現できていること
* ネットワーク・ストレージが分離されたテスト環境の実現
* スナップショットのロールバックを利用した環境の初期化
* GitLab CIと連携して分離されたテスト環境でテスト実行するフロー

### 改善が必要なこと
* テスト環境の再初期化という単純なジョブの実行をGitLab CIの枠組みに押し付けたことで、GitLab CIの設定ファイルの複雑化を招いているため、より適切な方法に乗り換えたい

### これから試さないといけないこと
* nested ESXi上に多数のVMを作成して、多数のコンポーネントを含む環境を再現しても問題が出ないかどうか
	* ロールバックを利用した環境の初期化が実用上問題ない時間で利用可能か
	* 消費するリソースが想定範囲内に収まるか
* vAppによるテスト環境まるごとOVFエクスポート及びその移行

## 今後
IaaS基盤のテスト環境を用意する取り組みについて述べて来ましたが、この取り組みがうまく行ったとしても、まだまだやることは尽きません。

まず、今回説明した取り組みが仮に期待している通りに動いたとしても、作られるテスト環境は決して完全ではありません。以下のような物理機器への依存度の高いテストはこの枠組みでは実現できないという制約があるためです。

* vSANを利用しているため、物理ストレージに紐づくデータストアに関係するものはテストできない
* ESXi内で閉じるネットワークを利用しているため、下層の物理ネットワーク機器に関係するものはテストできない

当然、まずは今回説明した枠組みの実現も道半ばのため、その取り組みを優先しますが、更に物理よりのレイヤーもテストできるようにするということも同様に考えていかねばなりません。

また、取り組みの適用範囲を物理機器にも広げる必要があるという話の一方で、仮想基盤上で動く箇所に限定してでも、さらに枠組みを推し進めるということにも力を入れたいと思っています。具体的には、今回の取り組みの先に次のようなことを思い描いています。

* 構築や運用の自動化プログラムに対するテストを充実させ、CIを実現する
* 構築の自動化プログラムは、新しい環境の情報が登録された時点で自動実行され、人の手を煩わせずに環境がデプロイされる（Continuous Deliveryの実現）
* サービス停止を伴わないようなメンテナンスについては、手順をプログラムとして実装し、レビュー及びテスト環境での実行で問題が無いと確認されれば、ステージング環境、本番環境へ順次適用していく（Canary Releaseの実現）

全てを期待通りに実現することは難しいかもしれませんが、サービスの成長とともに運用の対象が増える中で、品質を保ちながらサービス継続するためには、こうした取り組みは不可欠だと考えています。

## 結び
今回は、IaaS基盤のテスト環境に関する取り組みを紹介し、実現していきたい未来についても少し書きました。何度か書いた通り、まだ途中の取り組みではあるので、また機会があれば状況を発信できればいいなと思います。

明日は、 @sato-mh さんが、Pythonに関するネタを書いてくれるそうです。本記事の話も、プログラムはほとんどPythonで書いているので、楽しみですね！

## 参考
[^1]: [How to Enable Nested ESXi & Other Hypervisors in vSphere 5.1](https://www.virtuallyghetto.com/2012/08/how-to-enable-nested-esxi-other.html)　(やや古いですが、nested ESXiを構築する時の設定について記されています)
[^2]: [How to properly clone a Nested ESXi VM?](https://www.virtuallyghetto.com/2013/12/how-to-properly-clone-nested-esxi-vm.html)　(こちらもやや古いですが、nested ESXiを使っているとよくハマるポイントを抑えていると思います)
[^3]: [スナップショットを使用した仮想マシンの管理](https://docs.vmware.com/jp/VMware-vSphere/6.5/com.vmware.vsphere.vm_admin.doc/GUID-CA948C69-7F58-4519-AEB1-739545EA94E5.html) (公式ドキュメント)
[^4]: [vSphere vApp を使用したマルチティア アプリケーションの管理](https://docs.vmware.com/jp/VMware-vSphere/6.5/com.vmware.vsphere.vm_admin.doc/GUID-E6E9D2A9-D358-4996-9BC7-F8D9D9645290.html) (公式ドキュメント)