Skip to content

Creating a database automatically upon startup #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
LuisBosquez opened this issue Dec 27, 2016 · 67 comments
Open

Creating a database automatically upon startup #2

LuisBosquez opened this issue Dec 27, 2016 · 67 comments

Comments

@LuisBosquez
Copy link
Contributor

A couple of comments (4) in the DockerHub page suggest adding parameters to create a database with username and password automatically.

@twright-msft twright-msft changed the title [mssql-server-linux] Creating a database automatically upon startup Creating a database automatically upon startup Jan 5, 2017
@rburgst
Copy link

rburgst commented Jan 16, 2017

+1

@rburgst
Copy link

rburgst commented Jan 16, 2017

Is there a timeline for this? Also the missing tools in this container/image (see #8 ) make this hard to achieve for me on my own.

@potzkovge
Copy link

+1

@twright-msft
Copy link
Collaborator

FYI - We released CTP 1.4 today. This release of the mssql-server-linux image now includes the mssql-tools package (sqlcmd and bcp) in it.

Executing sqlcmd as part of the entrypoint.sh script can be used for this kind of scenario for now. Since this is such a commonplace requirement we want to make it easier in the future, but sqlcmd will provide a reasonable option until then.

@kuncevic
Copy link

kuncevic commented Nov 24, 2017

Was wondering how would you create default db and user just by using docker-compose.yaml file
That is what i've got now:


  sqlserver:
    container_name: 'sqlserver'
    image: microsoft/mssql-server-linux:2017-CU1
    environment:
      - ACCEPT_EULA=Y
      - MSSQL_PID=Developer
      - SA_PASSWORD=<pwd>
      - MSSQL_DB=mydb (was expected db to be created)
      - MSSQL_USER=me
      - MSSQL_PASSWORD=<pwd>
    ports:
      - "1433:1433"
    networks:
      - app-network

Using this image for now https://github.com/mcmoe/mssqldocker to create the container and default db

@ghost
Copy link

ghost commented Nov 28, 2017

hi @kuncevic did this docker compose work for you? did you get a db and user on the container?

@twright-msft
Copy link
Collaborator

Creating databases and users at container run time is not implemented yet.

@kuncevic
Copy link

kuncevic commented Dec 2, 2017

@pjpradeepjha using this image https://github.com/mcmoe/mssqldocker - yes
But the mssql docker image is so huge in size also it needs at least 3.5 gb of ram to run (2gb with CU2).
So I ended up using PostgresSQL alpine image which is like 14mb size.
I wish mssql has a small alpine image just to handle nothing else but basic select, update and delete

@ghost
Copy link

ghost commented Dec 4, 2017

@kuncevic @twright-msft thanks for the comments. appreciate the help. :) I was constantly trying to create user and db from docker compose on the mssql docker image to no effect.

@twright-msft
Copy link
Collaborator

@kuncevic - We will continue to make the SQL image container smaller. Just takes some time to minify something like SQL Server as you can imagine. :)

@brunooliveiramac
Copy link

:) Thanks a lot @kuncevic

@felixhayashi
Copy link

felixhayashi commented Feb 10, 2019

Bump. Both postgres and mysql images already support using environment variable to create an initial database when the image is run and the container is created (POSTGRES_DB: "mydb" or MYSQL_DATABASE: "mydb"). Would be great if this were also supported in the official mssql image, otherwise we need to rely on executing sqlcmd to create the db on container startup.

@celamb4
Copy link

celamb4 commented May 29, 2019

Any updates? Its been in the backlog for over 2 years. Doesnt seem like that big of a request. If we cant create one based on ENV is there a default DB created when the container boots up?

@0x-2a
Copy link

0x-2a commented Jul 2, 2019

The naming convention in these env vars is inconsistent with industry standard database connectors.

MYSQL_DATABASE here actually refers to the database Instance in connector drivers, not the Database.

For example, MYSQL_DATABASE treated as an Instance variable would have users connect with the following (which is currently what it does):
sqlserver://localhost\Foo:1433

Where as MYSQL_DATABASE as a Database variable would have users connect with:
sqlserver://localhost:1433;database=Foo, which is currently does not.

I think this is why some folks have connection issues and others don't. It would probably be best to support both.

For others wondering, it looks like you can do this after your docker starts up:

docker exec -i YOUR_MSSQL_DOCKER_CONTAINER /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'YOUR_MSSQL_PASS_HERE' -Q 'CREATE DATABASE YOUR_DATABASE_NAME'

@lkurzyniec
Copy link

lkurzyniec commented Oct 30, 2019

It is possible, here you are examples: https://github.com/microsoft/sql-server-samples/tree/master/samples/containers

And also my example, IMHO much more straight forward: https://github.com/lkurzyniec/netcore-boilerplate

docker-compose

version: "3.6"

services:
  mssql:
    image: mcr.microsoft.com/mssql/server:2017-latest
    container_name: mssql
    command: /bin/bash ./entrypoint.sh
    ports:
      - 1433:1433
    environment:
      - ACCEPT_EULA=Y
      - MSSQL_PID=Express
      - SA_PASSWORD=SomeStrongPwd123
    volumes:
      - dbdata:/var/opt/mssql/data
      - ./db/mssql/docker-entrypoint.sh:/entrypoint.sh
      - ./db/mssql/docker-db-init.sh:/db-init.sh
      - ./db/mssql/mssql-cars.sql:/db-init.sql

  netcore-boilerplate:
    image: netcore-boilerplate:local
    container_name: netcore-boilerplate
    build:
      context: .
    ports:
      - 5000:80
    depends_on:
      - mssql

volumes:
  dbdata:

docker-entrypoint.sh

#start SQL Server, start the script to create/setup the DB
 /db-init.sh & /opt/mssql/bin/sqlservr

!!! There is a space in front of.

db-init.sh

#wait for the SQL Server to come up
sleep 30s

echo "running set up script"
#run the setup script to create the DB and the schema in the DB
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P SomeStrongPwd123 -d master -i db-init.sql

db-init.sql

USE [master]
GO

IF DB_ID('cars') IS NOT NULL
  set noexec on               -- prevent creation when already exists

/****** Object:  Database [cars]    Script Date: 18.10.2019 18:33:09 ******/
CREATE DATABASE [cars];
GO

USE [cars]
GO

/****** Object:  Table [dbo].[Cars]    Script Date: 18.10.2019 18:33:09 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Cars](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[Plate] [varchar](50) NOT NULL,
	[Model] [varchar](50) NULL,
	[OwnerId] [int] NULL,
 CONSTRAINT [PK_Cars] PRIMARY KEY CLUSTERED
(
	[Id] ASC
)) ON [PRIMARY]
GO

/****** Object:  Table [dbo].[Owners]    Script Date: 18.10.2019 18:33:09 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Owners](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[FirstName] [varchar](50) NOT NULL,
	[LastName] [varchar](50) NOT NULL,
	[FullName]  AS (([FirstName]+' ')+[LastName]),
 CONSTRAINT [PK_Owners] PRIMARY KEY CLUSTERED
(
	[Id] ASC
)) ON [PRIMARY]
GO

SET IDENTITY_INSERT [dbo].[Cars] ON
GO
INSERT [dbo].[Cars] ([Id], [Plate], [Model], [OwnerId]) VALUES (1, N'JHV 770', N'Mercedes-Benz GLE Coupe', 1)
GO
INSERT [dbo].[Cars] ([Id], [Plate], [Model], [OwnerId]) VALUES (2, N'TAD-3173', N'Datsun GO+', 1)
GO
INSERT [dbo].[Cars] ([Id], [Plate], [Model], [OwnerId]) VALUES (3, N'43-L348', N'Maruti Suzuki Swift', 2)
GO
INSERT [dbo].[Cars] ([Id], [Plate], [Model], [OwnerId]) VALUES (4, N'XPB-2935', N'Land Rover Discovery Sport', 3)
GO
INSERT [dbo].[Cars] ([Id], [Plate], [Model], [OwnerId]) VALUES (5, N'805-UXC', N'Nissan GT-R', NULL)
GO
SET IDENTITY_INSERT [dbo].[Cars] OFF
GO

SET IDENTITY_INSERT [dbo].[Owners] ON
GO
INSERT [dbo].[Owners] ([Id], [FirstName], [LastName]) VALUES (1, N'Peter', N'Diaz')
GO
INSERT [dbo].[Owners] ([Id], [FirstName], [LastName]) VALUES (2, N'Leon', N'Leonard')
GO
INSERT [dbo].[Owners] ([Id], [FirstName], [LastName]) VALUES (3, N'Shirley', N'Baker')
GO
INSERT [dbo].[Owners] ([Id], [FirstName], [LastName]) VALUES (4, N'Nancy', N'Davis')
GO
SET IDENTITY_INSERT [dbo].[Owners] OFF
GO

ALTER TABLE [dbo].[Cars]  WITH CHECK ADD  CONSTRAINT [FK_Cars_Owners] FOREIGN KEY([OwnerId])
REFERENCES [dbo].[Owners] ([Id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Cars] CHECK CONSTRAINT [FK_Cars_Owners]
GO

CREATE LOGIN [user]
    WITH PASSWORD = 'simplePWD123!';

CREATE USER [user] FOR LOGIN [user] WITH DEFAULT_SCHEMA=[dbo]
GO

GRANT ALL ON Cars TO [user];
GRANT ALL ON Owners TO [user];
GO

hd1fernando added a commit to hd1fernando/MercadoLivre.Clone that referenced this issue Jun 5, 2022
…e dados

Estava ocorrendo um erro de conexão pois o Nhibernate no Progra.cs procurava uma conexão com o banco MercadoLivreClone. Porém, o BD ainda não existia.

A solução foi criar o BD pelo Docker conforme a sugestão em:
microsoft/mssql-docker#2 (comment)
@kolendomichal
Copy link

Any sort of update on this?
@amvin87

@potatoqualitee
Copy link

I am eager for an update as well 🙏🏼

@abdennour
Copy link

6 years and no fix ! wy wy wy

@tracker1
Copy link

Give this a look... just dumped it from another project, and minor tweaks... completely untested in current state.

https://github.com/tracker1/mssql-docker-enhanced

@hlovdal
Copy link

hlovdal commented Dec 7, 2022

Updated 2023-03-30 to make the cmd_wrapper.sh script tolerant of sqlcmd failures.


@Schlurcher NB, the last command in an entrypoint script should always be executed thourgh exec, e.g.

...
# NB NB The last (long running) command should always be started through exec, see
# https://stackoverflow.com/questions/39082768/what-does-set-e-and-exec-do-for-docker-entrypoint-scripts and
# https://stackoverflow.com/questions/32255814/what-purpose-does-using-exec-in-docker-entrypoint-scripts-serve
# for details.
exec /opt/mssql/bin/sqlservr

I generalized the script to support a generic /docker-entrypoint-initdb.d directory instead of a hardcoded setup.sql and also used it as CMD replacement instead of ENTRYPOINT replacement. The docker-compose.yml file then needs the following change:

   db-server:
     image: mcr.microsoft.com/mssql/server:2017-latest
     ...
+    command: [ "/cmd_wrapper.sh" ]
     volumes:
       ...
+      - ./volume/db-server/cmd_wrapper.sh:/cmd_wrapper.sh
+      - ./volume/db-server/docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d/

with cmd_wrapper.sh being the following:

#!/bin/bash

function finish() {
        local _ret=$?
        if [[ _ret -ne 0 ]]
        then
                echo "========================================================================"
                echo "$0: ERROR: Some command exited with exit code $_ret"
                echo "========================================================================"
        fi
}
trap finish EXIT

# This script cannot unconditionally terminate on command failure because in
# some situations command failures occurs when sqlcmd fails to log in in the
# beginning, but eventually it will succeed. Example log:
# ...
# -03-15 10:18:20.78 spid6s      Starting up database 'msdb'.
# -03-15 10:18:20.78 spid11s     Starting up database 'mssqlsystemresource'.
# -03-15 10:18:20.79 spid11s     The resource database build version is 14.00.3460. This is an informational message only. No user action is required.
# -03-15 10:18:20.84 spid11s     Starting up database 'model'.
# -03-15 10:18:21.08 spid11s     Polybase feature disabled.
# -03-15 10:18:21.08 spid11s     Clearing tempdb database.
# -03-15 10:18:21.57 spid11s     Starting up database 'tempdb'.
# -03-15 10:18:21.78 spid18s     A self-generated certificate was successfully loaded for encryption.
# -03-15 10:18:21.80 spid18s     Server is listening on [ 127.0.0.1 <ipv4> 1433].
# -03-15 10:18:21.80 spid18s     Dedicated administrator connection support was not started because it is disabled on this edition of SQL Server. If you want to use a dedicated administrator connection, re
# start SQL Server using the trace flag 7806. This is an informational message only. No user action is required.
# -03-15 10:18:21.87 Logon       Error: 18401, Severity: 14, State: 1.
# -03-15 10:18:21.87 Logon       Login failed for user 'sa'. Reason: Server is in script upgrade mode. Only administrator can connect at this time. [CLIENT: 127.0.0.1]
# Waiting for sys.databases query to return 4 or more rows
# -03-15 10:18:21.94 spid6s      Synchronize Database 'msdb' (4) with Resource Database.
# -03-15 10:18:21.94 spid21s     The Service Broker endpoint is in disabled or stopped state.
# -03-15 10:18:21.94 spid21s     The Database Mirroring endpoint is in disabled or stopped state.
# -03-15 10:18:22.04 spid21s     Service Broker manager has started.
# -03-15 10:18:22.24 spid6s      Database 'master' is upgrading script 'u_tables.sql' from level 234884480 to level 234884484.
# -03-15 10:18:22.25 spid6s      Starting u_Tables.SQL at  15 Mar 2023 10:18:22:253
# -03-15 10:18:22.25 spid6s      This file creates all the system tables in master.
# -03-15 10:18:22.28 spid6s      drop view spt_values ....
# -03-15 10:18:22.34 spid6s      Creating view 'spt_values'.
# -03-15 10:18:22.46 spid6s      drop table spt_monitor ....
# -03-15 10:18:22.50 spid6s      Creating 'spt_monitor'.
# -03-15 10:18:22.52 spid6s      Grant Select on spt_monitor
# -03-15 10:18:22.53 spid6s      Insert into spt_monitor ....
# -03-15 10:18:22.89 spid6s      Finishing at  15 Mar 2023 10:18:22:893
# -03-15 10:18:22.91 Logon       Error: 18401, Severity: 14, State: 1.
# -03-15 10:18:22.91 Logon       Login failed for user 'sa'. Reason: Server is in script upgrade mode. Only administrator can connect at this time. [CLIENT: 127.0.0.1]
# Waiting for sys.databases query to return 4 or more rows
# -03-15 10:18:23.08 spid6s      Database 'master' is upgrading script 'ProvisionAgentIdentity.sql' from level 234884480 to level 234884484.
# -03-15 10:18:23.08 spid6s      Database 'master' is upgrading script 'no_op.sql' from level 234884480 to level 234884484.
# -03-15 10:18:23.33 spid6s      Database 'master' is upgrading script 'no_op.sql' from level 234884480 to level 234884484.
# -03-15 10:18:23.33 spid6s      -----------------------------------------
# -03-15 10:18:23.33 spid6s      Starting execution of dummy.sql
# -03-15 10:18:23.33 spid6s      -----------------------------------------
# -03-15 10:18:23.34 spid6s      Database 'master' is upgrading script 'repl_upgrade.sql' from level 234884480 to level 234884484.
# -03-15 10:18:23.34 spid6s      Executing replication upgrade scripts.
# -03-15 10:18:23.49 spid6s      Attempting to load library 'xpstar.dll' into memory. This is an informational message only. No user action is required.
# -03-15 10:18:23.53 spid6s      Using 'xpstar.dll' version '2017.140.3460' to execute extended stored procedure 'xp_instance_regread'. This is an informational message only; no user action is required.
# -03-15 10:18:23.53 spid6s      Executing sp_vupgrade_replication.
# -03-15 10:18:23.57 spid6s      DBCC execution completed. If DBCC printed error messages, contact your system administrator.
# -03-15 10:18:23.93 spid6s      Starting up database 'SomeDatabase1'.
# -03-15 10:18:23.96 Logon       Error: 18401, Severity: 14, State: 1.
# -03-15 10:18:23.96 Logon       Login failed for user 'sa'. Reason: Server is in script upgrade mode. Only administrator can connect at this time. [CLIENT: 127.0.0.1]
# Waiting for sys.databases query to return 4 or more rows
# -03-15 10:18:24.04 spid6s      Parallel redo is started for database 'SomeDatabase1' with worker pool size [1].
# -03-15 10:18:24.07 spid6s      Parallel redo is shutdown for database 'SomeDatabase1' with worker pool size [1].
# -03-15 10:18:24.15 spid6s      Synchronize Database 'SomeDatabase1' (6) with Resource Database.
# -03-15 10:18:24.19 spid6s      Starting up database 'SomeDatabase2'.
# -03-15 10:18:24.33 spid6s      Parallel redo is started for database 'SomeDatabase2' with worker pool size [1].
# -03-15 10:18:24.75 spid6s      Parallel redo is shutdown for database 'SomeDatabase2' with worker pool size [1].
# -03-15 10:18:24.87 spid6s      Synchronize Database 'SomeDatabase2' (7) with Resource Database.
# ...
# -03-15 10:19:25.75 spid6s      The Utility MDW does not exist on this instance.
# -03-15 10:19:25.75 spid6s      User 'sa' is changing database script level entry 15 to a value of 500.
# -03-15 10:19:25.76 spid6s      Skipping the execution of instmdw.sql.
# -03-15 10:19:25.76 spid6s      ------------------------------------------------------
# -03-15 10:19:25.76 spid6s      execution of UPGRADE_UCP_CMDW_DISCOVERY.SQL completed
# -03-15 10:19:25.76 spid6s      ------------------------------------------------------
# -03-15 10:19:25.84 spid6s      Database 'master' is upgrading script 'ssis_discovery' from level 234884480 to level 234884484.
# -03-15 10:19:25.84 spid6s      ------------------------------------------------------
# -03-15 10:19:25.85 spid6s      Starting execution of SSIS_DISCOVERY.SQL
# -03-15 10:19:25.85 spid6s      ------------------------------------------------------
# -03-15 10:19:25.88 spid6s      Database SSISDB does not exist in current SQL Server instance
# -03-15 10:19:25.88 spid6s      User 'sa' is changing database script level entry 17 to a value of 500.
# -03-15 10:19:25.88 spid6s      Database SSISDB could not be upgraded successfully.
# -03-15 10:19:25.88 spid6s      ------------------------------------------------------
# -03-15 10:19:25.89 spid6s      Execution of SSIS_DISCOVERY.SQL completed
# -03-15 10:19:25.89 spid6s      ------------------------------------------------------
# -03-15 10:19:25.97 spid6s      Database 'master' is upgrading script 'SSIS_hotfix_install.sql' from level 234884480 to level 234884484.
# -03-15 10:19:26.00 spid6s      ------------------------------------------------------
# -03-15 10:19:26.00 spid6s      Starting execution of SSIS_HOTFIX_INSTALL.SQL
# -03-15 10:19:26.01 spid6s      ------------------------------------------------------
# -03-15 10:19:26.01 spid6s      Database SSISDB does not exist in current SQL Server instance
# -03-15 10:19:26.01 spid6s      ------------------------------------------------------
# -03-15 10:19:26.01 spid6s      Execution of SSIS_HOTFIX_INSTALL.SQL completed
# -03-15 10:19:26.01 spid6s      ------------------------------------------------------
# -03-15 10:19:26.01 spid6s      Database 'master' is upgrading script 'provision_ceipsvc_account.sql' from level 234884480 to level 234884484.
# -03-15 10:19:26.02 spid6s      ------------------------------------------------------
# -03-15 10:19:26.02 spid6s      Start provisioning of CEIPService Login
# -03-15 10:19:26.02 spid6s      ------------------------------------------------------
# -03-15 10:19:26.03 spid6s      Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.03 spid6s      Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.05 spid6s      Configuration option 'Agent XPs' changed from 0 to 1. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.05 spid6s      Configuration option 'Agent XPs' changed from 0 to 1. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.06 spid6s      Configuration option 'Agent XPs' changed from 1 to 0. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.06 spid6s      Configuration option 'Agent XPs' changed from 1 to 0. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.06 spid6s      Configuration option 'show advanced options' changed from 1 to 0. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.07 spid6s      Configuration option 'show advanced options' changed from 1 to 0. Run the RECONFIGURE statement to install.
# -03-15 10:19:26.07 spid6s      ------------------------------------------------------
# -03-15 10:19:26.07 spid6s      Ending provisioning of CEIPLoginName.
# -03-15 10:19:26.08 spid6s      ------------------------------------------------------
# -03-15 10:19:26.08 spid6s      SQL Server is now ready for client connections. This is an informational message; no user action is required.
# -03-15 10:19:26.08 spid6s      Recovery is complete. This is an informational message only. No user action is required.
# ========================================================================
# Database ready for initialization
# ========================================================================
# Processing create_login_and_user.sql
# ...


# So starting with termination enabled but, selectively turning off later on.
set -euo pipefail

# /opt/mssql/bin/sqlservr ought to match the CMD from the upstream docker image, e.g.
#
# $ docker inspect mcr.microsoft.com/mssql/server:2017-latest | jq '.[0].Config.Cmd'
# [
#   "/opt/mssql/bin/sqlservr"
# ]
# $

function wait_for_server_ready() {
        local rows_affected=0

        # Sql server has 4 system database, so when they are connected and
        # created, SQL server can be assumed to be running and working as
        # expected. Example output from sqlcmd:

        #name
        #--------------------------------------------------------------------------------------------------------------------------------
        #master
        #tempdb
        #model
        #msdb
        #some_other_database_001
        #some_other_database_002
        #some_other_database_003
        #some_other_database_004
        #some_other_database_005
        #
        #(9 rows affected)
        while [[ rows_affected -lt 4 ]]
        do
                echo "Waiting for sys.databases query to return 4 or more rows"
                sleep 1
                set +o pipefail # Turn off termination for sqlcmd failures, see earlier comments.
                rows_affected=$(/opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U sa -P "${MSSQL_SA_PASSWORD}" -Q 'SELECT name FROM sys.databases' 2>/dev/null | sed -n 's/(//; s/ rows affected.*//p;')
                set -o pipefail
        done
}

function process_init_scripts() {
        local old_pwd=$PWD
        for dir in "$@"
        do
                cd "$dir" || { echo "$0; Error: unable to cd to $dir" 1>&2; exit 1;}
                for file in *.sql
                do
                        case "$file" in
                                "*.sql")
                                        echo "No *.sql files in $dir."
                                        ;;
                                *)
                                        echo "Processing $file"
                                        /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U sa -P "${MSSQL_SA_PASSWORD}" -d master -i "$file"
                                        sync
                                        ;;
                        esac
                done
        done
        cd "$old_pwd"
}

echo "Starting SQL-Server on 127.0.0.1"
# Ignoring output from mssql-conf since it will complain
#   SQL Server needs to be restarted in order to apply this setting. Please run
#   'systemctl restart mssql-server.service'.
# which is not an issue here in this script.
/opt/mssql/bin/mssql-conf set network.ipaddress 127.0.0.1 > /dev/null
/opt/mssql/bin/sqlservr &
pid=$!

wait_for_server_ready
echo "========================================================================"
echo "Database ready for initialization"
echo "========================================================================"
process_init_scripts /docker-entrypoint-initdb.d

sync

echo "Setup finished. Stopping SQL-Server..."
kill "$pid"
wait "$pid"

sync
sleep 1

echo "Starting SQL-Server on 0.0.0.0"
/opt/mssql/bin/mssql-conf set network.ipaddress 0.0.0.0 > /dev/null

# NB NB The last (long running) command should always be started through exec, see
# https://stackoverflow.com/questions/39082768/what-does-set-e-and-exec-do-for-docker-entrypoint-scripts and
# https://stackoverflow.com/questions/32255814/what-purpose-does-using-exec-in-docker-entrypoint-scripts-serve
# for details.
exec /opt/mssql/bin/sqlservr

@waqas-syed
Copy link

Still no updates? This is turning into an irony now!

@stuartpa
Copy link

Does:

apt-get install sqlcmd
sqlcmd create mssql --accept-eula --user-database foo
sqlcmd query "SELECT DB_NAME()"

Help with this scenario?

https://aka.ms/sqlcmd

@bartelink
Copy link

@stuartpa The point is that every other similar image has a way to request the creation of a database in a declarative manner.
It's the need to have a separated step (and being able to trust that it's been done) that's the problem.
Nobody is suggesting that the individual step is in any way hard (though your wiring happens to be OS-specific).

@stuartpa
Copy link

wiring happens to be OS-specific).

I'm not tracking what is OS-specific, can you flesh this out a bit more.

@bartelink
Copy link

bartelink commented Mar 30, 2023

@stuartpa Just saying that I'm not disputing that your scripting will work (create a database), but it does have a dependency on a specific environment and permissions, i.e. if the container simply did it, one would not need to have something that has apt-get (and the associated required permissions) in the context of the specific consumption scenario.

The table in #800 summarises the situation well

Perhaps you can flesh out what you're hoping to accomplish with your suggestion? e.g. in my suggestion, I have a command thats functionally equivalent, leaning on the container's contents, instead of assuming we want/can install a package - but I am calling out that this is pretty useless as it is not integrated, and as a result I have to maintain special case documentation

(Happy to remove this and my preceding message from the thread if we can agree that the point was the integration, not how one might do the step that people want/need/expect to be integrated into the container image)

@fardarter
Copy link

wiring happens to be OS-specific).

I'm not tracking what is OS-specific, can you flesh this out a bit more.

The issue is I don't want to script it out, I just want to pass a file for the container to understand. I can script it out, but I can write assembly too and don't want to.

Every other DB container has this feature. It's entirely possible.

MS simply doesn't care.

@tracker1
Copy link

I don't have a stake in one direction or another... but the container really should have the options to use/specify environment variables to create a database with a non-sa user that has full access only for that database. This would align closer to other Database containers.

@vbueb
Copy link

vbueb commented Aug 18, 2023

A workaround using docker-compose :

version: "3"
services:
  db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    ports:
      - "1433:1433"
    environment:
      ACCEPT_EULA: y
      MSSQL_SA_PASSWORD: 01pass_WORD
  db-init:
    image: mcr.microsoft.com/mssql/server:2022-latest
    network_mode: service:db
    command: bash -c 'until /opt/mssql-tools/bin/sqlcmd -U sa -P 01pass_WORD -Q "CREATE DATABASE mydb"; do echo retry && sleep 1; done'
    depends_on:
      - db

Here we do not use an arbitrary sleep timeout, we loop until the sql command ends up in success (and wait 1s between retries).

@LadislavBohm
Copy link

Just another version of what @vbueb wrote that waits for db to properly start and executes all sql scripts in certain directory. It also exits because I believe that db-init contain does not need to keep running after db has been setup:

  db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    restart: always
    ports:
      - "1433:1433"
    environment:
      ACCEPT_EULA: y
      SA_PASSWORD: $SA_PASSWORD
    healthcheck:
      test:
        [
          "CMD",
          "/opt/mssql-tools/bin/sqlcmd",
          "-U",
          "sa",
          "-P",
          "$SA_PASSWORD",
          "-Q",
          "SELECT 1",
        ]
      interval: 10s
      retries: 5
      start_period: 20s
  db-init:
    image: mcr.microsoft.com/mssql/server:2022-latest
    network_mode: service:db
    command: >
      bash -c '
        for file in ./sql-scripts/*.sql; do
          echo "Executing SQL file $$file"
          until /opt/mssql-tools/bin/sqlcmd -U sa -P $SA_PASSWORD -i "$$file" > /dev/null; do
            echo "Retry SQL execution for $$file"
            sleep 1
          done
        done
        exit 0
      '
    volumes:
      - ./sql-scripts:/sql-scripts
    depends_on:
      db:
        condition: service_healthy

Setup above executes all scripts inside sql-scripts directory after sqlserver becomes active.

If you want to execute another service after db init has finished a simple setup like this worked fine for me:

  api:
    build:
      context: ../
      dockerfile: ./someapi/Dockerfile
    ports:
      - "8080:80"
    environment:
      ConnectionStrings:MyDatabase: "Server=db;Database=MyDatabase;User Id=sa;Password=$SA_PASSWORD;"
    depends_on:
      db-init:
        condition: service_completed_successfully

@LeeRoyManea
Copy link

+1

@ravensorb
Copy link

Four years and no movement? Pretty much all of the other db systems out there support something like this - would be great to see sqlserver support it as well.

@james-d-elliott
Copy link

services:
  mssql:
    image: 'mcr.microsoft.com/mssql/server:2022-latest'
    environment:
      ACCEPT_EULA: 'y'
      MSSQL_SA_PASSWORD: 'example_complex_password'
      MSSQL_DB: 'database_name'
      MSSQL_USER: 'user_name'
      MSSQL_PASSWORD: 'example_complex_password'

The above works. As long as the passwords are complex enough this will setup the database and create a user with CONTROL.

@PureKrome
Copy link

@james-d-elliott is that documented anywhere? I'm guessing you mean the MSSQL_DB env var

@james-d-elliott
Copy link

james-d-elliott commented Apr 19, 2025

Not sure if it is, it probably isn't if I had to guess.

I just used docker inspect to find the entrypoint and command, and checked to see what they do. Also I believe for it to work you need _DB, _USER, and _PASSWORD. I would consider the provided env vars the minimum for CI purposes.

@bartelink
Copy link

This MS table mentions MSSQL_SA_PASSWORD but nothing else.

If anyone is home around here, there is a specific issue tracking supporting these: #800. Googling turns up this fork that seemingly implements it?

If anyone comes back up out of the rabbit hole and can confirm/deny, I'll be applying it to my best effort

@james-d-elliott
Copy link

james-d-elliott commented Apr 19, 2025

I mean it's fairly easy to confirm just running it. Use docker inspect to see what command and entrypoint is configured, then follow the breadcrumbs:

docker inspect (excerpt, passwords are test passwords):

[
    {
        "Path": "/opt/mssql/bin/launch_sqlservr.sh",
        "Args": [
            "/opt/mssql/bin/sqlservr"
        ],
        "Platform": "linux",
        "Config": {
            "Env": [
                "ACCEPT_EULA=y",
                "MSSQL_SA_PASSWORD=F5vBTaMQJKxW8T6BbkNh",
                "MSSQL_USER=test",
                "MSSQL_PASSWORD=Yo7TFKSVGog7nhkR28do",
                "MSSQL_DB=test",
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "MSSQL_RPC_PORT=135",
                "CONFIG_EDGE_BUILD=",
                "MSSQL_PID=developer"
            ],
            "Cmd": [
                "/opt/mssql/bin/sqlservr"
            ],
            "Image": "mcr.microsoft.com/mssql/server:2022-latest",
            "WorkingDir": "",
            "Entrypoint": [
                "/opt/mssql/bin/launch_sqlservr.sh"
            ],
        },
    }
]

/opt/mssql/bin/launch_sqlservr.sh:

#!/bin/bash

PERMISSIONS_CHECK_PATH="/opt/mssql/bin/permissions_check.sh"

if [ -x $PERMISSIONS_CHECK_PATH ]; then
    $PERMISSIONS_CHECK_PATH
else
    # This should never happen. A permissions_check.sh script has to exist if a
    # Dockerfile uses launch_sqlservr.sh as ENTRYPOINT
    #
    echo "Unable to run startup permissions check, exiting."
    exit 1
fi

source /opt/mssql/bin/init_custom_setup.sh
if [ $? -ne 0 ]; then
    exit 1
fi

"$@" &
pid="$!"

/opt/mssql/bin/run_custom_setup.sh
if [ $? -ne 0 ]; then
    exit 1
fi

wait $pid

/opt/mssql/bin/init_custom_setup.sh:

#!/bin/bash
#
# This script prepares the custom setup phase that will run after
# the SQL Server process has started.
#
MSSQL_SETUP_SCRIPTS_LOCATION="/mssql-server-setup-scripts.d"

function CheckIfDataDirectoryIsEmpty
{
    local dir="/var/opt/mssql/data"
    if [ ! -d "${dir}" ]; then
        true
    elif [ -z "$(ls -A ${dir})" ]; then
        true
    else
        false
    fi
}

if [ -n "${MSSQL_DB}" ]; then
    if ! CheckIfDataDirectoryIsEmpty; then
        echo "Creation of db $MSSQL_DB was requested, but the data directory is not empty, ignoring."
    else
        if [[ -z "${MSSQL_USER}" && -z "${MSSQL_PASSWORD}" ]] ||
           [[ -n "${MSSQL_USER}" && -n "${MSSQL_PASSWORD}" ]]; then
            export MSSQL_CUSTOM_INIT=true
        else
            echo "Either both MSSQL_USER and MSSQL_PASSWORD must be set together, or none of them."
            exit 1
        fi
    fi
fi

if [ -d "${MSSQL_SETUP_SCRIPTS_LOCATION}" ]; then
    if ! CheckIfDataDirectoryIsEmpty; then
        echo "Custom setup script provided, but the data directory is not empty, ignoring."
    else
        export MSSQL_CUSTOM_INIT=true
        export MSSQL_SETUP_SCRIPTS_LOCATION
    fi
fi

/opt/mssql/bin/run_custom_setup.sh:

#!/bin/bash
#
# This script executes the custom setup phase that runs after the SQL Server process has started.
#

SQLCMD=/opt/mssql-tools18/bin/sqlcmd
if [ ! -x $SQLCMD ]; then
    SQLCMD=/opt/mssql-tools/bin/sqlcmd
	if [ ! -x $SQLCMD ]; then
		echo "sqlcmd not available at $SQLCMD, unable to execute custom setup."
		exit 1
	fi
fi

SQLCMD_SA="$SQLCMD -C -U sa -P $MSSQL_SA_PASSWORD"

function IsSqlServerReady
{
    IS_SERVER_READY_QUERY='SET NOCOUNT ON; Select SUM(state) from sys.databases'
    dbStatus=$($SQLCMD_SA -h -1 -Q "$IS_SERVER_READY_QUERY" 2>/dev/null)
    errCode=$?
    if [[ "$errCode" -eq "0" && "$dbStatus" -eq "0" ]]; then
        return 0
    else
        return 1
    fi
}

if [ -z "$MSSQL_CUSTOM_INIT" ]; then
    exit 0
fi

echo "Waiting for Sql Server to be ready before executing custom setup"
until IsSqlServerReady; do
    sleep 5;
done

if [ -n "$MSSQL_DB" ]; then
    echo "Creating database $MSSQL_DB"
    $SQLCMD_SA -Q "CREATE DATABASE [$MSSQL_DB]"

    if [[ -n $MSSQL_USER && "$MSSQL_USER" != "sa" ]]; then
        echo "Creating login $MSSQL_USER with password defined in MSSQL_PASSWORD environment variable"

        cmd="CREATE LOGIN $MSSQL_USER WITH PASSWORD = '$MSSQL_PASSWORD';"
        cmd+="USE $MSSQL_DB;"
        cmd+="CREATE USER $MSSQL_USER FROM LOGIN $MSSQL_USER;"
        cmd+="GRANT CONTROL to $MSSQL_USER;"
        $SQLCMD_SA -Q "$cmd"
    fi
fi

if [ -n "${MSSQL_SETUP_SCRIPTS_LOCATION}" ]; then
    for file in $MSSQL_SETUP_SCRIPTS_LOCATION/*; do
        echo "Executing custom setup script $file"
        $SQLCMD_SA -i $file
    done
fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests