Skip to content

Commit

Permalink
Merge pull request docker#450 from sixeyed/master
Browse files Browse the repository at this point in the history
Update Getting Started to Windows 2019
  • Loading branch information
sixeyed authored Feb 6, 2019
2 parents 6b70e30 + f9b8a44 commit 84ac7fa
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 298 deletions.
17 changes: 2 additions & 15 deletions windows/sql-server/Dockerfile.builder
Original file line number Diff line number Diff line change
@@ -1,15 +1,2 @@
# escape=`
FROM microsoft/windowsservercore
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]

RUN Install-PackageProvider -Name chocolatey -RequiredVersion 2.8.5.130 -Force; `
Install-Package -Name microsoft-build-tools -RequiredVersion 15.0.26228.0 -Force; `
Install-Package -Name netfx-4.5.2-devpack -RequiredVersion 4.5.5165101 -Force

RUN Install-Package nuget.commandline -RequiredVersion 3.5.0 -Force; `
& C:\Chocolatey\bin\nuget install Microsoft.Data.Tools.Msbuild -Version 10.0.61026
ENV MSBUILD_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin"
RUN $env:PATH = $env:MSBUILD_PATH + ';' + $env:PATH; `
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine)
FROM microsoft/dotnet-framework:4.7.2-sdk-windowsservercore-ltsc2016
RUN nuget install Microsoft.Data.Tools.Msbuild -Version 10.0.61804.210
27 changes: 21 additions & 6 deletions windows/sql-server/Dockerfile.v1
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,33 @@ FROM dockersamples/assets-db-builder AS builder
WORKDIR C:\src
COPY src\Assets.Database-v1\ .
RUN msbuild Assets.Database.sqlproj `
/p:SQLDBExtensionsRefPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61026\lib\net40" `
/p:SqlServerRedistPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61026\lib\net40"
/p:SQLDBExtensionsRefPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61804.210\lib\net46" `
/p:SqlServerRedistPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61804.210\lib\net46"

# update to latest SqlPackage
FROM microsoft/windowsservercore:ltsc2016 AS sqlpackage
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

ENV download_url="https://download.microsoft.com/download/6/E/4/6E406E38-0A01-4DD1-B85E-6CA7CF79C8F7/EN/x64/DacFramework.msi"

RUN Invoke-WebRequest -Uri $env:download_url -OutFile DacFramework.msi ; `
Start-Process msiexec.exe -ArgumentList '/i', 'DacFramework.msi', '/quiet', '/norestart' -NoNewWindow -Wait; `
Remove-Item -Force DacFramework.msi

# db image
FROM microsoft/mssql-server-windows-express
FROM microsoft/mssql-server-windows-express:2016-sp1
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]

VOLUME C:\database
ENV sa_password D0cker!a8s
COPY --from=sqlpackage ["C:\\Program Files\\Microsoft SQL Server\\140\\DAC", "C:\\Program Files\\Microsoft SQL Server\\140\\DAC"]

ENV ACCEPT_EULA="Y" `
DATA_PATH="C:\database" `
sa_password="D0cker!a8s"

VOLUME ${DATA_PATH}

WORKDIR C:\init
COPY Initialize-Database.ps1 .
CMD ./Initialize-Database.ps1 -sa_password $env:sa_password -Verbose
ENTRYPOINT ["powershell", "./Initialize-Database.ps1"]

COPY --from=builder C:\src\bin\Debug\Assets.Database.dacpac .
27 changes: 21 additions & 6 deletions windows/sql-server/Dockerfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,33 @@ FROM dockersamples/assets-db-builder AS builder
WORKDIR C:\src
COPY src\Assets.Database-v2\ .
RUN msbuild Assets.Database.sqlproj `
/p:SQLDBExtensionsRefPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61026\lib\net40" `
/p:SqlServerRedistPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61026\lib\net40"
/p:SQLDBExtensionsRefPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61804.210\lib\net46" `
/p:SqlServerRedistPath="C:\Microsoft.Data.Tools.Msbuild.10.0.61804.210\lib\net46"

# update to latest SqlPackage
FROM microsoft/windowsservercore:ltsc2016 AS sqlpackage
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

ENV download_url="https://download.microsoft.com/download/6/E/4/6E406E38-0A01-4DD1-B85E-6CA7CF79C8F7/EN/x64/DacFramework.msi"

RUN Invoke-WebRequest -Uri $env:download_url -OutFile DacFramework.msi ; `
Start-Process msiexec.exe -ArgumentList '/i', 'DacFramework.msi', '/quiet', '/norestart' -NoNewWindow -Wait; `
Remove-Item -Force DacFramework.msi

# db image
FROM microsoft/mssql-server-windows-express
FROM microsoft/mssql-server-windows-express:2016-sp1
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]

VOLUME C:\database
ENV sa_password D0cker!a8s
COPY --from=sqlpackage ["C:\\Program Files\\Microsoft SQL Server\\140\\DAC", "C:\\Program Files\\Microsoft SQL Server\\140\\DAC"]

ENV ACCEPT_EULA="Y" `
DATA_PATH="C:\database" `
sa_password="D0cker!a8s"

VOLUME ${DATA_PATH}

WORKDIR C:\init
COPY Initialize-Database.ps1 .
CMD ./Initialize-Database.ps1 -sa_password $env:sa_password -Verbose
ENTRYPOINT ["powershell", "./Initialize-Database.ps1"]

COPY --from=builder C:\src\bin\Debug\Assets.Database.dacpac .
91 changes: 55 additions & 36 deletions windows/sql-server/Initialize-Database.ps1
Original file line number Diff line number Diff line change
@@ -1,47 +1,66 @@
# Adapted from Microsoft's SQL Server Express sample:
# https://github.com/Microsoft/sql-server-samples/blob/master/samples/manage/windows-containers/mssql-server-2016-express-windows/start.ps1

param(
[Parameter(Mandatory=$false)]
[string]$sa_password)
[string] $sa_password = $env:sa_password,
[string] $data_path = $env:data_path,
[string] $TargetServerName = '.\SQLEXPRESS',
[string] $TargetDatabaseName = 'AssetsDB',
[string] $TargetUser = 'sa',
[string] $TargetPassword = $env:sa_password
)

# start the service
Write-Verbose 'Starting SQL Server'
start-service MSSQL`$SQLEXPRESS
if ($TargetDatabaseName -eq '.\SQLEXPRESS') {

if ($sa_password -ne "_") {
Write-Verbose 'Changing SA login credentials'
$sqlcmd = "ALTER LOGIN sa with password='$sa_password'; ALTER LOGIN sa ENABLE;"
Invoke-Sqlcmd -Query $sqlcmd -ServerInstance ".\SQLEXPRESS"
}
# start the service
Write-Verbose 'Starting SQL Server'
Start-Service MSSQL`$SQLEXPRESS

if ($sa_password -ne "_") {
Write-Verbose 'Changing SA login credentials'
$sqlcmd = "ALTER LOGIN sa with password='$sa_password'; ALTER LOGIN sa ENABLE;"
Invoke-SqlCmd -Query $sqlcmd -ServerInstance ".\SQLEXPRESS"
}

# attach data files if they exist:
$mdfPath = 'c:\database\AssetsDB_Primary.mdf'
if ((Test-Path $mdfPath) -eq $true) {
$sqlcmd = "CREATE DATABASE AssetsDB ON (FILENAME = N'$mdfPath')"
$ldfPath = 'c:\database\AssetsDB_Primary.ldf'
$mdfPath = "$data_path\AssetsDB_Primary.mdf"
$ldfPath = "$data_path\AssetsDB_Primary.ldf"

# attach data files if they exist:
if ((Test-Path $mdfPath) -eq $true) {
$sqlcmd = "$sqlcmd, (FILENAME = N'$ldfPath')"
$sqlcmd = "IF DB_ID('AssetsDB') IS NULL BEGIN CREATE DATABASE AssetsDB ON (FILENAME = N'$mdfPath')"
if ((Test-Path $ldfPath) -eq $true) {
$sqlcmd = "$sqlcmd, (FILENAME = N'$ldfPath')"
}
$sqlcmd = "$sqlcmd FOR ATTACH; END"
Write-Verbose 'Data files exist - will attach and upgrade database'
Invoke-Sqlcmd -Query $sqlcmd -ServerInstance ".\SQLEXPRESS"
}
else {
Write-Verbose 'No data files - will create new database'
}
$sqlcmd = "$sqlcmd FOR ATTACH;"
Write-Verbose "Invoke-Sqlcmd -Query $($sqlcmd) -ServerInstance '.\SQLEXPRESS'"
Invoke-Sqlcmd -Query $sqlcmd -ServerInstance ".\SQLEXPRESS"
}

# deploy or upgrade the database:
$SqlPackagePath = 'C:\Program Files (x86)\Microsoft SQL Server\130\DAC\bin\SqlPackage.exe'
$SqlPackagePath = 'C:\Program Files\Microsoft SQL Server\140\DAC\bin\SqlPackage.exe'
& $SqlPackagePath `
/sf:Assets.Database.dacpac `
/a:Script /op:create.sql /p:CommentOutSetVarDeclarations=true `
/tsn:.\SQLEXPRESS /tdn:AssetsDB /tu:sa /tp:$sa_password

$SqlCmdVars = "DatabaseName=AssetsDB", "DefaultFilePrefix=AssetsDB", "DefaultDataPath=c:\database\", "DefaultLogPath=c:\database\"
Invoke-Sqlcmd -InputFile create.sql -Variable $SqlCmdVars -Verbose

# relay SQL event logs to Docker
$lastCheck = (Get-Date).AddSeconds(-2)
while ($true) {
Get-EventLog -LogName Application -Source "MSSQL*" -After $lastCheck | Select-Object TimeGenerated, EntryType, Message
$lastCheck = Get-Date
Start-Sleep -Seconds 2
}
/a:Script /op:deploy.sql /p:CommentOutSetVarDeclarations=true `
/TargetServerName:$TargetServerName /TargetDatabaseName:$TargetDatabaseName `
/TargetUser:$TargetUser /TargetPassword:$TargetPassword

if ($TargetServerName -eq '.\SQLEXPRESS') {
$SqlCmdVars = "DatabaseName=$TargetDatabaseName", "DefaultFilePrefix=$TargetDatabaseName", "DefaultDataPath=$data_path\", "DefaultLogPath=$data_path\"
Invoke-Sqlcmd -InputFile deploy.sql -Variable $SqlCmdVars -Verbose

Write-Verbose "Deployed AssetsDB database, data files at: $data_path"

$lastCheck = (Get-Date).AddSeconds(-2)
while ($true) {
Get-EventLog -LogName Application -Source "MSSQL*" -After $lastCheck | Select-Object TimeGenerated, EntryType, Message
$lastCheck = Get-Date
Start-Sleep -Seconds 2
}
}
else {
$SqlCmdVars = "DatabaseName=$TargetDatabaseName", "DefaultFilePrefix=$TargetDatabaseName", "DefaultDataPath=$data_path\", "DefaultLogPath=$data_path\"
Invoke-Sqlcmd -ServerInstance $TargetServerName -Database $TargetDatabaseName -User $TargetUser -Password $TargetPassword -InputFile deploy.sql -Variable $SqlCmdVars -Verbose

Write-Verbose "Deployed AssetsDB database, data files at: $data_path"
}
22 changes: 12 additions & 10 deletions windows/sql-server/part-3.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@ You now have a Docker image with a SQL schema and deployment script, packaged on
The image can be used in development environments where a fresh database is needed for working on new app features, and you want to easily reset the data to an initial state. In this scenario you don't want to persist data between containers, you want the database container to be disposable:

```Docker
docker container run --detach --name assets-db --publish 1433 dockersamples/assets-db:v1
docker container run --detach --name assets-db --publish 1433:1433 dockersamples/assets-db:v1
```

When the container starts it runs the deployment script, finds that there are no existing database files and creates a new database. You can check that by viewing the logs from the container - you'll see the output from the script:

```
> docker container logs assets-db
...
VERBOSE: Starting SQL Server
VERBOSE: Changing SA login credentials
VERBOSE: No data files - will create new database
Generating publish script for database 'AssetsDB' on server '.\SQLEXPRESS'.
Successfully generated script to file C:\init\deploy.sql.
VERBOSE: Changed database context to 'master'.
VERBOSE: Creating AssetsDB...
VERBOSE: Changed database context to 'AssetsDB'.
VERBOSE: Creating [dbo].[Assets]...
VERBOSE: Creating [dbo].[AssetTypes]...
VERBOSE: Creating [dbo].[Locations]...
VERBOSE: Creating [dbo].[FK_Assets_To_Locations]...
VERBOSE: Creating [dbo].[FK_Assets_To_AssetTypes]...
```

You can connect to the database container using SQL Server Management Studio or any other SQL client. From your Docker machine you need to get the IP address of the container with `docker container inspect`:
Expand Down Expand Up @@ -54,7 +56,7 @@ You can see that when you remove the container, and start a new one with the sam
```PowerShell
docker container rm --force assets-db
docker container run --detach --publish 1433 --name assets-db dockersamples/assets-db:v1
docker container run --detach --publish 1433:1433 --name assets-db dockersamples/assets-db:v1
```

Inspect this container with `docker container inspect` and you'll see it has a new IP address - this is a whole new container. Connect your SQL client, repeat the `SELECT * FROM Assets` query and you'll see the table is empty - the old data was lost when you removed the container, and its volume was removed. The new container starts with a new database.
Expand All @@ -70,7 +72,7 @@ docker container rm --force assets-db
mkdir C:\mssql
docker container run -d -p 1433 --name assets-db --volume C:\mssql:C:\database dockersamples/assets-db:v1
docker container run -d -p 1433:1433 --name assets-db --volume C:\mssql:C:\database dockersamples/assets-db:v1
```

When the container has started, you can verify that the new database is created and the files are written to the host directory by listing the contents on the host:
Expand All @@ -82,16 +84,16 @@ When the container has started, you can verify that the new database is created
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 25/09/2017 16:20 8388608 AssetsDB_Primary.ldf
-a---- 25/09/2017 16:20 8388608 AssetsDB_Primary.mdf
-a---- 10/09/2018 15:13 8388608 AssetsDB_Primary.ldf
-a---- 10/09/2018 15:13 8388608 AssetsDB_Primary.mdf
```

Now you can inspect the container to get its IP address, connect and insert rows into the `Assets` table. The data will be stored outside of the container, in the directory on the host. You can replace the container without changing the schema - say you rebuild it with a new version of the base image to get the latest Windows updates. As long as you use the same volume mapping as the previous container, you'll retain all the data:

```PowerShell
docker container rm -f assets-db
docker container run -d -p 1433 --name assets-db --volume C:\mssql:C:\database dockersamples/assets-db:v1
docker container run -d -p 1433:1433 --name assets-db --volume C:\mssql:C:\database dockersamples/assets-db:v1
```

This is a new container with a new file system, but the database location is mapped to the same host directory as the previous container. The setup script still runs, but it finds no differences in the current database schema and the schema definition in the Dacpac, so there's no diff script to apply.
Expand Down
4 changes: 2 additions & 2 deletions windows/sql-server/part-4.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Now you have two images locally, each packaging a separate version of the databa
```PowerShell
docker container rm -f assets-db
docker container run -d -p 1433 --name assets-db -v C:\mssql:C:\database dockersamples/assets-db:v2
docker container run -d -p 1433:1433 --name assets-db -v C:\mssql:C:\database dockersamples/assets-db:v2
```

When this new container starts, the init script attaches the existing data files and runs `SqlPackage`. Noe the schema is different from the Dacpac, so the tool generates a diff script to apply. Then it runs the script to update the schema - you can see the output in `docker container logs`:
Expand All @@ -46,7 +46,7 @@ VERBOSE: Creating [dbo].[FK_Assets_To_Users]...
The container retains the upgrade script which `SqlPackage` generates, and you can read it from the container to see the exact SQL statements that were used in the upgrade:

```PowerShell
docker container exec assets-db powershell cat C:\init\create.sql
docker container exec assets-db powershell cat C:\init\deploy.sql
```

For the v2 upgrade the script is 150+ lines of SQL, containing the DDL to update the schema, and the DML post-deployment scripts. The DDL includes the table changes and the new table, as in this snippet:
Expand Down
Loading

0 comments on commit 84ac7fa

Please sign in to comment.