Local Database With Scripts (MSSQL)
When developing apps locally it can be really useful to have a dockerised database unique to the application.
Often rather than just running a pre-built image, you'll want to run a database with some initial data, tables, or a schema.
For this purpose we can create our own image that extends the base image and adds our own scripts.
Setup
For most applications the directory structure will look something like this:
database/
Dockerfile
scripts/
01-create-database.sql
02-create-tables.sql
03-seed-data.sql
development/
compose.yml
src/
...
tests/
...
Dockerfile
Create a dockerfile in the database/
directory:
FROM mcr.microsoft.com/mssql/server:2022-latest
# Set the SQL Server environment variables
ENV ACCEPT_EULA="Y"
ENV SA_PASSWORD="Password123"
# Setup port
EXPOSE 1433
# Create a temp directory
RUN mkdir -p /tmp/init
# Copy all the scripts into the container
COPY ./scripts/ /tmp/init
ENTRYPOINT [ "/tmp/init/entrypoint.sh" ]
DANGER
As this is a local development database, we're using the sa
user with a simple password. Do not use this in production.
Scripts
Create the scripts in the database/scripts/
directory:
#!/bin/bash
# Run the sql scripts and start sql server
/tmp/init/run-scripts.sh & /opt/mssql/bin/sqlservr
#!/bin/bash
# Wait for the mssql database to be ready
while ! /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -C -Q "SELECT 1" > /dev/null; do
sleep 1
done
echo "SQL Server is up and running"
# Check if the setup has already been executed
SETUP_DONE=$(/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$SA_PASSWORD" -C -Q "IF EXISTS (SELECT 1 FROM master.sys.tables WHERE name = 'setup_marker' AND schema_id = SCHEMA_ID('dbo')) SELECT 1 ELSE SELECT 0" -h -1 -W -r 1 | grep -oE '^[0-9]+' | tr -d '[:space:]')
if [[ "$SETUP_DONE" == "1" ]]; then
echo "Setup has already been completed. Skipping initialization."
exit 0
else
echo "Setup has not been completed. Running initialization."
fi
# Run all scripts in the scripts folder
for entry in /tmp/init/*.sql;
do
echo "Running script $entry"
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -C -i $entry
done
# Create a marker table to indicate setup completion
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -C -Q "CREATE TABLE master.dbo.setup_marker (id INT PRIMARY KEY IDENTITY, created_at DATETIME DEFAULT GETDATE())"
echo "All scripts have been run"
The above script waits for the database to be ready, then checks if the setup has already run. If not it will run all the scripts in the scripts/
directory and create a marker table to indicate that the setup has been completed.
Create any scripts that you need in the database/scripts/
directory.
TIP
See below for an example of the scripts you might want to run.
CREATE DATABASE MyDatabase
USE MyDatabase
CREATE TABLE MyTable (
id INT PRIMARY KEY,
name NVARCHAR(50)
)
USE MyDatabase
INSERT INTO MyTable (id, name) VALUES (1, 'Alice')
INSERT INTO MyTable (id, name) VALUES (2, 'Bob')
USE MyDatabase
CREATE LOGIN MyUser WITH PASSWORD = 'MyPassword'
CREATE USER MyUser FOR LOGIN MyUser
ALTER ROLE db_owner ADD MEMBER MyUser;
Compose
Lastly we need to create a docker-compose.yml
file in the development/
directory:
services:
db:
build:
context: ../database
dockerfile: Dockerfile
volumes:
- db-data:/var/opt/mssql
ports:
- "1433:1433"
volumes:
db-data: