針對 Linux 上的 SQL Server 使用 SQL 評定 API

適用於:Linux 上的 SQL Server

SQL 評估 API 提供一種機制,用以評估 SQL Server 的配置,以取得最佳實務。 此 API 會搭配規則集提供,其中包含 SQL Server 小組建議的最佳作法。 此規則集會隨著新版本的發行而增強。 這有助於確保您的 SQL Server 設定符合建議的最佳作法。

Microsoft 發佈的規則集可在 GitHub 上取得。 您可以在範例存放庫中檢視整個規則集。

在本文中,請使用 PowerShell 執行 Linux 上的 SQL Server 及容器的 SQL 評估 API。

必要條件

  1. 請確定您在 Linux 上安裝 PowerShell。

  2. 從 PowerShell 資源庫安裝 SqlServer PowerShell 模組 (以 mssql 使用者身分執行)。

    su mssql -c "/usr/bin/pwsh -Command Install-Module SqlServer"
    

設定評估

SQL 評估 API 提供 JSON 格式的輸出。 要設定 SQL 評估 API,請完成以下步驟:

  1. 在你想評估的實例中,建立一個使用 SQL 認證的 SQL Server 評估帳號。 請使用以下 Transact-SQL 腳本建立登入帳號並設定強密碼。 您的密碼應遵循 SQL Server 預設 密碼原則。 依預設,密碼長度必須至少有 8 個字元,並包含下列四種字元組合中其中三種組合的字元:大寫字母、小寫字母、以 10 為底數的數字以及符號。 密碼長度最多可達 128 個字元。 盡可能使用長且複雜的密碼。

    USE [master];
    GO
    
    CREATE LOGIN [assessmentLogin]
        WITH PASSWORD = N'<password>';
    
    GRANT CONTROL SERVER TO [assessmentLogin];
    GO
    

    CONTROL SERVER 權限適用於大多數評估。 不過,有些評估可能需要系統 管理員 權限。 如果你沒有執行這些評估,請使用 CONTROL SERVER 權限。

  2. 儲存連接實例的憑證。 把你之前用的密碼替換 <password> 。

    echo "assessmentLogin" > /var/opt/mssql/secrets/assessment
    echo "<password>" >> /var/opt/mssql/secrets/assessment
    
  3. 確保只有 mssql 使用者可以存取認證,以保護新的評定認證。

    chmod 600 /var/opt/mssql/secrets/assessment
    chown mssql:mssql /var/opt/mssql/secrets/assessment
    

下載評定指令碼

以下範例腳本將使用您在前述步驟中建立的憑證來呼叫 SQL 評估 API。 指令碼會在 /var/opt/mssql/log/assessments 目錄中產生 JSON 格式的輸出。

注意

SQL 評定 API 也可以使用 CSV 和 XML 格式產生輸出。

您可以從 GitHub 下載此指令碼。

您可以將此檔案儲存為 /opt/mssql/bin/runassessment.ps1。

[CmdletBinding()] param ()

$Error.Clear()

# Create output directory if not exists

$outDir = '/var/opt/mssql/log/assessments'
if (-not ( Test-Path $outDir )) { mkdir $outDir }
$outPath = Join-Path $outDir 'assessment-latest'

$errorPath = Join-Path $outDir 'assessment-latest-errors'
if ( Test-Path $errorPath ) { remove-item $errorPath }

function ConvertTo-LogOutput {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        $input
    )
    process {
        switch ($input) {
            { $_ -is [System.Management.Automation.WarningRecord] } {
                $result = @{
                    'TimeStamp' = $(Get-Date).ToString("O");
                    'Warning'   = $_.Message
                }
            }
            default {
                $result = @{
                    'TimeStamp'      = $input.TimeStamp;
                    'Severity'       = $input.Severity;
                    'TargetType'     = $input.TargetType;
                    'ServerName'     = $serverName;
                    'HostName'       = $hostName;
                    'TargetName'     = $input.TargetObject.Name;
                    'TargetPath'     = $input.TargetPath;
                    'CheckId'        = $input.Check.Id;
                    'CheckName'      = $input.Check.DisplayName;
                    'Message'        = $input.Message;
                    'RulesetName'    = $input.Check.OriginName;
                    'RulesetVersion' = $input.Check.OriginVersion.ToString();
                    'HelpLink'       = $input.HelpLink
                }

                if ( $input.TargetType -eq 'Database') {
                    $result['AvailabilityGroup'] = $input.TargetObject.AvailabilityGroupName
                }
            }
        }

        $result
    }
}

function Get-TargetsRecursive {

    [CmdletBinding()]
    Param (
        [Parameter(ValueFromPipeline = $true)]
        [Microsoft.SqlServer.Management.Smo.Server] $server
    )

    $server
    $server.Databases
}

function Get-ConfSetting {
    [CmdletBinding()]
    param (
        $confFile,
        $section,
        $name,
        $defaultValue = $null
    )

    $inSection = $false

    switch -regex -file $confFile {
        "^\s*\[\s*(.+?)\s*\]" {
            $inSection = $matches[1] -eq $section
        }
        "^\s*$($name)\s*=\s*(.+?)\s*$" {
            if ($inSection) {
                return $matches[1]
            }
        }
    }

    return $defaultValue
}

try {
    Write-Verbose "Acquiring credentials"

    $login, $pwd = Get-Content '/var/opt/mssql/secrets/assessment' -Encoding UTF8NoBOM -TotalCount 2
    $securePassword = ConvertTo-SecureString $pwd -AsPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential ($login, $securePassword)
    $securePassword.MakeReadOnly()

    Write-Verbose "Acquired credentials"

    $serverInstance = '.'

    if (Test-Path /var/opt/mssql/mssql.conf) {
        $port = Get-ConfSetting /var/opt/mssql/mssql.conf network tcpport

        if (-not [string]::IsNullOrWhiteSpace($port)) {
            Write-Verbose "Using port $($port)"
            $serverInstance = "$($serverInstance),$($port)"
        }
    }

    # IMPORTANT: If the script is run in trusted environments and there is a prelogin handshake error,
    # add -TrustServerCertificate flag in the commands for $serverName, $hostName and Get-SqlInstance lines below.
    $serverName = (Invoke-SqlCmd -ServerInstance $serverInstance -Credential $credential -Query "SELECT @@SERVERNAME")[0]
    $hostName = (Invoke-SqlCmd -ServerInstance $serverInstance -Credential $credential -Query "SELECT HOST_NAME()")[0]

    # Invoke assessment and store results.
    # Replace 'ConvertTo-Json' with 'ConvertTo-Csv' to change output format.
    # Available output formats: JSON, CSV, XML.
    # Encoding parameter is optional.

    Get-SqlInstance -ServerInstance $serverInstance -Credential $credential -ErrorAction Stop
    | Get-TargetsRecursive
    | ForEach-Object { Write-Verbose "Invoke assessment on $($_.Urn)"; $_ }
    | Invoke-SqlAssessment 3>&1
    | ConvertTo-LogOutput
    | ConvertTo-Json -AsArray
    | Set-Content $outPath -Encoding UTF8NoBOM
}
finally {
    Write-Verbose "Error count: $($Error.Count)"

    if ($Error) {
        $Error
        | ForEach-Object { @{ 'TimeStamp' = $(Get-Date).ToString("O"); 'Message' = $_.ToString() } }
        | ConvertTo-Json -AsArray
        | Set-Content $errorPath -Encoding UTF8NoBOM
    }
}

注意

當您在受信任的環境中執行此指令碼時,如果遇到 prelogin 握手錯誤,請在程式碼中 $hostName、Get-SqlInstance 和 $serverName 這幾行的命令加入 -TrustServerCertificate 旗標。

執行評定

  1. 確保 mssql 使用者擁有腳本並能執行。

    chown mssql:mssql /opt/mssql/bin/runassessment.ps1
    chmod 700 /opt/mssql/bin/runassessment.ps1
    
  2. 建立一個日誌資料夾,並給 mssql 使用者該資料夾的權限。

    mkdir /var/opt/mssql/log/assessments/
    chown mssql:mssql /var/opt/mssql/log/assessments/
    chmod 0700 /var/opt/mssql/log/assessments/
    
  3. 你現在可以以 mssql 使用者身分建立第一份評估。 以此使用者身份執行評估會更安全,尤其是當你自動透過 cron 或 systemd執行後續評估時。

    su mssql -c "pwsh -File /opt/mssql/bin/runassessment.ps1"
    
  4. 指令完成後,會產生 JSON 格式的輸出。 你可以將此輸出用於任何支援解析 JSON 檔案的工具,包括 Visual Studio Code。