Docker for Windowsを使って、SQL Server Express を使用する

#Docker for Windowsを使って、SQL Server Express を使用する
##概要
MS SQLServer databaseを使用しているシステムの単体テストを実行する際に、ローカルPCへSQL Server Expressをインストールして使っています。
(テストダブル(Mocking Framework for .NETとか)を使えば無用なのですが、敢えてフルコンタクトなテストしてます)
しかし、テストを実行していない時間も裏でSQLServerが動き続けているのは、無駄ですよね。
また、Windowsには、アプリのインストールとアンインストールを繰り返すと徐々に不安定になるという欠陥があり、Windowsをクリーンインストールをすると見違えるようにキビキビと動作する経験をされた方も多いでしょう。
開発機とはいえ、長く快適に動作して欲しいので、なるべくアプリのインストールはしたくありません。
ひと昔であれば、仮想環境を使うのが定石でしたが、リソースをバカ食いするので、ハイエンドな開発環境でないと快適な速度で、動かすことはできません。
そこで、今どきの解決策として、コンテナ(Docker)という軽量な準仮想環境を使って、単体テスト用のDBを用意してみました。

##コンテナの種類
Windows10 Proで、コンテナを動作させるには、Docker for Windowsというソフトを利用します。
Docker for Windowsには、LinuxコンテナモードとWindowsコンテナモードという2種類のモードが用意されており、どちらか一方のモードを選択する必要があります。
###Linuxコンテナモード
コンテナは、Linux発祥の技術です。
Windowsで、Linuxコンテナを直接動作させることはできません。
Hyper-Vの上で、Alpine Linuxというコンテナを動作させることに特化したコンパクトな専用OSを動作させて、その上で動作させています。
Linuxの上で直接動作させたときに比べれば、オーバーヘッドが大きいのですが、結構サクサク動きます。
ただ、少々残念なことに、microsoft/mssql-server-linuxのコンテナイメージは、ubuntu:16.04をベースに作られているので、少しデカイんですよね。
Minimal Ubuntuとかを使えば、半分のサイズになる筈なので、もっと軽量化される余地がありそうです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/7839/4a0fda5b-3a91-0aa0-45a9-d86547e2eb52.png)
###Windowsコンテナモード
Windowsコンテナは、Alpine Linuxのような余計なレイヤーが必要ないためWindowsで使うならコチラのほうが、本命だと考えていたのですが、結果を先に言えば、使うのはお勧めできません。
ベースイメージが、microsoft/windowsservercoreのためか、linux版の9.6倍の13.8GBもあります。
コンテナイメージは、キャッシュされますが、linux版が瞬時に起動するのに対して、Windows版は、少しの時間待たされます。
SQL Database自体のソースコード自体は同じもので、Linuxは互換性レイヤーを付加して動かしているにも関わらずこの結果は、Microsoftにとっては厳しい現実ですね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/7839/51eb4fbb-692b-11cb-ade6-a8acf0da2632.png)
###WSL(Windows Subsystem for Linux)
Docker for Windowsではありませんが、Windows標準のLinux環境であるWSLについても試してみました。
WSLの上で、Dockerが動作するとネットで報告されていますが、残念ながらまだ完全ではありません。
少し前まで、インストールすらままならなかったので、格段に進歩しており解決まで、もう少しなのですが、残念ながらmicrosoft/mssql-server-linuxを動作させてみると外部アプリから接続できません。
もしからしたらインサイダープログラム版とかだと成功するかも知れません。それくらいもう一歩なんですよね。
うちの会社では、Windows10 Proじゃなくて、Homeとか買ったりして配るので、Hyper-Vが使えない場合があり切実に解決されるのを願ってます。

##起動方法
###パラメーターが多いので、docker-compose.ymlを記載して、コンテナを作成します。
文字コード(1041)と照合順序(Japanese_CI_AS)を指定しないと文字化けするので、必ず指定します。

```yaml:docker-compose.yml
version: '3'
services:
    mssql:
      image: microsoft/mssql-server-linux:latest
      container_name: mssql-server
      ports:
        - 1433:1433
      environment:
        - ACCEPT_EULA=Y
        - SA_PASSWORD=[パスワード]
        - MSSQL_PID=Express
        - MSSQL_LCID=1041
        - MSSQL_COLLATION=Japanese_CI_AS
```
###コンテナを起動します。
```powershell:powershell
PS > docker-compose up -d
```

##データベースの初期化
SSMSなどで、DBとテーブルを作成してもいいのですが、手間を減らしたいので、SQLコマンドファイルをコンテナ内へコピーして、sqlcmdコマンドで実行します。
一度作ってしまえば、コンテナを削除しないかぎり使い回せます。
あくまでも単体テスト用のテンポラリなDBなので、ボリュームを指定して永続化とかはしません。
必要なくなったらコンテナと一緒に、データも綺麗に削除されます。

```powershell:init.bat
docker cp  ./init.sql mssql-server:/tmp/init.sql
docker exec mssql-server /opt/mssql-tools/bin/sqlcmd -i /tmp/init.sql -U sa -P [パスワード]
```

```sql:init.sql
CREATE DATABASE UnitTestDB
GO

USE UnitTestDB
GO

CREATE TABLE [dbo].[user_info](
	[user_info_id] [int] IDENTITY(1,1) NOT NULL,
	[user_id] [varchar](40) NOT NULL,
	[sex] [int] NOT NULL,
	[age] [int] NOT NULL,
	[mailaddress] [varchar](100) NULL,
	[time_zone] [varchar](40) NOT NULL,
	[del_flag] [bit] NOT NULL,
	[regist_datetime] [datetime] NOT NULL,
	[update_datetime] [datetime] NOT NULL,
 CONSTRAINT [PK_user_info] PRIMARY KEY CLUSTERED 
(
	[user_info_id] ASC,
	[user_id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
```