[MSSQL] Docker上で実行してバックアップを復元するには

[MSSQL] Docker上で実行してバックアップを復元するには

やりたいこと

DockerHubから取得したMicrosoft Linux版のSQL Serverで、Windows上のディレクトリを永続化のためにマウントして、バックアップデータ(.bak)からデータベースを復元する。

Dockerでマウントされているディレクトリに復元しようとすると、上手くいかなかったので解決方法を含めて手順をメモしておく。

環境

  • Windows 10 Pro
  • Docker Desktop (Docker 19.03.13)
  • Image: mcr.microsoft.com/mssql/server 2019-CU8-ubuntu-16.04

手順

ディレクトリ情報

  • C:\bak 復元するためのバックアップデータ(.bak)を保存
  • C:\mssql コンテナ内のMSSQLのデータ保存先にマウントして永続化するディレクトリ

コンテナを起動する

上2つのディレクトリをマウントする。
Docker Desktopがこのディレクトリを共有するのか?って聞いてくるので、Yesとすると、Docker DesktopのSettings > Resources > FILE SHARINGに追加してくれる。

docker run --name mssql -itd -v "c:\bak\":/bak -v "c:\mssql":/var/opt/mssql -p 1433:1433 -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=<Password>' mcr.microsoft.com/mssql/server:2019-latest

SSMS (SQL Server Management Studio)から復元する

手っ取り早くWindowsのSSMSからGUIで復元操作を行う。
※コンテナに入って直接コマンドで行ってもOK

ハマりポイント

普通に復元しようとすると、復元すると生成されるmdfやldfがないぞとエラーが投げられる。
/var/opt/mssql/dataに対するmssqlユーザーはフルアクセス権があるにも関わらず表示され、GitHubではバグだと騒がれている(MSSQL 2019 Database Restore Fails

メッセージ 3634、レベル 16、状態 1、行 2
The operating system returned the error '2(The system cannot find the file specified.)' while attempting 'RestoreContainer::ValidateTargetForCreation' on '/var/opt/mssql/data/<Database Name>.mdf'.
メッセージ 3156、レベル 16、状態 5、行 2
File '<Database Name>' cannot be restored to '/var/opt/mssql/data/<Database Name>.mdf'. Use WITH MOVE to identify a valid location for the file.
メッセージ 3634、レベル 16、状態 1、行 2
The operating system returned the error '2(The system cannot find the file specified.)' while attempting 'RestoreContainer::ValidateTargetForCreation' on '/var/opt/mssql/data/<Database Name>_log.ldf'.
メッセージ 3156、レベル 16、状態 5、行 2
File '<Database Name>_log' cannot be restored to '/var/opt/mssql/data/<Database Name>_log.ldf'. Use WITH MOVE to identify a valid location for the file.
メッセージ 3119、レベル 16、状態 1、行 2
Problems were identified while planning for the RESTORE statement. Previous messages provide details.
メッセージ 3013、レベル 16、状態 1、行 2
RESTORE DATABASE is terminating abnormally.

新しく空っぽのデータベースを作成してから、そこに既存のデータベースを上書きするREPLACEオプションを付けて復元すると上手くいくらしいので実行する。

USE [master]
RESTORE DATABASE [<Database Name>] FROM  DISK = N'/bak/database.bak' WITH  FILE = 1,  MOVE N'<Database Name>' TO N'/var/opt/mssql/data/database.mdf',  MOVE N'<Database Name>_log' TO N'/var/opt/mssql/data/database_log_1.ldf',  NOUNLOAD, REPLACE, STATS = 5

GO

さっきとは違うエラーが投げられる。

メッセージ 3634、レベル 16、状態 1、行 2
The operating system returned the error '2(The system cannot find the file specified.)' while attempting 'RestoreContainer::ValidateTargetForCreation' on '/var/opt/mssql/data/<Database Name>_log_1.ldf'.
メッセージ 3156、レベル 16、状態 5、行 2
File '<DATABASE NAME LOG>' cannot be restored to '/var/opt/mssql/data/<Database Name>_log_1.ldf'. Use WITH MOVE to identify a valid location for the file.
メッセージ 3119、レベル 16、状態 1、行 2
Problems were identified while planning for the RESTORE statement. Previous messages provide details.
メッセージ 3013、レベル 16、状態 1、行 2
RESTORE DATABASE is terminating abnormally.

バックアップファイルを作ったSSMSのバージョンの違いからか、生成される復元クエリを見るとログのldfファイル名の末尾に_1が自動的に付与されている。
これでは、新しく作ったデータベースのログは<Database Name>_log.ldfなので、上書きではなく新規作成になってしまう。
今回は新規作成が出来ずにこけている。
上書きされるように末尾の_1を削除して再実行して、復元されることを確認した。

なぜ、mssqlユーザーに書き込み権限があるのに書き込めないのかは不明。
GitHubでは前まで出来てたのにバージョン上げたら出来なくなった、バグだ!って騒がれてる。
(ほんとに?)

WindowsやC#の技術者ってLinux嫌い苦手なのか、情報が少ない気がする…(偏見)

コマンドメモ

コンテナに入る

docker exec -it mssql bash

コンテナ内でクエリを実行する

コンテナに入った状態でsqlcmdを実行する。
Microsoftが配布しているイメージにはsqlcmdはインストール済みだけどパス設定がされていないのでフルパスで実行する。

/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "<Password>"

プログラミングカテゴリの最新記事