コンテナ内の SQL Server でテスト用 DB を作る際、.bak ファイルからデータベースを復元したかったのでやってみました
手順
次のステップでやっていきます
- データベースを .bak でバックアップする
- bak を .tar に変換
- .tar を埋め込みリソースに設定 → ここまで割愛
- .tar ファイルをコンテナに転送して .bak に展開
- .bak を使って DB をリストア
埋め込みリソースを設定する
Visual Studio のプロパティ設定で埋め込みリソースを設定しても良いのですが、ファイルが増えてくると都度埋め込みリソースに設定するのはめんどくさいので、.csproj でまとめて埋め込みリソースに設定する記述を追加します。
<ItemGroup> <EmbeddedResource Include="{リソースフォルダのパス}\*.tar" /> </ItemGroup>
埋め込みリソースを読み込む
埋め込みリソースとして持っておけば、いろいろ取り回しが楽なので埋め込みリソースを使用します
埋め込みリソースを Stream に読み込むコードは以下のような感じです。
ファイルパスは、名前空間.フォルダ名.ファイル名 です
フォルダ名に -
が入っている場合、-
は使えないので、_
に置換します。(例)test-resources フォルダの場合、test_resources にする)
var resourceFullName = $"{プロジェクトの名前空間}.{フォルダ名}.{ファイル名}"; var assembly = Assembly.GetExecutingAssembly(); using (var stream = assembly.GetManifestResourceStream(resourceFullName)) { if (stream is null) throw new FileNotFoundException(resourceName); }
.tar をコンテナに転送
コンテナに .tar を転送します。
埋め込みリソースを読み込むコードを下記のように変更します。
はじめに、転送先のディレクトリをコンテナ内に作成します。
CreateContainerParameters
の設定に Cmd
を設定します。
var containerConfig = new CreateContainerParameters { Image = imageFullName, Env = environmentVairbales, ExposedPorts = exposedPorts, HostConfig = hostConfig, Cmd = new[] { "bash", "-c", "mkdir -p {ディレクトリパス}" } };
var resourceFullName = $"{プロジェクトの名前空間}.{フォルダ名}.{ファイル名}"; var assembly = Assembly.GetExecutingAssembly(); using (var stream = assembly.GetManifestResourceStream(resourceFullName)) { if (stream is null) throw new FileNotFoundException({ファイル名}); await _dockerClient.Containers.ExtractArchiveToContainerAsync( _containerId, new ContainerPathStatParameters { Path = "コンテナの転送先ディレクトリ" }, stream ); }
ExtractArchiveToContainerAsync
を使うと、転送後に .tar を展開してくれるので、リストアは .bak を指定します。
DB をリストアする
SqlCommand でリストア用のクエリを流します
var restoreCommand = $@" RESTORE DATABASE [{データベース名}] FROM DISK = N'{.bak の転送先ディレクトリ}/{.bak ファイル名}' WITH REPLACE, MOVE '{データベース名}_Data' TO '{.mdf ファイルの展開先}', MOVE '{データベース名}_Log' TO '{.ldf ファイルの展開先}', RECOVERY; "; using(var command = new SqlCommand(restoreCommand, connection)) { await command.ExecuteNonQueryAsync(); }
まとめ
.bak から展開 DB の復元が出来ました。
これで、ユニットテスト毎にきれいなテストデータでテストを回すことが出来るようになりました。