SQLServerのDockerコンテナに初期データを投入して起動します。
マイクロソフト公式のDockerイメージを使用します。MySQLだと初期データ投入の仕組みが初めから組み込まれていますが、SQLServerにはそれないのでシェルを作成しました。
Microsoft SQL Server Dockerイメージ(https://hub.docker.com/_/microsoft-mssql-server)
参考:公式からリンクされているデータ投入サンプル(https://github.com/twright-msft/mssql-node-docker-demo-app)
Qiita Docker for Windowsを使って、SQL Server Express を使用する
ディレクトリー構成
|- docker-compose.yml
|- docker
|- mssqlserver
|- Dockerfile
|- initdb.d
|- entrypoint.sh
|- import-data.sh
|- demo.sql
|- Demo.dbo.DEMO.csv
|- data
|- log
|- secrets
各ファイル
docker-compose.yml
environmentで設定しているSQL Serverの環境変数についてはこちらを参照。
version: '3'
services:
mssql:
build:
context: ./docker/mssqlserver/
image: mssql
ports:
- 1433:1433
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=56CFUVzh # パスワードポリシー(https://docs.microsoft.com/ja-jp/sql/relational-databases/security/password-policy?view=sql-server-ver15)
- MSSQL_PID=Express # SQL Serverのエディションまたはプロダクトキー
- MSSQL_LCID=1041 # ロケールID 日本語 (https://www.ryadel.com/en/microsoft-windows-lcid-list-decimal-and-hex-all-locale-codes-ids/)
- MSSQL_COLLATION=Japanese_CI_AS # 照合順
- DB_NAME=DEMO # 初回起動時のDB存在判定のために使用します。
volumes:
- ./docker/mssqlserver/initdb.d:/docker-entrypoint-initdb.d
- ./docker/mssqlserver/data:/var/opt/mssql/data
- ./docker/mssqlserver/log:/var/opt/mssql/log
- ./docker/mssqlserver/secrets:/var/opt/mssql/sec
Dockerfile
初期データと投入用シェルスクリプトをコピーし、entrypoint.shを呼び出します。
(ちなみにEXPOSE
はただのドキュメントらしいです。)
FROM mcr.microsoft.com/mssql/server:2017-latest
USER root
SHELL ["/bin/bash", "-c"]
WORKDIR /docker-entrypoint-initdb.d
COPY ./initdb.d/ /docker-entrypoint-initdb.d/
RUN chmod -R +x /docker-entrypoint-initdb.d
EXPOSE 1433
ENTRYPOINT ["/bin/bash", "./entrypoint.sh"]
entrypoint.sh
データ登録のシェルとSQLServerを同時起動します。ここで少しはまったのですがSQLServerの起動を先にするとimport-data.sh実行後コンテナが停止してしまいます。SQLServerを後ろにするとコンテナは起動し続けます。(つまりDockerは一番最後に実行したプロセスが生きているかどうかでコンテナを停止するのか判断している?)
→これは単純にどちらをバックグラウンドで実行するかの違いでした。SQLServerをバックグラウンドで実行してしまっているので、import-data.shが終わるとプロセスID=1のこのシェルが終了します。PID=1のプロセスが停止するとDockerが停止します。詳しくはコメント欄の2件目を参照してください。
Initialize MS SQL in Docker container - create database at startup(https://www.softwaredeveloper.blog/initialize-mssql-in-docker-container)
#!/bin/bash
LOG_OUT=/var/opt/mssql/log/init-stdout.log
LOG_ERR=/var/opt/mssql/log/init-stderr.log
exec 1>>$LOG_OUT
exec 2>>$LOG_ERR
# SQL Serverが前だとコンテナが停止してしまいます。
#/opt/mssql/bin/sqlservr & /docker-entrypoint-initdb.d/import-data.sh
/docker-entrypoint-initdb.d/import-data.sh & /opt/mssql/bin/sqlservr
import-data.sh
SQLServerと同時起動するので、インスタンスが起動するまで初めに20秒スリープします。また、SQLやCSVインポートを実行してエラーの場合1秒待って再実行するようにしています。
#!/bin/bash
sleep 20
if [ `ls -U1 /var/opt/mssql/data | grep $DB_NAME | wc -l` -eq 0 ]; then
cd /docker-entrypoint-initdb.d
sql_files=`ls *.sql`
for file in $sql_files;
do
for i in {1..30};
do
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -i $file
if [ $? -eq 0 ]
then
echo "${file} completed."
break
else
echo "${file} failed."
sleep 1
fi
done
done
csv_files=`ls *.csv`
for file in $csv_files;
do
for i in {1..30};
do
table_name=`basename $file .csv`
/opt/mssql-tools/bin/bcp $table_name in $file -c -t',' -S localhost -U sa -P $SA_PASSWORD
if [ $? -eq 0 ]
then
echo "${file} completed."
break
else
echo "${file} failed."
sleep 1
fi
done
done
fi