Docker for Windows betaを試す (Hyper-V enabled)

※WordPressが不調でレイアウトがものすごく酷い事になってます。そのうち直します。

docker今更説明不要だと思いますが、Docker。そのDockerの標準提供されている動作環境の一つに「Docker for Windows」があります。

Docker for Windowsは、Dockerの実行環境をWindows上で実現する、手軽なパッケージです。但し、現状のDocker for Windowsは「Virtual Box」を使って実現しているため、Hyper-Vを使用する環境では使えません(Hyper-Vを無効にする必要がある)。

※正確には、Docker for Windowsに含まれる「Docker Engine」がVirtualBoxを必要としています。Docker clientは単独で動作します。

現在新たに開発中のバージョンでは、仮想マシンをVirtualBoxではなくHyper-V上で実現させることが出来るようになっていて、非常に操作性に優れています。このベータ版は、Dockerのベータプログラムに申し込んだユーザーに順次配布されているようで、先日私のところにもやってきたので早速試してみました。

Dockerをサクッと試してみたいという方も、これで始められると思います。


ベータプログラム

ベータプログラムは以下から申し込めます。

Explore a new kind of Docker – Docker early access

いつ配布されるのかは良くわかりません。私もWindows Subsystem for Linuxにかまけてすっかり忘れていました。


インストール

dockerbeta1確かめていませんが、古いDocker for Windowsはアンインストールしておいた方が良いでしょう。

ベータプログラムの順がやってくると、メールで案内が来ます。メール文中にDocker for Windowsのベータ版へのリンクと、アクセスキーが含まれているので、それぞれ保存しておきます。

dockerbeta2ダウンロードしたmsiを実行します。インストールは非常に簡単ですが、Hyper-Vを構成している場合は、デフォルトの構成ファイルと仮想イメージの配置フォルダにDocker Engineが配置されるので、必要であればあらかじめ配置されるフォルダを変更しておくことをお勧めします。

dockerbeta3インストールされると、デスクトップにこのようなアイコンが配置されます。

dockerbeta4起動すると、初回はこのようなダイアログが表示されます。ベータプログラムのキーを入力して開始します。

dockerbeta5すると、タスクトレイにこのようなクジラのアイコンが表示されます。

いくつかの環境で試したのですが、一台だけHyper-Vの仮想スイッチの構成がうまくいかず、「DockerNAT」仮想スイッチが外部ネットワークに接続されていないケースがありました。もし起動時に通信できない事があった場合は、Hyper-Vマネージャの仮想スイッチの構成を確認してみて下さい。

私の環境では、他に仮想スイッチがあった場合に、一旦それらを削除しておいて実行したところ、正常に動作しました。例えば、Visual StudioでWindows Phoneエミュレーターを起動した場合に、自動的に仮想スイッチが構成されるので、これを削除しておきます(DockerNATが作られた後で、手動で戻す)。

Dockerチームはbeta8でこの事を認識しているので、いずれ修正されるでしょう。

“Error response from daemon: dial tcp 10.0.75.2:2375: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond”


Docker EngineがHyper-Vで起動

dockerbeta6これを待ち望んだ人もいるかと思います。ちゃんとHyper-Vの仮想マシンの一員として動作しています。Docker Engineの仮想マシンには「MobyLinuxVM」という名前が付けられており、シャットダウンも普通に可能です。なので一旦シャットダウンし、CPUやメモリ構成を変更することが可能です(どの程度保証されているのかはわかりません)。私は再起動時に前回の状態に復元(起動していれば起動する)するようにしました。

なお、仮想マシンのコンソールには「何も」表示されません。文字通り何も表示されず、Hyper-Vのロゴが表示されたままになっています。これはこの仮想マシンがDockerで必要な最小限のリソースしか使わないように最適化されているからと思われます。なので、基本的に仮想マシンのコンソールを操作することはありません。

dockerbeta7その代わり、タスクトレイのアイコンを右クリックするとコンテキストメニューが表示され、ここで幾つかの操作を行うことが出来ます(但し、興味深い何かはありませんでした)。

  • Docker Engineが起動したかどうかの基本的な確認は「Logs…」で確認できます。
  • 「Dashboard…」は、もっかのところ「Kitematicダウンロードしてね」と表示されるだけです。Kitematicはこの表示で初めて知りました。細かいところはググってみて下さい。使いやすいGUIインターフェイスです。

Hello Docker on Windows/Hyper-V

dockerbeta9ということで、これでもう動いています。また、Docker Client CLIもReadyなので、すぐに使い始めることが出来ます。とりあえず、Docker初めての方向けの手引きです。普通にコマンドラインを開きます。CLIはパスが通っているので、cmd.exe直実行でもOKです。

これですよこれ、この手軽さが欲しかった!

では、DockerでUbuntuコンテナを実行し、bashを操作してみます。

C:\> docker run -i -t ubuntu /bin/bash

これは、DockerHubからubuntuの最新Dockerイメージをダウンロードしてきて、Docker Engine内(つまりHyper-V)で実行して、/bin/bashを実行します。「-i -t」はbashの標準入出力をWindowsのコマンドプロンプトに結合して、直接操作可能にするという意味です。

初回はイメージのダウンロードに時間がかかるかもしれません。成功するとこのようにbashのプロンプトが(コマンドプロンプトに)表示され、普通に操作できます。Welcome Docker!!

dockerbeta10ここでexitでシェルを抜けるとコマンドプロンプトに戻りますが、これでDocker Engine内のubuntuインスタンスは綺麗さっぱり消えています(ダウンロードしたイメージだけキャッシュされている)。もう一度起動すると、今度はほぼ一瞬で起動するはずです。

これがDockerの利点で、後片付けが不要なので、ちょっと何か試すとかの用途には非常に便利です。もちろん、本来のDockerの強みである、DockerFileを定義したコンテナの作成と利用も当然可能です。「ディスポーザブルインフラストラクチャー」として、気軽に使ってみてください。

continuatioN Linking – NL名古屋

「continuatioN Linking」という題目で、NL名古屋で登壇してきました。

NとLの字さえ使っていれば何でも良いというカオスなショートセッション会なのですが、内容は非常に濃くて面白いものばかりでした。とても満足度が高かったです。Togetterのまとめはこちら

今回写真撮り忘れてしまったのでありませんが、50名超えと大入りな感じでした。


継続ネタ

継続渡しスタイル(Continuation Passing Style)の話に絡めて、.NET TaskとF# Asyncのシームレスな相互運用を行うネタを発表してきました。

何しろここは名古屋 (;´Д`) なので、このネタで行くにはまだ「ひよっこ」で恐怖しかない感じでしたが、掴みもスベる事なく発表できたのでうれしかったです。一部の方には触れるものがあったようで、「おおーー!!」という声はやって良かった感ありました。

発表はショートセッションですが参加者が多いこともあり、最終的に時間制約が10分となって苦しいところでしたが、予定通り進行を無視して「継続」させていただきましたありがとうございます。


補足

さて、内容は駆け足だったので少し補足しておきます。

FSharp.Control.FusionTasks.128GitHub: kekyo/FSharp.Control.FusionTasks
NuGet (F# 2.0): FSharp.Control.FusionTasks.FS20
NuGet (F# 3.0): FSharp.Control.FusionTasks.FS30
NuGet (F# 3.1): FSharp.Control.FusionTasks.FS31
NuGet (F# 4.0): FSharp.Control.FusionTasks.FS40

検討

アイデアはすぐに思いついたものの、実現可能かどうかが良くわかりませんでした。そもそも素人の浅はかで、.NET TaskクラスとF# Asyncクラスは似ているな、もしかしたら簡単に相互運用できるかも?と思ったのがきっかけです。

  • わざわざ似ているものが併存している事に何か特別な理由があるのかと思っていましたが、実はF# AsyncのほうがTaskよりも歴史が古く、CLR 4.0の形も無いころから既に非同期ワークフローがサポートされていました(.NET 2.0から実現している)。だからこの疑問は不適切で、.NET TaskはF#に依存しないように改めて設計しなおしたのだと思われます。
  • F#非同期ワークフローは、AsyncBuilderクラスを使用する、一種の構文糖(computation式)だと理解しています。F#の場合、任意の型に(インスタンスであろうとスタティックであろうと)拡張メンバー(C#で言う所の拡張メソッド)を生やす事ができるため、AsyncBuilderに.NET Taskを扱うメンバーを増やすことで、非同期ワークフローでシームレスに.NET Taskを扱えるのではないかと考えました。
  • 一番大きな動機は、HttpClientなどのネイティブ非同期対応ライブラリを、そのままF# Asyncで使うことが面倒であったということがあります。F#にも標準で.NET Taskのためのサポートはあります。「Async.AwaitTask関数」がそれですが、この関数は見ての通りT型が特定されなければならず、非ジェネリックTaskをAsync<unit>に変換できません。また、逆の変換(AsyncからTask)への変換方法もありません。逆の変換ができると、F#で書いた非同期ワークフローのインスタンスを、C#側でawait出来るようになるため、さらに応用性が広がります。

※ computation式については、「詳説コンピュテーション式」が詳しいです。

非同期コンテキストの結合

.NET非同期処理(async-await)と例外の制御 で持ち出した「タスクコンテキスト」という用語なのですが、もはや統合されたこの世界では「非同期コンテキスト」としか言いようがないですね。

「非同期コンテキスト」をシームレスに結合した場合、維持されなければならない重要なポイントがあります。それは、「同期コンテキスト(SynchronizationContext)」「キャンセルトークン(CancellationToken)」です。うーん、コンテキスト紛らわしい (*´Д`)

.NET Task側の事はある程度わかっているのですが、F#非同期ワークフローではこれがどのように維持されるのかがわからず、シームレスな相互運用が実現するにはココの担保が不可欠だと考えていました。

fsugjpの方々とやりとりしたり(あまりまとまりは無いです)、MSDNを調べたりして、以下の事がわかりました (Thx fsugjp!!)

  • F#にはAsync.FromContinuations<T>関数があり、これを使うとコールバック関数を経由してAsyncクラスの結果を制御できます。これは丁度TaskCompletionSource<T>クラスを使ってTaskを間接的に操作することに相当するので、Taskの結果を反映させることに使えます。
    余談ですが、初見ではあの引き数で何ができるのか、さっぱりわかりませんでした(つまりビギナー認定w)
  • 「Continuations」という単語の響きに導かれ、逆のパターンにはAsync.StartWithContinuations<T>関数を使えばよいことがわかりました。こっちはもっと単純で、正常・異常・キャンセルの継続処理をCPS形式で渡すだけです。

同期コンテキスト自体は、Asyncクラス内で非同期待期に使用しているので、F#非同期ワークフローで使う限り特に問題なさそうです。Task.ConfigureAwaitメソッドに相当する同期コンテキストのキャプチャ制御についてはむしろF#の方が柔軟性があり、Async.SwitchToContextAsync.SwitchToThreadPoolAsync.SwitchToNewThread関数を使用して、いかようにでも同期コンテキストを操ることができます。

そしてキャンセルトークンの方ですが、F#側はAsyncクラスのインスタンスを何らかの方法で実行するときにトークンを保持し、それがAsyncクラスの非同期コンテキストの情報として保持されて使われます。簡単に言うと:

// 非同期ワークフロー内で非同期スリープ(Task.Delayと概念は同じ)
let asyncBody = async {
  // (トークンはこの非同期ワークフローのコンテキストに暗黙に伝搬している)
  do! Async.Sleep(10000)
}

// キャンセルトークンを準備
let cts = new CancellationTokenSource()

// 非同期ワークフローをキャンセルトークンありで同期実行する
Async.RunSynchronously(asyncBody, Timeout.Infinite, cts.Token)

※ 注意: RunSynchronouslyは説明のために使用しています。本当は使わないように書くべきです。Task.Waitに相当します。

上記のような状態でSleepしているときにトークンがシグナル状態となると、正しくSleepが中断されます。Task.Delayの場合はキャンセルトークンを受け取るオーバーロードを使用していないと中断できませんが、F#非同期ワークフローの場合は、現在の非同期コンテキストに伝搬するトークンが管理され、Async.Sleepはそれを監視しているので正しく中断されるのです。

伝搬の手法は魔術的な何かでもなんでもなく、RunSynchronouslyで渡されたトークンがAsync.CancellationToken プロパティで管理されていて、Async.Sleepはこれを参照しているからです。実際、Task.Delayと異なり、Async.Sleepにはトークンを明示的に指定するオーバーロードはありません。

作ってみた感想

この部分、私的にはとても良くできていると思いました。というのも、F#非同期ワークフローの「非同期処理」に関する範囲と制約は、すべてワークフロー(computation式)内に閉じているからです。キャンセルトークンの管理もここで閉じているので、操作する側はAsyncクラスのインスタンス=非同期コンテキストと言うように、はっきりとイメージ出来ます。

対照的に.NET TaskとC# async-awaitではこれが曖昧で、ビギナーにasync-awaitの事を説明するためには、どこからが非同期コンテキストなのかをしつこいほどに解説する必要がありました。また、デフォルトではキャンセルに対する操作は完全に使用者任せとなり、Task.Delayのようにトークンを引き渡すシグネチャを明示的に設計に盛り込む必要があります。私はこのことに気が付くのが遅かったために、フレームワークインターフェイスの変更という大手術を行う羽目になったことがあります。そして、たとえ周到に準備しても、使用者がトークンを渡すのを忘れると台無しとなり、トークンをどこで管理するのかということも(使用者が)考える必要があります。

物事にはトレードオフがあるはずで、.NET Taskとasync-awaitが後発でありながらこういう選択をした理由も恐らくあるのでしょう。想像出来ることと言えば、async-await方式は、メソッド内のコードに「await」という単語が入るだけで、それ以上の大幅な変化がないと言うことです。しかし、実用的な非同期コードをasync-awaitで書いたことがある方ならわかると思いますが、現実には非同期であることを意識したコードを書かないと、pitfallに落とされます(一例を例外の記事でも書きました)。

F#非同期ワークフローでは、「async」に囲まれたcomputation式内でしか使えず、computation式では「let!」「do!」などの普通には使わない予約語を使う必要があります。ただ、上で述べたような問題とのトレードオフとしては悪くない選択だなと思います。説明も簡単なのが大きいですね。

そして、一番最初の「もしかしたら簡単に相互運用できるかも?」というのは、「それなりにイケた」という感じですが、やってみた後の感想としては、.NET TaskとF# Asyncクラスはそれぞれ役割もインターフェイスも似ているにも関わらず、現実には設計思想からして全く違うものだという印象が強くなりました。

後は、現在進行中のもう一つのプロジェクトと合わせて、何とかF#のコードが書けるようになったと言うことかな。人に説明するにはまだいろいろ足りてない感じですが、F#や関数型言語の面白さの一端は見えてきました。

それではまた。

PCいぢりメモ

訳あってPCの構成を変更する必要が生じたので、メモ。

CPUが一世代前なので、今更これを一から作るという人はいないと思うのですが、多分、この構成でやってる人はあまりいないと思うので、役に立つかも。気になるであろう部分を写真多めに盛っておきます。

構成

※Amazonでリンク張ってるので気になる方は直接ググって下さい

この構成の難しいところは、Mini-ITXなのでケース容積が非常に小さいところにハイエンドパーツを埋めているところです。ちっちゃいPC好きなので、どうしてもこういう無理ゲーな構成をやってしまう…

事の発端

朝電源を入れたらコレ。まぁ、SSDは壊れていなさそうと言うことと、前日Windows Updateで新たなIPが降ってきてた事もあり、それが直接の原因かも。ただ、折角(?)ブートしなくなってしまったので、とある問題の解決も含めて構成変更しようかと思いました。

というのも、SSD 2発をIntel RAID 0で構成してあったんですが、どうも感触が良くない。このSSD、体感かなり良いはずなのに、RAID 0構成してからあまり「速い」という印象もなく、なんだか勿体ないなと思ってました。それならRAID 0をやめて別のマシンにSSDを1台持って行ったほうが良いじゃないかと。

とはいえ、480GBだけでは心もとないので何か追加したい。それなら噂のNVMeに行くかと。しかしNVMeするならマザーボードも変えたほうが良く、この時点できちんとケースに収まるかかなり不安に…

最大の問題はクーラーで、現状のSAMUEL 17が新しいマザーに付くかどうか。念のため Cooler Master 風神スリム も手配。これは同じマザーのレビューで使われていたのが理由ですが、結局ダメでした(後述)。

マザーボード構築 (1)

WP_20160408_15_18_37_Proマザーボードだけさっくり置き換えるという訳にはいかず、一旦すべてのパーツをケースから外し、ケーブリングからやり直す事に。Mini-ITXの難しさの一つでもあるかな。で、取り出したマザーからCPUとメモリを外し、新しいマザーに移植したところ。

WP_20160408_15_19_01_Pro写っているヒートシンクはSAMUEL 17で、この時点で風神スリムは付かないことが判明。理由はメモリのヒートシンク高が高いこと。このマザーの特徴的なVRMの高さはぎりぎり収まるものの、メモリは完全にアウトでした。これは高さの様子です。

WP_20160408_15_19_21_Pro

WP_20160408_15_20_09_Proこういうことが買う前にわかる、良い施策無いかなーと思います。今はPCパーツショップがレポートとか書いてくれることが下支えになってると思うのですが、エッジの効いた構成だと事例がない…

WP_20160408_15_20_39_Proで、SAMUEL 17はちょっと変わったフットプリントなんですが、このヒートシンクは未来を予見しすぎているのか、買ってからずっと乗り換えで使えてるんですよね。今回もまさかこんなにフィットするとは思っていなかった。

WP_20160408_15_20_51_Proこれが….

WP_20160408_15_21_46_Proこう付きます。

WP_20160408_15_21_54_Pro

WP_20160408_15_22_30_Pro

WP_20160408_15_22_44_Pro

WP_20160408_15_23_01_Proもう、ホントギッチリで、SAMUEL天才か

WP_20160408_15_25_47_Pro大抵ここで心配になるのはEPS12Vコネクタの取り回しで、ほとんどのマザーはヒートシンク下にあるので先にコネクタを接続しておかなければならず、組み立てに苦労します。しかしこのマザーはそれを予見するかのように、EPS12Vを前方外周に配置していました。これ、かなりやりやすくて良いです。ASUSは昔トラブって以来避けてきたのですが、見直しました。

マザーボード構築 (2)

WP_20160408_15_29_18_Pro個人的にライザーカードの類は好きではない(どうしてもコネクターのような信頼性を損なう部品が必要になる)のですが、このマザーはライザーが3つもある。一つはVRM、そしてこのサウンドカード、最後にPCIe/Wifiカード。サウンドについては外付けのDACがあるので不要なのですが、これをつけておかないとバックパネルにみっともない穴が開いたままになるので、一応付けることに。

WP_20160408_15_30_55_Pro付けるとこんな感じ。

WP_20160408_15_34_47_ProWifiも不要なのですが、このライザーカードには、PCIeが刺さります。そして今回の構成変更の目的である、NVMeがここに刺さるので、やはりこれも使います。ただ、Wifiモジュールは外せそうだったので取り外しました。幸いWifiアンテナの穴(バックパネル)は出荷時で塞がっているので、サウンドカードのような問題はありませんでした。

WP_20160408_15_44_26_Pro_fこれが….

WP_20160408_15_45_03_Pro_fこう。

WP_20160408_15_54_50_Pro_fWifiはMini PCIeなので、外してオミットします。

WP_20160408_16_08_38_ProこのNVMe SSDは非常に高温になる事が知られているので、念のためヒートシンクを貼っておきました。サウンドカードとのクリアランスがちょっと不安になる感じです。間に何か挟んだほうが良いかもしれません。

WP_20160408_16_08_50_Pro

WP_20160408_16_09_06_Pro

組み込み

WP_20160408_16_14_08_Proさて、いざ組み込もうとしたら、なぜかきっちり入らない。よくよく見てみると、なんとVRMのライザーカードが共締め仕様となっており、ネジで止まってる…

WP_20160408_16_18_49_Proこのネジを外したところ、さっくりとハマりました。しかし、あらかじめ取り付けたファンが邪魔で一旦外す羽目に… 外してしまうとコネクタを再挿入するのが大変だ。

WP_20160408_16_30_37_Proケーブルを接続。良いですね、このきっちりかっちり感 :)

WP_20160408_16_33_16_Proファンのコネクタをどうにか接続し、取り付け完了(実はファンが逆であることに後で気が付く)。

WP_20160408_16_39_18_ProPCIeライザーカードとRadeonを取り付け、上部ファンも取り付ける。

上部ファンは12cmの穴が開いていますが、92mmのファンを無理やり付けています。理由はSFX電源の奥行きがやや長尺で、12cmだと干渉してしまうからです。この電源は650Wなんですが、これ以外に選択肢はなく、以前使っていた450WではRadeonを安定運用できなかったので、やむなくこういうことになっています。Mini-ITXは難しい…

WP_20160408_16_45_51_ProSSDとHDDを取り付けて…

WP_20160408_16_48_14_Pro

WP_20160408_16_49_26_Proどうにか、収まりました。

WP_20160408_16_50_44_ProSATAケーブルはスマートケーブルに変えないとダメですね。そのうちやります。

Overall

WP_20160409_11_22_48_Proファンの再換装は省略。

cdi折角なのでCristalDiskMarkで測ってみました。

cdm測定中、51℃まで上昇… 雫ちゃんに大音響でお願いされたのでびびった (*´Д`)

温度は使わなければすぐに冷えたので、ベンチマークをやり続けるとか極端な事をしなければ問題ないように感じました。

ここからVSやらOfficeやら再インストール。まだ先が長い…
ちなみにVectorは作業用として、HDDはデイリーバックアップ用として使います。

それでは。