Skip to content

Commit

Permalink
Performance review (#28)
Browse files Browse the repository at this point in the history
* Remove usage of DBATOOLS for doing backups (performance)
* Improve configuration monitoring logic to avoid parsing if configuration has not changed (performance)
* Replace event viewer monitoring logic with LogMonitor by default (performance)
* Remove powershell-yaml from the images and only support JSON (performance)
* Remove usage of DBATOOLS from SbsMssqlIndexOptimize (performance)
* Update MSSSQL images to 2022 CU14
* Added new MSSQL_AGENT_ENABLED to control state of Sql Server Agent
* Fix for Memory auto-release job not working
* Reduce the amount of server restarts triggered by configuration changes during bootstrap (performance)
* Added integration tests for backup and restore to Azure Blob Storage
  • Loading branch information
david-garcia-garcia committed Jul 28, 2024
1 parent d0abe6b commit ce45480
Show file tree
Hide file tree
Showing 86 changed files with 873 additions and 664 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ Make sure to replace the URL to your private repository in the script, and that

```powershell
# Rename envsettings.ps1.template to envsettings.ps1 and complete build params
# https://github.com/microsoft/mssql-docker/issues/540
$Env:MSSQLINSTALL_ISO_URL = "https://xx.blob.core.windows.net/software/mssql.iso";
$Env:MSSQLINSTALL_CU_URL = "https://xx.blob.core.windows.net/software/cu.exe";
$Env:MSSQLINSTALL_CUFIX_URL = "https://xx.blob.core.windows.net/software/cufix.7z";
$ENV:REGISTRY_PATH = "myregistry.azurecr.io/core/"
$ENV:IMAGE_VERSION = "1.0.32";
$ENV:TESTS_SAS_URL = "https://xx.blob.core.windows.net/mytests";
# Build the images
.\buildall.ps1
Expand Down Expand Up @@ -70,6 +72,10 @@ SQL Server 2022 Analysis Services exposed through HTTP.

See details [here](sqlserver2022as/readme.md).

**SQL Server 2022 Integration Services**

SQL Server Integration Services

## Debugging the powershell code

To debug the powershell code in the different images, you use the helper method import functions:
Expand All @@ -86,12 +92,13 @@ The included azure pipeline integration needs the following variables:

| Name | Description |
| ---------------------- | ------------------------------------------------------------ |
| MSSQLINSTALL_CU_URL | Url to the cumulative update fix package |
| MSSQLINSTALL_CUFIX_URL | Url to the cumulative update installer |
| MSSQLINSTALL_CU_URL | Url to the cumulative update installer |
| MSSQLINSTALL_CUFIX_URL | Url to the cumulative update fix package (https://github.com/microsoft/mssql-docker/issues/540) |
| MSSQLINSTALL_ISO_URL | Url to the MS SQL Server ISO image |
| REGISTRY_USER | Container registry username |
| REGISTRY_PWD | Container registry password |
| REGISTRY_PATH | Container registry URL with prefix, i.e. "myimages.azurecr.io/core" |
| TESTS_SAS_URL | An azure Blob Storage SAS URL, use during testing to verify backup and restore automation to Azure Blob |

The images are tagged in the registry using the branch/tag name of the current build.

Expand Down
3 changes: 3 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ stages:
REGISTRY_PATH: $(REGISTRY_PATH)
IMAGE_VERSION: $(Build.SourceBranchName)
TEMP: $(Agent.TempDirectory)
TESTS_SAS_URL: $(TESTS_SAS_URL)
- pwsh: .\buildall.ps1 -Test
name: run_tests
# Only build if [build] is present
Expand All @@ -50,6 +51,7 @@ stages:
IMAGE_VERSION: $(Build.SourceBranchName)
TESTDIR: $(System.DefaultWorkingDirectory)
TEMP: $(Agent.TempDirectory)
TESTS_SAS_URL: $(TESTS_SAS_URL)
- task: PublishTestResults@2
name: publish_tests_results
condition: and(not(canceled()), not(contains(variables['Build.SourceVersionMessage'], '[notest]')))
Expand Down Expand Up @@ -79,3 +81,4 @@ stages:
REGISTRY_PATH: $(REGISTRY_PATH)
IMAGE_VERSION: $(Build.SourceBranchName)
TEMP: $(Agent.TempDirectory)
TESTS_SAS_URL: $(TESTS_SAS_URL)
2 changes: 1 addition & 1 deletion bootstraptest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function WaitForLog {
Start-Sleep -Seconds 1
$logs = Invoke-Command -Script {
$ErrorActionPreference = "silentlycontinue"
docker logs $containerName --tail 250 2>&1
docker logs $containerName --tail 350 2>&1
} -ErrorAction SilentlyContinue
if ($logs -match $logContains) {
return;
Expand Down
3 changes: 2 additions & 1 deletion buildall.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ param (
[string]$Images = ".*"
)

.\imagenames.ps1
. .\imagenames.ps1
. .\bootstraptest.ps1
. .\importfunctions.ps1

$global:ErrorActionPreference = 'Stop';

Expand Down
3 changes: 2 additions & 1 deletion envsettings.ps1.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ $Env:MSSQLINSTALL_CU_URL = "https://xx.blob.core.windows.net/software/cu.exe";
$Env:MSSQLINSTALL_CUFIX_URL = "https://xx.blob.core.windows.net/software/cufix.7z";
$ENV:REGISTRY_PATH = "myregistry.azurecr.io/core/"
$ENV:IMAGE_VERSION = "1.0.32";
$ENV:BUILD_TEMP = "c:\windows\temp"
$ENV:BUILD_TEMP = "c:\windows\temp"
$ENV:TESTS_SAS_URL = "https://xx.blob.core.windows.net/mybackups"
2 changes: 0 additions & 2 deletions servercore2022/compose-async.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ services:
image: ${IMG_SERVERCORE2022}
environment:
- SBS_DEBUG=True
- SBS_GETWINEVENT=[{LogName:["Application"],ProviderName:"*",Level:[1]},{LogName:["Application"], ProviderName:"SbsContainer", Level:[1,2,3,4]}]
- SBS_GETEVENTLOG=[{LogName:"Application", Source:"*", MinLevel:"Information"}, {LogName:"System", Source:"*", MinLevel:"Warning"}]
- SBS_INITASYNC=True
networks:
- container_default
Expand Down
2 changes: 0 additions & 2 deletions servercore2022/compose-basic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ services:
environment:
- SBS_DEBUG=True
- SBS_CONTAINERTIMEZONE=Alaskan Standard Time
- SBS_GETWINEVENT=[{LogName:["Application"],ProviderName:"*",Level:[1]},{LogName:["Application"], ProviderName:"SbsContainer", Level:[1,2,3,4]}]
- SBS_GETEVENTLOG=[{LogName:"Application", Source:"*", MinLevel:"Information"}, {LogName:"System", Source:"*", MinLevel:"Warning"}]
networks:
- container_default
# Environment completely wiped out on purpose, to test
Expand Down
22 changes: 22 additions & 0 deletions servercore2022/compose-error-sync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
servercore:
stop_grace_period: 40s
build:
context: .
args:
IMG_SERVERCORE2022: ${IMG_SERVERCORE2022}
IMG_SQLSERVER2022AS: ${IMG_SQLSERVER2022AS}
IMG_SQLSERVER2022BASE: ${IMG_SQLSERVER2022BASE}
IMG_SQLSERVER2022K8S: ${IMG_SQLSERVER2022K8S}
image: ${IMG_SERVERCORE2022}
environment:
- SBS_INITASYNC=false
- SBS_TESTERROR=true
- SBS_DEBUG=True
networks:
- container_default
# Environment completely wiped out on purpose, to test
# scripts resiliency to null/empty
networks:
container_default:
external: true
2 changes: 0 additions & 2 deletions servercore2022/compose-error.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ services:
IMG_SQLSERVER2022K8S: ${IMG_SQLSERVER2022K8S}
image: ${IMG_SERVERCORE2022}
environment:
- SBS_GETWINEVENT=[{LogName:["Application"],ProviderName:"*",Level:[1]},{LogName:["Application"], ProviderName:"SbsContainer", Level:[1,2,3,4]}]
- SBS_GETEVENTLOG=[{LogName:"Application", Source:"*", MinLevel:"Information"}, {LogName:"System", Source:"*", MinLevel:"Warning"}]
- SBS_INITASYNC=True
- SBS_TESTERROR=true
- SBS_DEBUG=True
Expand Down
3 changes: 0 additions & 3 deletions servercore2022/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ services:
- SBS_DISABLEAUTOSHUTDOWN=0
# Call these proceses during shutdown
- SBS_SHUTDOWNCLOSEPROCESSES=cmd,powershell,pwsh,logmonitor
# Output in the entrypoint loop
- SBS_GETWINEVENT=[{LogName:["Application"],ProviderName:"*",Level:[1]},{LogName:["Application"], ProviderName:"SbsContainer", Level:[1,2,3,4]}]
- SBS_GETEVENTLOG=[{LogName:"Application", Source:"*", MinLevel:"Information"}, {LogName:"System", Source:"*", MinLevel:"Warning"}]
# Secret key
- SBS_TESTPROTECT_PROTECT=supersecretekey
networks:
Expand Down
15 changes: 7 additions & 8 deletions servercore2022/dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@ FROM mcr.microsoft.com/windows/servercore:ltsc2022

SHELL ["powershell.exe"]

RUN mkdir "c:\LogMonitor"; `
Invoke-WebRequest -Uri "https://github.com/microsoft/windows-container-tools/releases/download/v2.0.2/LogMonitor.exe" -OutFile "C:\LogMonitor\LogMonitor.exe"
RUN $global:ErrorActionPreference = 'Stop'; `
mkdir 'c:\Program Files\LogMonitor'; `
Invoke-WebRequest -Uri "https://github.com/microsoft/windows-container-tools/releases/download/v2.0.2/LogMonitor.exe" -OutFile 'c:\Program Files\LogMonitor\LogMonitor.exe'

# Change the default to something a little bit larger than the default 5s.... 15s
# https://github.com/dotnet/runtime/issues/63709
RUN $global:ErrorActionPreference = 'Stop'; `
reg add hklm\system\currentcontrolset\services\cexecsvc /v ProcessShutdownTimeoutSeconds /t REG_DWORD /d 15; `
reg add hklm\system\currentcontrolset\control /v WaitToKillServiceTimeout /t REG_SZ /d 15000 /f;

# Set shell to PowerShell
# SHELL ["C:\\LogMonitor\\LogMonitor.exe", "powershell.exe"]

COPY "setup\\external" "C:\\setup"
RUN xcopy /E /Y "c:\\setup\\assets" "C:\\"
RUN echo "setup\\external";c:\setup\setup.ps1
Expand All @@ -30,6 +28,7 @@ RUN xcopy /E /Y "c:\\setup\\assets" "C:\\"
RUN echo "setup\\base";c:\setup\setup.ps1
RUN Remove-Item -Path c:\setup -Recurse -Force;

SHELL ["cmd.exe"]
CMD ["powershell.exe", "-File", "C:\\entrypoint\\entrypoint.ps1" ]
#CMD ["C:\\LogMonitor\\LogMonitor.exe", "/CONFIG", "c:\\configmap_logmonitor\\config.json", "powershell.exe", "-File", "C:\\entrypoint\\entrypoint.ps1" ]
# SHELL ["cmd.exe"]
# CMD ["powershell.exe", "-File", "C:\\entrypoint\\entrypoint.ps1" ]

CMD ["c:\\Program Files\\LogMonitor\\LogMonitor.exe", "/CONFIG", "c:\\logmonitor\\config.json", "powershell.exe", "-File", "C:\\entrypoint\\entrypoint.ps1" ]
7 changes: 3 additions & 4 deletions servercore2022/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ This image extends the base Server Core 2022 image with some preinstalled softwa
* Chocolatey ([Chocolatey Software | Chocolatey - The package manager for Windows](https://chocolatey.org/))
* 7zip ([Chocolatey Software | 7-Zip (Install) 23.1.0](https://community.chocolatey.org/packages/7zip.install))
* Nuget package provider for Powershell
* Powershell-yaml ([cloudbase/powershell-yaml: PowerShell CmdLets for YAML format manipulation (github.com)](https://github.com/cloudbase/powershell-yaml))
* Log Source for event viewer "SbsContainer" in the "Application" category
* Enabled Long Path Support through windows registry
* Disable IEEnhancedSecurity through windows reigstry
Expand All @@ -34,7 +33,7 @@ If this is not sufficient, you can use LogMonitor as a replacement
[windows-container-tools/LogMonitor/README.md at main · microsoft/windows-container-tools (github.com)](https://github.com/microsoft/windows-container-tools/blob/main/LogMonitor/README.md)

```powershell
CMD ["C:\\LogMonitor\\LogMonitor.exe", "/CONFIG", "c:\\configmap_logmonitor\\config.json", "powershell.exe", "-File", "C:\\entrypoint\\entrypoint.ps1" ]
CMD ["C:\\LogMonitor\\LogMonitor.exe", "/CONFIG", "c:\\logmonitor\\config.json", "powershell.exe", "-File", "C:\\entrypoint\\entrypoint.ps1" ]
```

The image automatically detects that LogMonitor is the container entrypoint, and will ignore any log fowarding configuration set through SBS_GETEVENTLOG.
Expand Down Expand Up @@ -385,11 +384,11 @@ Relevant locations

| Path | Usage |
| -------------------------------------------------------- | ------------------------------------------------------------ |
| c:\environment.d\**.json|**.yaml | Provide environment variables as a json or yaml file/s |
| c:\environment.d\**.json | Provide environment variables as a json |
| c:\entrypoint\init\ | Path for initialization scripts |
| c:\entrypoint\refreshenv\ | Path for scripts run after the env configuration is refreshed|
| c:\entrypoint\shutdown\ | Path for shutdown scripts |
| c:\logrotate\log-rotate.d\ | Path for log rotation scripts |
| c:\configmap_logmonitor\config.json | Default location for the LogMonitor configuration file. |
| c:\logmonitor\config.json | Default location for the LogMonitor configuration file. |
| c:\ProgramFiles\WindowsPowerShell\Modules\Sbs\Functions\ | Path to custom autoloaded Powershell functions |

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,18 @@ function SbsPrepareEnv {

# Configmaps and files
$configDir = "C:\environment.d";
$mergedConfig = @{}
$confHashes = @()

if (Test-Path $configDir) {

# We make this recursive to allow mounting full configmap without subpaths in K8S
# see https://github.com/Azure/AKS/issues/4309
$confFiles = Get-ChildItem -File -Recurse -Path $configDir -Include *.json, *.yaml, *.yml | `
$confFiles = Get-ChildItem -File -Recurse -Path $configDir -Include *.json | `
Where-object { -not ($_.FullName -match "\\\.") } | `
Sort-Object Name;

foreach ($configFile in $confFiles) {
$fileContent = Get-Content -Path $configFile.FullName -Raw | ConvertFrom-Yaml
foreach ($key in $fileContent.Keys) {
$mergedConfig["$key"] = $fileContent[$key];
}
$confHashes += (Get-FileHash $configFile.FullName -Algorithm SHA1).Hash;
}
}

Expand All @@ -37,15 +34,12 @@ function SbsPrepareEnv {
# We make this recursive to allow mounting full configmap without subpaths in K8S
# see https://github.com/Azure/AKS/issues/4309
$secretFiles = Get-ChildItem -File -Recurse -Path $secretsDir | `
Where-object { -not ($_.FullName -match "\\\.") } | `
Where-object { -not ($_.FullName -match "\\\.") } | `
Sort-Object Name;

# With secrets, every file is a value, and the file name is the secret name
foreach ($secretFile in $secretFiles) {
$fileContent = Get-Content -Path $secretFile.FullName -Raw;
# This TRIM here is just convenience...
# See https://github.com/kubernetes/kubernetes/issues/23404
$mergedConfig["$($secretFile.Name)"] = "$($fileContent)".Trim();
$confHashes += (Get-FileHash $secretFile.FullName -Algorithm SHA1).Hash;
}
}

Expand All @@ -55,8 +49,8 @@ function SbsPrepareEnv {
$currentHash = Get-Content -Path $hashFilePath;
}

$configuration = $mergedConfig | ConvertTo-Json -Depth 50;
$md5Hash = [System.Security.Cryptography.HashAlgorithm]::Create("MD5").ComputeHash([System.Text.Encoding]::UTF8.GetBytes($configuration))
$mergedHashes = -join($confHashes);
$md5Hash = [System.Security.Cryptography.HashAlgorithm]::Create("SHA1").ComputeHash([System.Text.Encoding]::UTF8.GetBytes($mergedHashes));
$md5HashString = [System.BitConverter]::ToString($md5Hash);

# In docker this is confusing because the ENV is gone when restarting containers, but the filesystem inside
Expand All @@ -65,6 +59,26 @@ function SbsPrepareEnv {
return $false;
}

# Time to parse and merge the configuration
$mergedConfig = @{}

foreach ($configFile in $confFiles) {
$fileContent = Get-Content -Path $configFile.FullName -Raw | ConvertFrom-Json
foreach ($key in $fileContent.PSObject.Properties.Name) {
$mergedConfig[$key] = $fileContent.$key
}
}

# With secrets, every file is a value, and the file name is the secret name
foreach ($secretFile in $secretFiles) {
$fileContent = Get-Content -Path $secretFile.FullName -Raw;
# This TRIM here is just convenience...
# See https://github.com/kubernetes/kubernetes/issues/23404
$mergedConfig["$($secretFile.Name)"] = "$($fileContent)".Trim();
}

$configuration = $mergedConfig | ConvertTo-Json -Depth 50;

$configChangeCount = SbsGetEnvInt -name "SBS_CONFIG_CHANGECOUNT" -defaultValue 0
Write-Host "Configuration change count $($configChangeCount)"
$Env:SBS_CONFIG_CHANGECOUNT = ($configChangeCount + 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ Function SbsRunScriptsInDirectory {
[bool]$Async)

if (-not (Test-Path -Path $Path)) {
SbsWriteWarning "Path does not exist: $Path"
SbsWriteWarning "SbsRunScriptsInDirectory Path does not exist: $Path";
return;
}

SbsWriteHost "Running scripts in directory $Path";
SbsWriteHost "SbsRunScriptsInDirectory run scripts in directory $Path";

if ($Async -eq $true) {
# We run this asynchronously for multiple reasons:
Expand Down Expand Up @@ -42,9 +43,7 @@ Function SbsRunScriptsInDirectory {
if ($job.State -eq 'Failed') {
SbsWriteWarning "Found exception while running async entrypoint scripts."
$reason = $job.ChildJobs[0].JobStateInfo.Reason;
$stack = $reason.ErrorRecord.ScriptStackTrace;
$message = $reason.Message;
SbsWriteError "$($message) $($stack)";
SbsWriteException -Exception $reason.ErrorRecord
}

SbsWriteHost "Async init job state $($job.State)"
Expand All @@ -53,11 +52,18 @@ Function SbsRunScriptsInDirectory {
$scripts = Get-ChildItem -Path $Path -Filter *.ps1 | Sort-Object Name;
SbsWriteHost "Running $($scripts.count) init scripts synchronously $(ConvertTo-Json $scripts.Name -Compress)";
Import-Module Sbs;
foreach ($script in $scripts) {
$sw = [System.Diagnostics.Stopwatch]::StartNew();
SbsWriteHost "$($script.Name): START";
& $script.FullName;
SbsWriteHost "$($script.Name): END completed in $($sw.Elapsed.TotalSeconds)s";
try {
foreach ($script in $scripts) {
$sw = [System.Diagnostics.Stopwatch]::StartNew();
SbsWriteHost "$($script.Name): START";
& $script.FullName;
SbsWriteHost "$($script.Name): END completed in $($sw.Elapsed.TotalSeconds)s";
}
}
catch {
# We use this to convert the terminating to a non terminating error,
# so that Error-Action influences startup behaviour the way we expect it to be.
SbsWriteException -Exception $_
}
}
}
Loading

0 comments on commit ce45480

Please sign in to comment.