monoが動くDockerイメージを作る記事を書いたら非常につまらなかったので、C#アプリをDockerで動かしてみた【KSP-DMP】

最近話題のDockerをご存知ですか？
Immutable InfrastructureやdevOpsと行ったバズワードで広まり、AWSやAzureといった各クラウド事業者も注目しているLinuxの軽量コンテナDocker
各サーバをコンテナイメージにしてDockerHub配布できる。そしてVMとくらべて軽量といった利点があり
実際にどういう利点があるか。というのはググっていただければ沢山の記事が出てくると思います

記事の例
* http://deeeet.com/writing/2014/05/01/what-is-docker/
* http://www.atmarkit.co.jp/ait/articles/1405/16/news032.html

自分が思うDockerの利点は
1. 各イメージから別のイメージを作れる
2. イメージはimmutableである(1と合わせてイメージをgitのように扱える)
3. イメージをDockerHubで共有でき、各ソフトウェアの公式イメージも多数ある
4. イメージをDockerfileというソースコードとして配布&ビルドもできる(chefやpuppetにもある機能ですが)

という利点があるかなと思ってます。

もちろん、dockerにも欠点や「向いてない」ものもあります。
先ほどの記事にも幾つか欠点や「向いてない」点等が挙げられていますし
ググっていただければ他にも色々書かれています。

この記事はC# Advent Calendarの記事なので、C#er的に気になる点を1つあげます。
C#的に最も気になる点といえば、DockerはWindows OSのコンテナには対応してない点があげられるでしょう。
ただ、mono projectの取り組みや、最近の.NETのオープン化にともなって
非Windows環境であっても十分に活用できる状況になっているので、その点は特に問題にならないと思います

> むしろ、monoより歴史が浅いdockerの方が圧倒的に色々不安定で
> UbuntuやDebian系最新OS以外だと、まだ地雷がある状態です
> なので、重要度が低いアプリでちょこちょこ実績を積む時期かなと思っています。
> (なお仕事でCentOS6の地雷軽く踏みました(--;。ゲストがCentOS6のDockerfileでADDがちゃんと動かなった。Linuxカーネル古いとダメみたいですね)
> それに比べればmonoはGNOMEやUnityで実績ありますし。

monoが動くコンテナの作り方
==========================

では、早速monoが動くコンテナを作っていきましょう

■作成手順
1. [dockerをインストールする](https://docs.docker.com/)
2. `sudo docker run -i -t mono /bin/bash` を実行する
3. するとmonoが入ったDebianコンテナイメージがDLされて、コンテナが立ち上がる

以上

これだけ？
---------

はい。monoが動くコンテナを立ち上げるだけならこれだけです。簡単でしょ？

簡単なのはいいけど、記事になってない気が
--------------------------

はい。monoが動くコンテナを作るだけじゃ記事になりませんでした(泣)
数ヶ月前まではmonoが入ったコンテナを作るときはUbuntuやCentOSとかのイメージを元にソースビルドして作ってたのですが
楽しいことに、公式リポジトリにDebianベースのmono project公式のイメージが入ったので
その時のDockerfile(コンテナイメージを作成するスクリプト)がだいぶ無駄になりました (- -;

実はMicrosoftもこのmono公式イメージを元に公式のASP.NET vNextイメージを作っており
C#er的に必要な基本イメージは、嬉しい事に揃っています！

* [mono公式イメージ](https://registry.hub.docker.com/u/library/mono/) ([Dockerfile](https://github.com/mono/docker))
* [ASP.NET公式イメージ](https://registry.hub.docker.com/u/microsoft/aspnet/) ([Dockerfile](https://registry.hub.docker.com/u/microsoft/aspnet/dockerfile/))

なので、基本的に自作せずに公式イメージを使うべきです。
記事書くにあたって、[ベースイメージがUbuntu, CentOSのDockerfileを作りましたが](https://github.com/wilfrem/csharp-dockerfile)
特に理由がなければ公式イメージを使うべきと思います。


で、どうするの？
--------------
記事としては微妙なので
重要度低い既存アプリを実際にDockerで動かすところまでやってみます。


と言うわけで
=============

重要度低い既存のC#アプリを実際にDockerイメージにしてazureで動かしてみます！

~~今回の犠牲者~~今回Docker化するアプリC#アプリはこのアプリです。

![DMP KSP Multi Player](http://d-mp.org/img/logo.png "KSP Dark Multiplayer(DMP)")
KSP Dark Multi-Player(DMP)

[ソースコード](https://github.com/godarklight/DarkMultiPlayer)

このKSP Dark Multi-Player(DMP)というのはKerbal Space Program(KSP)というゲームのマルチプレイヤーMODです

![Kerbal Space Program](http://media.tumblr.com/8a5935078d0749ca56ac7b561a31f9b1/tumblr_inline_ng157iHPIh1rr2wit.png "Kerbal Space Program")

KSPはUnityで作られており、KSP本体やMODはC#で書かれています。

もちろんKSPや大半のMODはWindowsやMac等のクライアントPCで動かす物で、サーバで動かす物では無いのですが
DMPだけはKSPに入れるクライアントMODの他に、ホストマシンで動かすサーバソフトウェアがあります。

このサーバソフトウェアは純粋なC#コードで書かれた.NETバイナリなので、
これを実際にDockerイメージ化してazure上で動かしてみます！

動かすまでの手順
=======

1. monoの互換性チェックとmono上での動作確認
2. Dockerイメージの設計
3. Dockerfileの作成とビルド
4. azureへのデプロイ

互換性チェックと動作確認
----------------

monoとWindowsの.NET環境は互換性はかなり高いですが
時々機能が未実装ということがあります。
他にもWindows固有の機能を使ってる等でエラーになるケースもあるので
まずは互換性チェックします。

今回互換性チェックに使うのは[MoMA](http://www.mono-project.com/docs/tools+libraries/tools/moma/)です

MoMAは[だいぶメンテされてない](http://www.buildinsider.net/mobile/insidexamarin/04)のですが、
代替ツールが見つからないので、False-Positiveをチェックする形でこれを利用します
(この辺りは.NETオープン化でチェック要らなくなるのかな？)

![MoMA.png](https://qiita-image-store.s3.amazonaws.com/0/42898/e3fa2c9e-73f4-424e-0387-ae014c4dadb5.png)

MoMAで分析にかけると
* Assemby.UnsafeLoadFromが見つからない(DMP側のプラグインロード時)
* Typeの==オーバーロードにMonoTodoがマーキングされている(DMPの設定ファイル読み込み時)
という二点の警告が出てきました。

UnsafeLoadFromは[ここ](https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Reflection/Assembly.cs)から内部呼び出しされており、内部を見ると[実装されている](https://github.com/mono/mono/blob/dfebf124e54e11ef4de85addffd8d9df102e859b/mono/metadata/appdomain.c#L1895)
よって、MoMAが古いことによる問題と分かる

Typeの==オーバーロードは[コード](https://github.com/mono/mono/blob/master/mcs/class/corlib/System/Type.cs#L493)をみると「実装の詳細が分かったら実装してね」って書いているだけで、実装自体に問題ないように見える

そして、Linux上で動作確認をして、問題が無いことを確認した

![動作確認](https://qiita-image-store.s3.amazonaws.com/0/42898/9d2a1733-73d5-a251-2b33-186fd3250855.png)

Dockerイメージの設計
-------------------

DMPは以下のファイル構成になっている
> DMPServer
> ┣ Universeフォルダ。DMPサーバの状態が保存される
> ┣ logsフォルダ。DMPサーバのログが書き出される
> ┣ Pluginsフォルダ。DMPサーバに入れるプラグインフォルダ
> ┣ DMP*.txt DMPサーバの設定ファイル
> ┣ DMPServer.exe DMPサーバ本体
> ┗ *.dll DMPサーバが参照しているdll類

この中で永続化が必要なデータ類は"Universe"と"logs"フォルダの２つで
あとは不変な実行バイナリと設定ファイルである。

よって、"Universe"と"logs"の2つをイメージの外に置いて他をDockerイメージの中に入れる
起動時にはUniverseとlogsの2つのフォルダを外からマウントする形にする。
これにより、イメージから立ち上げたコンテナは常に同じ状態で、データだけは永続化された状態になる

Dockerfileの作成とビルド
---------------
以下の形にフォルダを構成する
> /path/to/somewhere
> ┣Dockerfile
> ┗DMPServerApp Universeとlogsフォルダを除いたDMPサーバファイル

Dockerファイルは先ほどの設計を元に以下のように作成する
https://github.com/wilfrem/DarkMultiPlayer-docker/blob/master/dockerfile/Dockerfile

あとはDockerfileと同階層で`sudo docker build -t タグ名 .`を実行し、DockerHubにpush(アップロード)する
(今回は公開していいものなのでDockerHubを使っているが、社内の物の場合は社内でDockerHubを立ててもらってそちらにpushする)

azureへのデプロイ
------------
以下の手順でサクッと作ってしまいます

1. コントロール画面からUbuntu14.04 サーバを作成する(今回はCLIの`azure vm docker`は使わず)
2. 作成したサーバにデータディスクを挿し、Universeフォルダとlogフォルダを配置する
3. Dockerをインストールする
4. 先ほどDockerHubにpushしたイメージをpullする
5. Universeとlogフォルダをマウントする[起動スクリプト](https://github.com/wilfrem/DarkMultiPlayer-docker/blob/master/bootstrap/bootstrap.sh)を書く
6. 起動スクリプトをsupervisordに登録する

以上が手順です。
これでazure上にDMPのサーバが立ったのでKSPマルチプレイが遊べるようになりました。
後は普通のマルチプレイゲームの要領でazureのサーバにつなぎに行くだけで遊べるようになりました。
(ごめんなさい、諸般の事情でスクショは無いです)

以上がC#アプリをDockerで動かしてみた記事になります。
C# Advent Calendarなのに、書いてみたらあんまりC#っぽくない内容ですみませんでした。

[C# Advent Calendar](http://qiita.com/advent-calendar/2014/csharp)の次の日は[jag5X](http://qiita.com/advent-calendar/2014/csharp)さんです。よろしくお願いします。
　
　
　
　
　
　
　
　
　
　
　
　
　
　
　
　

    
  

おまけ
======

[Kerbal Space Program: Beta Than Ever is Now Available](http://kerbaldevteam.tumblr.com/post/105298544359/kerbal-space-program-beta-than-ever-is-now)
![KSP Beta](http://media.tumblr.com/5ef599c0294320bff53bfef6e333d7bb/tumblr_inline_ngmxzrfoDl1rr2wit.jpg)

KSP大幅バージョンアップがもう来た、、、だと？(Steamで自動アップデート)
　
　

まさか、、、、
　
　
　
　
　
　
ぎぃやあああああああぁぁぁぁぁぁぁぁぁぁぁぁ破壊的変更入ってDMP死んだああああああぁぁぁぁぁぁぁぁぁぁ＼(^o^)／
昨晩動かし始めたサーバー、クライアント側が壊れててつながらねぇええええぇぇぇぇorz
そして昨日のスクショ撮り忘れてたああぁぁぁぁぁぁ／(^o^)＼

サービス終了のお知らせ
------------------

長い間、azure上のDMPマルチプレイをご利用いただきありがとうございました。サーバを建てたのはつい数時間前だった気がしますが、
KSPの突然のバージョンアップによってazure上のDMPサーバは文鎮化し、強制的にサービス終了になりました。
azure上のDockerイメージは自分が頑張って開発したサービスではありますが、出すのが早すぎた(早期アクセスゲーム的に)という結論に至りました。

出なおしてまいりますので、DMPのバージョンアップをお待ちください。

あとがき
========

いやー、開発版(α版、β版)って使ってて楽しいですねー