メモのページ - チラシの裏メモ 3枚目

通信技術や気になった事を黙々とメモし続ける

MirageOS UnikernelでWebサーバ

前回は、Ubuntu Linuxの最新バージョン20.04にMirageOSをインストール、Hello Worldアプリの実行を成功させた。
Hello Worldアプリは立ち上げてHello Worldを自動で出力させるだけ。これで満足するするような自分ではない。もっと本格的なツール、例えばFTPサーバやWebサーバ等は無いか探したところ、チュートリアル的なDNSサーバやHTTPサーバ等がmirage-skeltonディレクトリ配下やGithubに有る事に気が付いた。
4連休全て天気予報は雨との事で外出の予定無し。時間はたっぷり有る。
...という事で、今回は簡易なWebサーバ「static website tls」の導入を試みた。
※前回:https://debslink.hatenadiary.jp/entry/20200718/1595076105



当方の環境
ホストOS:Windows7 32bit版 / RAM: 4GB / CPU: Intel Core i3-2350M 2.30GHz
ゲストOS:Ubuntu Server 20.04 x86 64bit版
Virtualbox 5.2.32
MirageOS 3.8.0
OCaml 4.10.0
Ubuntu Linuxは既にデプロイ済みである事とする。
PCのCPU仮想化支援機構はBIOSにて既に有効設定済みである事とする。
Ubuntu Linuxのカーネルやバージョンやインストール済みのツール等は、前回のHello Worldから変えていない。



MirageOSのインストール
MirageOSインストールの準備、opamの環境設定、MirageOSのインストールに関しては、以下のリンク先を参照。
https://debslink.hatenadiary.jp/entry/20200718/1595076105



下準備
前回ではopamおよびMirageOSのインストールの為に外部リポジトリの使用を試みたものの、Ubuntu 20.04用のディレクトリがまだ準備されていなかった為に、Ubuntuのリポジトリを使用しインストールした。
ところが外部リポジトリの設定の事はすっかり忘れ、消さずにそのまま残していた為にapt-getで導入済みのツールのアップデートが出来なかった。
よって、今回は外部リポジトリの削除から始めた。

$ sudo apt-get update
Hit:1 http://jp.archive.ubuntu.com/ubuntu focal InRelease
Get:2 http://jp.archive.ubuntu.com/ubuntu focal-updates InRelease [111 kB]
Get:3 http://jp.archive.ubuntu.com/ubuntu focal-backports InRelease [98.3 kB]
Get:4 http://jp.archive.ubuntu.com/ubuntu focal-security InRelease [107 kB]
Ign:5 http://ppa.launchpad.net/avsm/ppa/ubuntu focal InRelease
Err:6 http://ppa.launchpad.net/avsm/ppa/ubuntu focal Release
  404  Not Found [IP: 91.189.95.83 80]
Reading package lists... Done
E: The repository 'http://ppa.launchpad.net/avsm/ppa/ubuntu focal Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
$
$ sudo add-apt-repository --remove ppa:avsm/ppa
[sudo] password for hoge: 
 Latest stable versions of OCaml and OPAM.
 More info: https://launchpad.net/~avsm/+archive/ubuntu/ppa
Press [ENTER] to continue or Ctrl-c to cancel removing it.


apt-get updateおよびapt-get upgradeの次は、Ubuntu Linux側でtap0インタフェースの作成。Ubuntu LinuxとMirageOSとの間の通信にてtap0インタフェースが使用される為である。
Ubuntu Linux側では既に生成されているブリッジインタフェースvirbr0とWebサーバを同じネットワークに属させ、tap0インタフェース経由でWebサーバにアクセスさせる為。

$ sudo ip tuntap add tap0 mode tap
$ sudo ip link set dev tap0 up
$ sudo brctl addif virbr0 tap0


その後、Webサーバへのアクセス確認用として、テキストベースのWebブラウザLynxをインストール。

$ sudo apt-get install lynx
Reading package lists...
Done
libcrypt-dev is already the newest version (1:4.4.10-10ubuntu4).
libcrypt-dev set to manually installed.
The following additional packages will be installed:
  libzarith-ocaml lynx-common
The following NEW packages will be installed:
  libcryptokit-ocaml libssl-ocaml libzarith-ocaml lynx lynx-common
0 upgraded, 5 newly installed, 0 to remove and 23 not upgraded.
Need to get 1,842 kB of archives.
After this operation, 6,744 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y


mirageコマンドが実行出来るよう、eval $(opam env)を実行し環境変数を設定。

$ 
$ eval $(opam env)
$


ちなみに、MirageOSおよびOCamlのコンパイラのバージョンは以下のとおり。
前回のHello World完了後から変わらず、MirageOSのバージョンは3.8.0、OCamlのコンパイラのバージョンは4.10.0。

$ mirage --version
v3.8.0
$ 
$ opam switch list
#  switch   compiler          description
→  4.10.0   ocaml-base-compiler.4.10.0  4.10.0
   default  ocaml-system.4.08.1 default
$ 


Webサーバ static_website_tlsのインストール
下準備を終えたところで、Webサーバプログラム「static website tls」のコンパイルとインストールに進む。
前回同様、OCamlでWebサーバプログラムを1から書くのではなく、MirageOSの公式githubからホームディレクトリに持ち出す。
clone完了後、lsコマンドを打つとstatic_website_tlsディレクトリが作成されている事が確認出来る。
このstatic_website_tlsディレクトリ配下にディスパッチファイル(dispatch.ml)と構成ファイル(config.ml)が有り、この2つのファイルが保存されているディレクトリ内でインストール作業をする為、cdコマンドで移動する。

$ cd mirage-skeleton/applications/static_website_tls/
$
$ ls
config.ml  dispatch.ml  htdocs  tls
$


自分の環境では、前もってmirage-crypto-rng-mirageをインストールする。
実は、Webサーバの導入は成功するまで何度も何度も失敗。いづれもWebサーバの動作確認の際に、Webブラウザ上でテスト用HTMLファイル(Hello MirageOS World!)を表示させる事が出来なかった。
その際に吐かれたログは以下のとおりだった。

2020-07-26 08:02:11 +00:00: WRN [tcpip-stack-socket] error The default generator is not yet initialized.
To initialize the RNG with a default generator, and set up entropy collection and periodic reseeding as a background task, do the following:
  If you are using MirageOS, use the random device in config.ml: `let main = Mirage.foreign "Unikernel.Main" (random @-> job)`, and `let () = register "my_unikernel" [main $ default_random]`.
  If you are using Lwt, execute `Mirage_crypto_rng_lwt.initialize ()` at the beginning of your event loop (`Lwt_main.run`) execution.
  If you're using neither MirageOS nor lwt, there is no periodic reseeding. For an initial seed from getrandom(), execute `Mirage_crypto_rng_unix.initialize ()`. 
You can use `Mirage_crypto_rng.accumulate` and `Mirage_crypto_rng.reseed` to reseed the RNG manually. in callback


config.mlファイルに`let main = Mirage.foreign "Unikernel.Main" (random @-> job)`と`let () = register "my_unikernel" [main $ default_random]`を書けみたいな事を言っている為、何度もconfig.mlファイルに追記・修正・挙げ句の果てに上記2行だけのconfig.ml作成等をするも、事象に変化無し。
config.mlやdispatch.mlは諦めて、次に怪しいと思っていた箇所 RNG(random number generator)に着手。error The default generator is not yet initialized.と言っている為、RNG関連のパッケージがインストールされていないのであればインストールしてみよう...と言う事で、opam search rngで関係が有りそうなツールの検索とインストールの有無の確認結果、mirage-crypto-rng-mirageがヒットした。
未インストールとの事だった為、opam install mirage-crypto-rng-mirageでインストール。

$ opam install mirage-crypto-rng-mirage
The following actions will be performed:
  ? install eqaf                     0.7   [required by mirage-crypto]
  ? install mtime                    1.2.0 [required by mirage-crypto-rng]
  ? install mirage-crypto            0.8.1 [required by mirage-crypto-rng]
  ? install mirage-crypto-rng        0.8.1 [required by mirage-crypto-rng-mirage]
  ? install mirage-crypto-rng-mirage 0.8.1
===== ? 5 =====
Do you want to continue? [Y/n] Y
:
省略
:
? installed eqaf.0.7
? installed mirage-crypto.0.8.1
? installed mtime.1.2.0
? installed mirage-crypto-rng.0.8.1
? installed mirage-crypto-rng-mirage.0.8.1
Done.
$


mirage-crypto-rng-mirageのインストールは正常完了。ツールの追加インストールは想定外だったが、作業続行。
Virtioオプションを付けてmirage configureコマンドを叩き、コンパイルに必要なファイルを生成。
上記で作成したtup0インタフェースにIPアドレス192.168.122.100/24をアサイン。
GWの192.168.122.1は元から有ったブリッジインタフェースvirbr0にアサインされていたIPアドレス。
HTTPおよびHTTPSのポート番号はMirageOSのWebサーバのデフォルト値と同じにつき、ここで指定しなくとも正常に動作すると思われる。

引き続き、make dependコマンドを打ち、依存関係の有るopamツールおよびUbuntuのパッケージを自動でインストール。
Package mirage-unikernel-hello-virtio does not exist, create as a NEW package? [Y/n]
では yキーを叩いてopamツールのインストールを進める。

$  mirage configure -t virtio --ipv4=192.168.122.100/24 --ipv4-gateway=192.168.122.1 --http=8080 --https=4433
$
$ make depend
opam pin add -k path --no-action --yes mirage-unikernel-https-virtio . && opam depext --yes --update mirage-unikernel-https-virtio ; opam pin remove --no-action 

mirage-unikernel-https-virtio
Package mirage-unikernel-https-virtio does not exist, create as a NEW package? [Y/n] y
[mirage-unikernel-https-virtio.~dev] synchronised from file:///home/hechtia/mirage-skeleton/applications/static_website_tls
[WARNING] Failed checks on mirage-unikernel-https-virtio package definition from source at
          file:///home/hechtia/mirage-skeleton/applications/static_website_tls:
  warning 37: Missing field 'dev-repo'
  warning 49: The following URLs don't use version control but look like version control URLs:
              "https://github.com/mirage/mirage-skeleton.git#master"
mirage-unikernel-https-virtio is now pinned to file:///home/hechtia/mirage-skeleton/applications/static_website_tls (version ~dev)
# Detecting depexts using vars: arch=x86_64, os=linux, os-distribution=ubuntu, os-family=debian
:
省略
:
? installed mirage-crypto-pk.0.8.1
? installed x509.0.11.2
? installed tls.0.12.3
? installed tls-mirage.0.12.3
? installed conduit-mirage.2.2.1
? installed cohttp-mirage.2.5.3
Done.
$


最後にmakeコマンドを打ち、Hello Worldのアプリケーションバイナリファイルhttps.virtioを生成。staticファイルも生成される。
仮想マシンのバイナリファイルsolo5-virtio-runは前回のHello Worldの際に生成済みにつき、今回は生成されない。
完了後、lsコマンドの実行でhttps.virtioが当フォルダ内に有る事を確認。

$ make
mirage build
Generating static1.ml
Generating static1.mli
Generating static2.ml
Generating static2.mli
config.exe: [WARNING] pkg-config solo5-bindings-virtio --variable=ld returned nothing, using ld
$
$ ls
_build       dune         dune-project       https.virtio  Makefile                            static1.ml   static2.mli
config.ml    dune.build   htdocs             key_gen.ml    mirage-unikernel-https-virtio.opam  static1.mli  tls
dispatch.ml  dune.config  https_libvirt.xml  main.ml       myocamlbuild.ml                     static2.ml
$


今回のWebサーバ、static website tlsとMirageOSとSolo5の関係を簡単に表現すると、以下の図のような感じ。
当記事で触れている箇所を赤枠で示している。
OSの中にOSが有るのは変に見えるが、本来はXenなどHypervisor上で動作する。
MirageOSとWebサーバプログラムは1対1で動作する。よってDNSサーバプログラムや他のプログラムをMirageOS上で動作させたい場合は、プログラムを動作させる為のMirageOSが1つづつ必要となる。




Webサーバプログラムの実行
Webサーバプログラム、static website tlsの実行まで辿り着いた。Webサーバの起動後、LynxというテキストベースのWebブラウザで動作確認。
仮想マシンバイナリファイルsolo5-virtio-runでアプリケーションバイナリhttp.virtioを実行させる。
Webブラウザ上で「Hello Mirage World!」が表示されれば、Webブラウザプログラムの生成とHTTP/HTTPSアクセスは成功となる。

$ sudo /home/hechtia/.opam/4.10.0/bin/solo5-virtio-run -n tap0 https.virtio
+ exec qemu-system-x86_64 -cpu Westmere -m 128 -nodefaults -no-acpi -display none -serial stdio -device virtio-net,netdev=n0 -netdev 

tap,id=n0,ifname=tap0,script=no,downscript=no -device isa-debug-exit -kernel /home/hechtia/mirage-skeleton/applications/static_website_tls/https.virtio
            |      ___|
  __|  _ /  |  _ / __ /
/__ / (   | | (   |  ) |
____//___/ _|/___/____/
Solo5: Bindings version v0.6.5
Solo5: Memory map: 128 MB addressable:
Solo5:   reserved @ (0x0 - 0xfffff)
Solo5:       text @ (0x100000 - 0x419fff)
Solo5:     rodata @ (0x41a000 - 0x4a5fff)
Solo5:       data @ (0x4a6000 - 0x6d3fff)
Solo5:       heap >= 0x6d4000 < stack < 0x8000000
Solo5: Clock source: TSC, frequency estimate is 2296908200 Hz
Solo5: PCI:00:02: virtio-net device, base=0xc000, irq=10
Solo5: PCI:00:02: configured, mac=52:54:00:12:34:56, features=0x79bfffe7
Solo5: Application acquired 'service' as network device
2020-07-26 08:54:12 -00:00: INF [netif] Plugging into service with mac 52:54:00:12:34:56 mtu 1500
2020-07-26 08:54:12 -00:00: INF [ethernet] Connected Ethernet interface 52:54:00:12:34:56
2020-07-26 08:54:12 -00:00: INF [ARP] Sending gratuitous ARP for 192.168.122.100 (52:54:00:12:34:56)
2020-07-26 08:54:12 -00:00: INF [udp] UDP interface connected on 192.168.122.100
2020-07-26 08:54:12 -00:00: INF [tcpip-stack-direct] stack assembled: mac=52:54:00:12:34:56,ip=192.168.122.100
2020-07-26 08:54:12 -00:00: INF [https] listening on 4433/TCP
2020-07-26 08:54:12 -00:00: INF [http] listening on 8080/TCP


コマンドsudo /home/hechtia/.opam/4.10.0/bin/solo5-virtio-run -n tap0 https.virtioの実行後、Webサーバのログが出力される。
[https] listening on 4433/TCPと[http] listening on 8080/TCPで停止し、リスニングの状態になりWebブラウザからのアクセスを待つ。
出力内容から分かるとおり、このWebサーバではHTTPとHTTPSの両方が立ち上がっているが、外部からのアクセスはHTTPで受け、Webサーバ内部でHTTPSに渡されるという仕組みになっている。

ここでTera Termなどターミナルツールをもう1枚立ち上げMirageOSを立ち上げているVirtualboxゲストOS(ここではUbuntu Linux)にログインし、LynxでWebブラウザにアクセスを試みると...

$
$ lynx http://192.168.122.100:8080

下の画像内に表示されているとおり、「Hello MirageOS World!」の表示に成功。
ここに辿り着くまで、長かった......



WebブラウザLynxでアクセスした際のログは、以下のとおり。
HTTPからHTTPSに渡される様子とSSLハンドシェイクの簡易なログが出力されている。

2020-07-26 08:54:34 -00:00: INF [https] [1] serving //192.168.122.100:8080/.
2020-07-26 08:54:34 -00:00: INF [http] [//192.168.122.100:8080/] -> [https://192.168.122.100:4433/]
2020-07-26 08:54:34 -00:00: INF [https] [1] closing
2020-07-26 08:54:36 -00:00: INF [handshake] cipher AES_128_GCM_SHA256
2020-07-26 08:54:36 -00:00: INF [handshake] group X25519
2020-07-26 08:54:47 -00:00: INF [https] [2] serving //192.168.122.100:4433/.
2020-07-26 08:54:47 -00:00: INF [https] [2] closing


今回の振り返り。VirtualboxのゲストOS内の話ではあるが、Tutorial用プログラムのWebサーバ「static_website_tls」の実行と、HTTP/HTTPSアクセスおよびWebブラウザLynxでHello MirageOS World!の表示に成功した。
外部からのアクセスも可能のようだが、その際は自己証明書ではなく信頼出来る認証局のサーバ証明書が必要となる。
海外のブログにLet's Encryptでの事例が有り(https://www.davidudelson.com/blog/2017/06/13/aws-unikernel-guide/)、自分も試してみたものの今のところ成功していない。



リンク先
https://mirage.io/ Mirage OS
https://github.com/mirage Mirage OS (github)
https://ocaml.org/ OCaml
https://releases.ubuntu.com/20.04/ Ubuntu 20.04
https://github.com/Solo5/solo5 Solo5
https://lynx.invisible-island.net/lynx.html Lynx


Mirage、OCaml、他各ツールの最新バージョンは以下のリンク先で検索し確認可能。
画面右上の「Search Packages」の窓内にパッケージ名を入力し検索。
https://opam.ocaml.org/packages/


他のMirageOSのエントリ
https://debslink.hatenadiary.jp/entry/20200815/1597493701 追記:MirageOS Unikernelでデータベース
https://debslink.hatenadiary.jp/entry/20200718/1595076105 前回:Ubuntu 20.04でMirageOS Unikernel
https://debslink.hatenadiary.jp/entry/20200526/1590495778 前々回:MirageOS Unikernelで通信プログラムの実行
https://debslink.hatenadiary.jp/entry/20200516/1589616362 初回:MirageOSのインストールとHello Worldの実行


自分にとって、UnikernelsやMirageOSの始めの一歩となったサイト (MirageOS のインストールから Hello World までを試す)
https://qiita.com/t-imada/items/6ee299653ac063532b4f