Docker for Windows でコンソールアプリケーションのコンテナを作る手順（シリーズその１）

#記事の目的
HelloWorldレベルの超簡単な.NETコンソールアプリケーションをDockerのコンテナで実行するのに必要な手順を理解します。これをスタート地点にしてもっと複雑なコンソールアプリケーションをコンテナ化することが出来ると思います。

#使用した環境
* Windows 10 アニバーサリーアップデート
* Docker for Windows Community Edition (version 17.03.1-ce) 
* Visual Studio 2017 Enterprise
 
#はじめる前にやっておきたいこと
* Docker はあらかじめ Windows Container にスイッチしておく（リブートが必要かもしれないので）
* docker pull microsoft/windowsservercore をあらかじめ実行しておく（ダウンロードに時間がかかるかもしれないので）

#コンソールアプリケーションのプロジェクトを作成
ごくありふれた.NET/C#のコンソールアプリです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/c2ea4e6a-535c-3ede-5406-db850370a2c8.png)


Dockerでコンテナを実行する時に任意の値を渡せることをデモできるように、プログラムはコマンドラインに指定された値を出力するようにしておきます。

```csharp:Program.cs
using System;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello world");
            Console.WriteLine((args.Any() ? 
                String.Join(Environment.NewLine, args) : "<no argument>"));
        }
    }
}
```

普通に実行したらこんな感じです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/3de84e79-3dba-3af8-5f13-1417e48b7419.png)

# プロジェクトにDockerfileを加える

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/087b4e96-5c79-4d46-82f9-7f2f13d9e7bf.png)

Dockerfile の中身

```
FROM microsoft/windowsservercore
WORKDIR /app
COPY obj/Docker/publish .
ENTRYPOINT ConsoleApp.exe
```
内容を言葉で表すと「Dockerの公式レジストリの、microsoftというユーザーが公開しているWindowsServerCoreというイメージをベースにする（ないならダウンロードする）。コンテナ内のappというディレクトリに移動する。ローカルのobj/Docker/publishにあるファイルをコピーする。コンテナがスタートされたときはそこにあるConsoleApp.exeを実行する。」そういう感じのスクリプトです。

# プロジェクトをビルドする

普通にビルドしますが、ビルドアウトプットを obj/Docker/publish フォルダーに手動でコピーします。
これ、例えば直接 bin/Debug とかに変更してみたんですが、うまく行きません:cry:　[MSbuildでも同様のハードコードされたパスの問題](https://developercommunity.visualstudio.com/content/problem/48019/msbuild-sdk-microsoftdotnetdockerdll-has-hard-code.html)が報告されてるんで、この部分はおそらくバグだと思う。回避方法知ってる方は教えてくださいな。

とりあえずは、ここは核心ではないので手動でコピーしました。もちろんビルドのステップとして自動化した方がいいですけどね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/92765c04-2c38-6ebf-8474-d23c8954e9c9.png)


#Docker イメージを作成する

Dockerfile があるディレクトリに行って、そこから以下のコマンドを実行します

```
docker build -t hello .
```
結果はこんな感じ。下の方に ``Successfully built 5f1494ed2cbb`` とあります。これがイメージのIDです（名前も付けられますがとりあえずこれで行きます）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/c83630c2-39ca-2b8a-9b1e-723139faf238.png)

イメージがちゃんと出来たかは `docker images` コマンドでも確認できます。 `hello`という名前のイメージ（レポジトリ）が確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/c8809f8a-5ee8-d20f-ed3a-59ece24aaff5.png)

#Docker コンテナを実行する

以下のコマンドでDockerイメージをコンテナとして実行します。コマンドライン・アーギュメントも指定します。

```
docker run hello this is fun
```

実行結果はこんな感じです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/26cf0021-bfab-1663-be51-ab236eaca643.png)

可能性は広がりますね。例えばこのコンソールアプリが実は結構面倒なインストール手順とか設定が必要だったりした場合は、Dockerfileで手順を自動化したり、イメージにして焼き付けておいたりして、必要な時はDockerのコンテナとしてどのマシンからも実行できようにしたり。
この辺りの応用に関しては私もただいま絶賛調査中です。

#お掃除
いろいろ残っている状態だと嫌でしょうから、お掃除の手順。

まずは全てのコンテナ（現在実行していないものも含めて）を表示させます。`hello`というイメージのコンテナがありますね。ちなみにコンテナのIDは78ec1e87e172です。
```
docker ps -a
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/8614d4b2-17bb-7564-0993-972214df1a07.png)

このコンテナを削除するには。以下のコマンド。IDはコンテナに限らず、短くてもユニークでさえあれば認識されます。この場合は78で十分。

```
docker rm 78
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/caf46851-70f8-4508-d309-246fddc0fae9.png)

次にイメージを削除します。まずは確認。

```
docker images
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/f1e5c11c-7d21-ad20-c39c-2401df85a4a6.png)

次に削除。rmiはrmとimageのiの合成だと覚えておけばオッケーです。helloはイメージのレポジトリ名だけどIDでも:ok_hand:。

```
docker rmi hello
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/5ed3b611-aef8-c656-a909-a3231ed2897f.png)

これでキレイになりました。

#ちなみに
Docker for Windows は二つの隔離モードがあります。Hyper-vとprocess。Hyper-vの方が重いけど隔離具合はベター。processの方がサクっと軽いけど隔離具合はやや弱い。
で、Windows 10でサクっとprocess隔離モードでやろうと思ったら・・・

```
docker run --isolation process hello
```

残念、Windows 10だとHyper-Vモードしか出来ない・・・

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/2eb3999d-4bb7-5632-d849-ae3f203077bc.png)

Windows Server 2016が必要ということです。