virshの学科ラッパーie-virshをRustで再実装した

これは琉大 Advent Calendar 2020の5日目の記事です。

昨日は未承諾広告※ shangliさんのクラスター計算機を作るときに気をつけたいことでした。

まだまだ琉大アドベントカレンダーは空きがあるので皆さんの参加お待ちしております!!!

学科システム

さて僕たちの学科(琉大情報工・知能情報コース・情報工学専攻)では独自にオンプレ上に構築した学科システムを持っています。学科システムのサーバーの管理はシステム管理チームと呼ばれる学生たちが、自分達自身で行うという方向性です。

現在の学科システムはubuntuベースのサーバーが4台、ファイルサーバーが2台、さくらの専用サーバーが1台という構成になっていて、ubuntuベースの演習用サーバー2つは学生に広く開放しています。

この学科システムでは2015年まではVMWare, 2015年以降はKVMを運用しており、学科サービスや学生演習用・学生が個人で開発するようでVMを動作させることが可能となっています。

KVMの学生ごとの管理

例えばOSの講義では学生がそれぞれVirtualBoxで作成したFedoraVMイメージを、学科システムにrsyncし、KVMとして動作させる課題が存在します。

学生にはそれぞれKVMの操作コマンドであるvirshの操作権限は与えていますが、いくつか問題点がありました。

  • virsh defineXMLを書くのがめんどい
  • virsh installが複雑
  • 人のVMを間違って消してしまう可能性がある
  • VNCパスワードを生成するのがめんどう
  • qcow2の置き場所は作って欲しい

これらを解決するために、以前の学科システムではie-virshというコマンドが存在していました。 これはvirshコマンドのラッパーで、以下の事が可能なコマンドです。

  • ie-virsh define 01でテンプレートXMLをもとにVMを構成
  • qcow2の置き場所も生成
  • ie-virsh start 01username-01というVMを起動できる
  • ie-virsh listvirsh list --all | grep $usernameと同じ挙動をする
  • ie-virsh destroy 01VMを終了できる
  • ie-virsh dumpxml 01XMLを確認できる

以前のシステムではこのie-virshを利用することで、5個のVMを作成することができ、かつ起動することが出来ていました。このラッパーは他のユーザーのVMは操作できないので安全でもあります。

貸し出しVMサービス

さらにシステム管理チームでは、あらかじめユーザー設定などをすませたVMのテンプレートイメージをもとに、ユーザーの希望に応じてVMを作成する貸し出しVMサービスがありました。

今まではRubyonRailsで実装されたAkatsukiというweb アプリケーション経由で行っていました。

attonblog.blogspot.com

(なおAkatsukiはシステム移行に伴って, Apache + Passengerから Nginx + Dockerで rails sに切り替えています)

Akatsukiでだいぶ問題はなかったのですが、VM操作にfog-libvirtを使っているため、テンプレートVMからのコピー時に、VMの差分イメージではなくVMイメージのフルコピーが使われてしまいます。

そのため差分イメージ(backing file)を使うにはRailsアプリケーション側の大規模な修正が必要そうでした。残念ながら現状のシス管メンバーはそこまでRailsの戦力に強いメンバーが揃っているわけではないので、CLIとして実装したいという気持ちになっていました。

ie-virshの再実装

そこでAkatsukiのVM作成的な機能をie-virshに組み込むぞ!!という気持ちになります。

今まで動いていたie-virshの実装はC + Python2という構成であり、python2を現代のサーバーで動かしたくはないので、python3へのリライトが迫られていました。

ie-virshのリポジトリ

上記のAkatsukiの機能を c + python3で組み込むのはなかなか手がかかりそうですし、せっかくなので別言語で書き直そうという機運がid:anatofuzの中で高まります。

そこでCに近い言語として興味があったRustを選択し、実装を行いました。

このあたりは作業の副産物です。 anatofuz.hatenablog.com

anatofuz.hatenablog.com

Rustで書いたie-virsh

実際に実装した結果がこれです

gitlab.ie.u-ryukyu.ac.jp

使い勝手

従来のシステムはヘルプがなかったですが、なんとhelp付きです

$ie-virsh
ie-virsh 0.1.2
AnaTofuZ <anatofuz@cr.ie.u-ryukyu.ac.jp>

USAGE:
    ie-virsh <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    console       connect to the guest console
    define        define (but don't start) a domain from an template XML file
    define-gdb    define the domain in which the gdb port is opened from the template XML file
    destroy       destroy (stop) a domain
    domiflist     list all domain virtual interfaces
    dominfo       domain information
    dumpxml       domain information in XML
    edit          edit XML configuration for a domain
    help          Prints this message or the help of the given subcommand(s)
    list          list domains
    shutdown      gracefully shutdown a domain
    start         start a (previously defined) inactive domain
    templates     show templates vm
    ttyconsole    tty console
    undefine      undefine a domain
    vncdisplay    vncdisplay

かなりのコマンドをサポートしており、今まではdestroyしかできませんでしたが、shutdownも出来るようになってます。

list

自分が作ったVMの状況が確認可能です

$ie-virsh list
uid: 11464 gid: 1001 name: k198584
 Id   Name                            State
------------------------------------------------
 -    k198584(anatofu-prome.cr)       shut off
 -    k198584-centos                  shut off
 -    k198584-centos2                 shut off
 -    k198584-u20                     shut off
 -    k198584-ubuntu18                shut off

define

  • テンプレートxmlをもとにvmをdefineします
    • 名前はなんでも良いですが、prefixにlogin user nameが入る仕様です
    • 例えば e155730 が ie-virsh define anatofuz とすると e155730-anatofuzというVMが作られます

start, dumpxmlなど

  • vm名を指定する必要がありますが、wrapperなので全部打つ必要がないようにしています
    • e155730-anatofuz の場合は ie-virsh start anatofuz でOKです
  • vm名をフルで打っても問題ないです
  • 起動しているvmに対しての操作はidを指定しても問題ないようになっています

テンプレートVMをもとに差分で生成する

ie-virsh templatesとすると、対応しているテンプレート一覧が出ます

$ie-virsh templates
uid: 11464 gid: 1001 name: k198584
CentOS-7
CentOS-8
Debian-10
Debian-8
Fedore-25
Ubuntu-16
Ubuntu-18
Ubuntu-20

そしてこれをdefineのときに-tオプションで指定すると、VMが差分で生成されます!

+amane+k198584 ie-virsh define dondoko -t Ubuntu-20
uid: 11464 gid: 1001 name: k198584
k198584-dondoko
generate xml : /etc/libvirt/qemu/k19/k198584/k198584-dondoko.xml
vnc password : DQCyWV2YQ$w(!B#(M0#8jcWO%hnqOj
Formatting 'k198584-dondoko.qcow2', fmt=qcow2 size=10737418240 backing_file=/ie-ryukyu/kvm/images/templates/template-Ubuntu-20.qcow2 backing_fmt=qcow2 cluster_size=65536 lazy_refcounts=off refcount_bits=16
Domain k198584-dondoko defined from /etc/libvirt/qemu/k19/k198584/k198584-dondoko.xml

実際に確認をしてみます

$ie-virsh list
uid: 11464 gid: 1001 name: k198584
 Id   Name                            State
------------------------------------------------
 -    k198584(anatofu-prome.cr)       shut off
 -    k198584-centos                  shut off
 -    k198584-centos2                 shut off
 -    k198584-dondoko                 shut off
 -    k198584-u20                     shut off
 -    k198584-ubuntu18                shut off

無事作成されていますね!!!(ちなみにこのあと学科内では、VMDHCP対象にするためにmacアドレスを登録する必要があります...)

実装について

Rustで最初に書いた本格的なプログラムなので、かなり汚いと思いますが、練習になりましたし何より書いてて楽しかったですね。

CLIの実装はclapを使っています。 なんとなくenumでサブコマンドをパターンマッチしたかったのですが、deriveを使う以外のやり方が解らず、無駄に構造体を量産してしまっています。やり方教えてほしい。

execやseuidのようなUNIXAPIを叩く必要があり、これにはnixが便利でした。とはいえnixはlibcのラッパーっぽいので、はじめからlibcを叩けばよかったのかもしれません。

実装したいはvscodeのremote edit機能を使って、サーバーに直接sshして書いていました。もともとローカルなmacOSでやっていましたが、linux用のバイナリを吐くためにdockerを起動するのがしんどくなってしまい、直接linuxのバイナリを吐きつつ編集できる方法が欲しかったので、vscode最高!!!みたいになっていました。

というわけで新しいie-virshの紹介でした。みんな使ってみてください。あとプルリクお待ちしております。

明日はxxxxさんです。