65.9K
CodeProject 正在变化。 阅读更多。
Home

SQL Server 数据库 :: 使用 Github、TeamCity 和 Octopus 进行持续部署

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2019 年 10 月 20 日

CPOL

20分钟阅读

viewsIcon

21467

这是关于使用 Github、TeamCity 和 Octopus 为 Microsoft SQL Server 数据库构建 CI/CD 管道的分步指南的第三部分,也是最后一部分。

引言

在我的 上一篇文章中,我们已经了解了如何在拥有源代码控制系统之外,为 Microsoft SQL Server 数据库实现持续集成系统。文章结尾,我们确定持续部署系统对于顺利交付项目中的修改至关重要。

同样,如前一篇文章所述,有几种可用的工具来实现持续部署,但对于本课程,我们将以 Octopus Deploy 为例,学习如何为代码到各种环境的持续交付设置管道。

背景

数据库部署不像应用程序部署那样直接,因为会涉及许多因素,如架构更改、数据更改、数据持久性以及其他杂项因素,例如部署停机时间、对更改的恐惧等。这些是导致许多组织选择坚持手动部署数据库更改的一些复杂性。

但是,通过本教程的学习过程,让我们尝试简化持续交付管道的设置,了解如何减少手动干预并消除潜在错误,并学习如何缓解部署失败。

必备组件

为了继续进行此步骤,您应该准备好数据库项目的持续集成系统。如果您还没有,请参阅我写的上一篇文章。

如果您已成功完成该步骤,让我们继续进行此漫长过程中的下一个也是最后一步。

3. 使用 Github、TeamCity 和 Octopus 实现 SQL Server 数据库持续交付

a. 理解部署流程

在我们继续本课程之前,了解数据库部署过程中涉及的基本步骤非常重要。整个过程大致可分为三个主要步骤:

  • 为数据库中的最新更改创建更改脚本
  • 创建并验证包含数据库更改的工件(NuGet 包或 zip 文件)
  • 将创建的工件发布到不同环境并自动化该过程

b. 设置 Octopus Server

如果您已经在使用 Octopus Deploy 服务器来部署您的应用程序,您可以为您的数据库项目部署在同一服务器上创建另一个项目。如果您没有安装服务器,请从官方网站下载 Octopus Server 和 Octopus Tentacle 并进行安装。Octopus 服务器需要安装在某个合适的位置,以便您可以从 TeamCity 推送已发布的包。请注意,Octopus Tentacle 需要安装在您将要部署数据库的每个服务器上,即测试、预生产、生产等。

与 TeamCity 一样,有很多在线教程可以指导您如何设置 Octopus Server 和 Octopus Tentacle。官方文档包含了关于如何安装这两个组件的详细分步教程。

如果您的安装已完成,您应该会看到 Octopus Manager 和 Octopus Tentacle Manager,它们看起来会有些像这样。

在 Octopus Manager 中,点击链接以浏览 Web 门户。此操作将打开您的浏览器,您应该能看到 Octopus Server 仪表板,您可以在其中配置您的部署过程。

我们首先要做的是为项目交付中的每个阶段设置环境。让我们假设我们的交付中有四个阶段,例如:开发、测试、预生产和生产。我们需要在 Octopus Server 中设置四个环境。在导航栏中,点击 Infrastructure(基础架构)选项卡。

在下一个屏幕上,点击 Add Environments(添加环境)按钮。如果您的屏幕与下图所示不同,请转到 Environments(环境)选项卡并点击 Add Environments(添加环境)按钮。

为环境指定一个适当的名称,然后点击 Save(保存)按钮。

这将为 Development(开发)添加一个部署目标。遵循相同的过程,重复步骤为 Test(测试)、Staging(预生产)和 Production(生产)创建三个环境。

c. 设置 Tentacles(触手)

下一步是为每个环境创建并指定部署目标。由于我们已经在开发、测试、预生产和生产服务器上安装了 Octopus Tentacle,它们将成为我们的部署目标,我们将在那里指定它们。

点击“Add Deployment Target”(添加部署目标)按钮。

在下一页上,选择部署目标的类型。在此示例中,Octopus Tentacle 托管在运行 Windows 的本地计算机上。根据您的部署目标托管的位置进行选择。选择部署目标类型后,系统会要求您选择目标类型。将鼠标悬停在 Listening Tentacle(监听触手)面板上,然后点击 Add(添加)按钮。

在下一个屏幕上,您可以看到触手的安装说明。如果您还没有在部署目标上安装 Tentacle Manager,请下载 tentacle 并安装在那里。此页面显示一个 Thumbprint(指纹),它特定于 Octopus Server。我们在部署目标上创建触手时应提供此指纹,而创建的触手将拥有自己的指纹,我们将在下一步创建部署目标时指定它。是否感到困惑?别担心。我们稍后会回到这里。

现在,复制指纹并打开 Tentacle Manager。在这里,我们创建一个触手以连接 Octopus Server 和开发环境的部署目标。

点击 Tentacles 列表,然后选择 New Tentacle(新建触手)以添加一个新的触手。

接下来,为此实例命名,此处为 Development(开发),然后点击 Next(下一步)。

这将带您进入新创建触手的欢迎屏幕,点击 Get Started(开始)以继续配置。

在下一个屏幕上,选择通信样式为 Listening tentacle(监听触手),然后继续点击 Next(下一步)。

对于存储,请保留默认设置,然后点击 Next(下一步)。

Listening Tentacle(监听触手)步骤中,选择您希望 Tentacle Service 监听的端口。默认值为 10933。在指纹框中,粘贴您从 Octopus Server 仪表板复制的指纹,然后点击 Next(下一步)。此指纹特定于服务器,并且您将创建的所有部署目标触手的指纹都将相同。

在下一步中,点击 Install(安装)按钮,新的触手将被安装并启动 Tentacle Service。

安装完成后,点击 Finish(完成),Tentacle Manager 将显示新创建触手的信息。触手的状态为运行中,如果您注意到,触手有自己的指纹。这特定于此触手,并且每个创建的触手将具有唯一的指纹。

复制此指纹,然后返回 Octopus Server 仪表板,点击 Next(下一步)。

Octopus 会要求为监听触手提供一个显示名称。提供一个合适的名称,设置目标环境和角色。如果您在 Octopus 中还没有创建任何角色,您可以在输入框中键入并创建一个。分配角色,如果您向下滚动,您会看到 Octopus Server 已经填充了监听触手的指纹和 URL。

点击 Save(保存)按钮,然后转到 Infrastructure(基础架构)选项卡。您应该能看到一个新的监听触手已被创建。

重复此过程,为测试、预生产和生产创建部署目标,并将它们设置到各自的环境中。

d. 创建 Octopus 项目

下一步是在 Octopus 中创建一个项目。为此,我们需要在 Octopus 中为我们的项目定义一个部署生命周期。为此,请在导航栏中点击 Library(库),然后转到 Lifecycles(生命周期)选项卡。在这里,您可以添加一个新的生命周期。

为此生命周期提供一个合适的名称和描述,然后保存。

最后一步是在 Octopus 中添加一个新项目,并设置它遵循此部署生命周期。从导航栏,转到 Projects(项目)选项卡,然后点击 Add Project(添加项目)按钮。这将打开一个弹出窗口,要求输入项目名称。输入您的项目名称并保存项目。

这样,您的项目将显示在 Projects(项目)下。

暂时暂停 Octopus 的设置,转而构建 TeamCity 和 Octopus Deploy 之间的管道。

e. 在 TeamCity 和 Octopus 之间创建管道

在此 CI/CD 管道设置中,TeamCity 通常负责检查源代码控制中的更改、编译源代码并创建用于部署的 NuGet 包。这些包将被推送到 Octopus,Octopus 将接收它们并推送到开发、测试、预生产和生产环境。

i. 安装 Octopus Deploy Integration 插件

为了在这两个工具之间创建管道,我们可以使用一个名为 Octopus deploy integration 的 TeamCity 插件。可以从 JetBrains 插件存储库或 Octopus 下载页面获取。我们将在接下来的部分中详细介绍设置,但如果您想了解有关该插件的更多信息,可以访问 Octopus 网站上的官方页面 此处

要从 TeamCity 安装此插件,请打开 TeamCity,点击 Administration(管理),然后在侧边栏中选择 Plugins-List(插件列表)。在出现的页面上,点击 Browse plugins repository(浏览插件存储库)并点击 Proceed(继续)。

这将带您到官方 TeamCity 插件存储库。在此存储库中,搜索名为 Octopus Deploy Integration 的插件,并从搜索列表中选择该项目。

在这里,您可以点击 Get(获取)按钮并将其安装到您的 TeamCity 服务器上。

您应该会返回到 TeamCity,然后可以选择安装该插件。

插件将上传到 TeamCity,需要启用它。启用新上传的插件,并在 TeamCity 请求确认时进行确认。建议在安装插件后重启 TeamCity 服务器。

如果安装成功,您应该能在 External Plugins(外部插件)列表中看到 Octopus Deploy Integration 插件。

ii. 安装 NuGet

由于我们的过程涉及将代码发布为 NuGet 包,因此我们必须在 TeamCity 中启用 NuGet。转到 Administration(管理)->Tools(工具)->Install Tool(安装工具)。

从下拉列表中选择 NuGet.exe,选择最新可用的稳定版本并安装。

如果安装成功,您应该能在 Tools(工具)下看到 NuGet。

iii. 创建 NuGet 规范

要从数据库项目构建 NuGet 包,我们需要在一个 .nuspec 文件中指定包元数据。如果您不知道 nuspec 文件是什么,可以将其视为 NuGet 发布您的包的规范。这是 NuGet 包最重要的组成部分,它是一个带有 .nuspec 扩展名的 XML 文件,代表您的包并包含来自 Nuget.org 的所有信息。

虽然不是必需的,但如果您将 .nuspec 文件包含在项目根目录中,将使事情变得更容易一些。

在项目根文件夹中添加一个名为 <ProjectName>.nuspec 的新文件。

在此 nuspec 文件中,复制并粘贴此代码。

将 [ProjectName]、[YourName] 和 [YourDescription] 替换为您对应的值。它看起来应该像这样。

<files> 部分,请注意其中有两个文件的引用。这意味着我们告诉 NuGet 在打包时包含这两个文件。.dacpac 文件包含我们数据库中所有 SQL Server 对象的定义,而 Deploy.ps1 文件是我们希望 Octopus 在接收包后执行的 PowerShell 脚本。此 PowerShell 脚本中的代码将从 dacpac 创建一个 SQL Server 脚本,并将在 Octopus 服务器上执行它。

向项目添加另一个名为“Deploy.ps1”的文件,并将此脚本粘贴到文件中。

引用
# -------------- 
# Set params
# --------------
 
$BuildName = $OctopusParameters["BuildName"]
$ServerName = $OctopusParameters["ServerName"]
$DatabaseName = $OctopusParameters["DatabaseName"]
$DbUsername = $OctopusParameters["DbUsername"]
$DbPassword = $OctopusParameters["DbPassword"]
 
$ConnectionString = "Server= $ServerName; Database= $DatabaseName; User ID= $DbUsername; Password= $DbPassword"
 
Write-Host "This build will deploy: " $BuildName " to Server: " $ServerName
 
try {
    # Load in DAC DLL (requires config file to support .NET 4.0)
    Add-Type -path "C:Program FilesMicrosoft SQL Serv-er150DACbinMicrosoft.SqlServer.Dac.dll"
 
    # Make DacServices object
    #$d = New-Object Microsoft.SqlServer.Dac.DacServices "Server = $ServerName; 
    Data-base = $DatabaseName; Integrated Security = True;";
    $d = New-Object Microsoft.SqlServer.Dac.DacServices $ConnectionString
 
    # Register events (this will write info messages to the Task Log)
    Register-ObjectEvent -in $d -EventName Message -Source "msg" 
    -Action { Out-Host -in $Event.SourceArgs[1].Message.Message} | Out-Null
 
    # Get dacpac file
    $dacpac = (Get-Location).Path + "Content" + $BuildName + ".dacpac"
    # 'Content' is from the nuget package that is created. So, you cannot see it on the local directory
 
    # Load dacpac from file & deploy to database
    $dp = [Microsoft.SqlServer.Dac.DacPackage]::Load($dacpac)
 
    # Set the DacDeployOptions
    $options = New-Object Microsoft.SqlServer.Dac.DacDeployOptions -Property @{
       'BlockOnPossibleDataLoss' = $true;
       'DropObjectsNotInSource' = $false;
       'ScriptDatabaseOptions' = $true;
    }
 
    Write-Host "Generating deployment script"
 
    # Generate the deployment script
    $deployScriptName = $BuildName + ".sql"
    $deployScript = $d.GenerateDeployScript($dp, $DatabaseName, $options)
 
    # Write the script out to a file
    $deployScript | Out-File $deployScriptName
 
    Write-Host "Deploying dacpac"
    # Deploy the dacpac
    $d.Deploy($dp, $DatabaseName, $true, $options)
 
    # Clean up event
    Unregister-Event -Source "msg"
 
    Write-Host "Successfully deployed"
    exit 0 # Success
}
catch {
    Write-Host ($_ | ConvertTo-Json)
     
    # Called on terminating error. $_ will contain details
    exit 1 # Failure
}

Deploy.ps1 的属性中,将“Copy to Output Directory”(复制到输出目录)设置为“Copy always”(始终复制)或“Copy if newer”(仅当更新时复制),因为我们希望在脚本发生更改时,这些更改能够进入已发布的包。在顶部的变量声明中,将项目名称更改为您 Octopus 项目的名称。我们这样做是为了避免为每个环境使用不同的部署脚本。我们可以在 Octopus 中设置变量并从中读取值。我们将在后面的部分详细介绍变量的创建。在第 17 行,更改 Octopus 运行的服务器上 Microsoft.SqlServer.Dac.dll 位置的路径。如果您找不到该文件,则需要下载并安装 sqlpackage

进行更改后,将新创建的两个文件(.nuspec 文件和 Deploy.ps1)添加到源代码控制中并签入代码。这应该会触发 TeamCity 中的构建。

现在,让我们继续在 TeamCity 中添加构建步骤,以从我们创建的 .nuspec 文件构建 NuGet 包。

iv. 在 TeamCity 中添加构建步骤

我们现在应该在 TeamCity 的构建过程中添加几个步骤。一个用于从我们的数据库/SSDT 项目创建 NuGet 包,另一个用于将构建的 NuGet 包推送到 Octopus。为此,让我们编辑项目的构建设置。转到 Projects(项目),将鼠标悬停在您的构建旁边的插入符号上。从下拉菜单中,选择 Edit Settings(编辑设置)。

选择 Build Step(构建步骤),然后点击 Add build step(添加构建步骤)按钮。

选择运行器类型为 NuGet Pack(NuGet 打包),并为构建步骤命名。在包管理器下,我们需要指定要用于构建包的规范文件。从目录结构中,选择我们在上一步中创建的 nuspec 文件。

指定要发布工件的目录。您也可以将其保留为默认值。选中“Publish created packages to build artifacts”(将创建的包发布到构建工件)复选框,然后点击 Save(保存)。

此步骤的实际意义是,每当 TeamCity 执行构建时,项目将被编译成一个包含 NuGet 包的工件,该工件可以推送到 Octopus。让我们验证一下它是否正常工作。转到 Projects(项目),然后点击您的构建步骤旁边的 Deploy(部署)按钮。这将重新构建您的代码。

构建完成后,您可以看到工件图标已高亮显示。到目前为止,图标的颜色是浅的,因为 TeamCity 没有构建任何工件,但由于我们有一个 NuGet 包,图标的颜色变深了,如果您将鼠标悬停在图标上,它将显示工件中可用的所有文件和文件夹。

您可以看到 Content 文件夹中创建了一个 dacpac,并且部署脚本(Deploy.ps1)也在包中。该包已准备好移至 Octopus,在那里您可以创建发布并将其自动化部署到各种目标。

为了实现这一点,我们需要在 TeamCity 中添加另一个构建步骤。在此之前,我们需要从 Octopus 获取一个 API 密钥。返回 Octopus Server Web 门户,点击页面右上角的用户名称。点击 Profile(个人资料),然后在下一页转到 My API Keys(我的 API 密钥),然后点击 New API Key(新建 API 密钥)。

提及适当的用途,然后点击 Generate New(生成新密钥)按钮。

复制您的 API 密钥,然后再次转到 TeamCity 门户。

添加一个具有以下配置的新构建步骤。

将运行器类型设置为 OctopusDeploy: Push Packages(OctopusDeploy:推送包),为该步骤命名,并提供到 Octopus Server 的凭据。粘贴上一步生成的 API 密钥。在包路径中,让我们设置一个模式,这样每当有新构建时,只有最新的构建包将被推送到 Octopus 库。

在这种情况下,包路径模式指示 TeamCity 从输出文件夹(即我们在上一个构建步骤中提到的 nuget 文件夹)中选择最新的 nupkg 文件。如果您在创建 NuGet 规范时指定了不同的路径,请确保您的路径指向正确。

此外,点击 Show Advanced Settings(显示高级设置)链接,并选中 Publish packages as build artifacts(将包发布为构建工件)旁边的复选框,如果您想替换具有相同名称的现有包,则可以更改覆盖模式。

保存设置,现在您应该能看到一个新的构建步骤已被添加。

通过此步骤,TeamCity 和 Octopus 之间的管道已设置完毕,可将项目构建成 NuGet 包并将其推送到 Octopus。让我们测试一下它是否有效。

转到 TeamCity,点击 Deploy(部署)按钮。

如果构建成功,您应该能在 Octopus 包库中看到已编译的 NuGet 包。要验证,请转到 Octopus->Library(库)->Packages(包)。这里是 TeamCity 推送的最新包。

因此,我们的代码在没有任何手动干预的情况下被推送到 Octopus。剩下的工作是自动创建发布并将其部署到各种环境。

f. 在 Octopus 中配置变量

在继续之前,还有一项配置需要完成。在 Deploy.ps1 脚本中,我们编写了代码,以便从 Octopus 本身获取服务器凭据,这样我们就可以为所有环境使用相同的脚本。我们现在需要做的是在 Octopus 中创建变量,并为不同环境分配不同的值。

在 Octopus 中,转到 Projects(项目),选择您的项目,然后转到 Variables(变量)。开始在 Enter new variable(输入新变量)文本框中键入,并添加这五个变量:

  • BuildName
  • ServerName
  • DatabaseName
  • DbUsername
  • DbPassword

为每个变量输入值,并为该值设置有效范围。您可以使用相同的值用于所有环境(或者)您可能为每个环境为一个变量添加不同的值。

保存以更新详细信息。通过这样做,我们避免了为不同环境使用不同的部署脚本/凭据的需要。现在所有环境都使用相同的脚本。

g. 在 Octopus 中定义部署过程

在同一个选项卡中,转到 Process(过程)部分,然后点击 Add Step(添加步骤)按钮。

在随后的窗口中,选择包作为步骤模板,然后从已安装的步骤模板中选择 Deploy a Package(部署包)。

为此步骤命名,并为该部署步骤分配目标角色。

在包详细信息下,我们指定了 Octopus 需要从 NuGet 库中提取的包的 ID。在此处输入您的项目名称,将其他所有内容保留为默认值,然后保存您的配置。

一个步骤已添加到部署过程中,我们可以继续了。

h. 自动化发布

接下来我们需要做的是,每当 Octopus 包库中出现新包时,自动创建发布。我们可以通过在我们的项目中创建触发器来实现。

在同一个选项卡中,切换到 Trigger(触发器),然后在 Automatic Release Creation(自动创建发布)下点击 Setup(设置)按钮。在包步骤下拉菜单中,选择您刚刚创建的包,然后点击 Save(保存)按钮。

我们还应该创建一个触发器,以便在有可供发布的包时触发部署。在同一个选项卡中,点击 Add Trigger(添加触发器),然后在下拉菜单中选择 Deployment Target Trigger(部署目标触发器)。

设置名称,对于事件过滤器,选择 Machine becomes available for deployment(机器可用于部署)。这将选择保持部署目标更新所需的所有必要事件。

保存触发器。

i. 测试部署管道

转到 TeamCity,点击项目构建步骤的 Deploy(部署)按钮。

切换到 Octopus Web 门户,然后点击您的项目。惊喜,惊喜!有一个可供部署到开发环境的发布。

如果点击 Deploy(部署)按钮,您的数据库将被部署到开发服务器。我们几乎完成了,但理想情况下,您不希望每次签入代码时都手动点击按钮。是吗?

让我们来看看如何进一步自动化此过程。

j. 自动化部署到开发环境

要自动化所有新发布的部署,我们需要在 Octopus 的部署生命周期中添加一个阶段。

在 Web 门户上,转到 Library(库)->Lifecycles(生命周期),然后点击您在设置 Octopus 服务器早期阶段创建的部署生命周期。

在部署生命周期下的 Phases(阶段)部分,点击 Add Phase(添加阶段)按钮。为此阶段指定一个名称。

向下滚动并点击 Add Environment(添加环境),然后在弹出窗口中,选择您希望新发布自动部署到的环境。在这种情况下,我们希望将发布部署到开发环境。

选中“Deploy automatically to this environment as soon as the release enters this phase”(发布一进入此阶段即自动部署到此环境)复选框,然后点击 OK(确定)。这是为我们实现神奇效果的设置。我们还需要添加其他环境,并设置是手动部署发布,还是需要手动干预才能将部署从一个环境迁移到另一个环境。在实际项目中,理想情况下,质量保证团队将在完成所有质量检查后,将部署从一个阶段移动到下一个阶段。因此,我们将所有其他环境的部署设置为手动排队。

保存您对部署生命周期所做的更改。

让我们测试一下该过程是否有效。转到 TeamCity,然后点击 Deploy(部署)。等待构建过程完成并将包推送到 Octopus。

切换到 Octopus 门户,然后……

万岁!

我们的数据库已成功部署。就是这样。管道已完全设置。

满足用例

到目前为止,我们已经进行了大量的安装、配置和一些编码。我们的努力有什么成果?进行如此长的过程是否值得?

回顾我们最初定义的用例,既然系统已经设置好,如果我们对代码进行微小更改并签入我们的 Github 存储库,项目应该会在 TeamCity 中自动构建,并且数据库应该由 Octopus 自动部署到服务器上。然后,它应该可以迁移到后续阶段。我们真的实现它了吗?让我们看看。

更改项目中的某些内容。例如,添加一个新表并签入代码。

稍等片刻,然后检查您的数据库服务器。

新表就在那里。请记住,我们只是签入了代码。正如我们之前所做的那样,我们既没有在 Visual Studio 中构建项目,也没有发布它。这只是一个简单的签入,代码就自动部署到了服务器上。

在 TeamCity 中,代码已检查,并且源代码控制包含了您团队中所有开发人员的所有更改历史记录。

结论

啊!教程结束了。

现在,只需编写代码并签入,它就可以轻松地从一个阶段迁移到另一个阶段,只需点击一个按钮即可。如果您曾经在执行数据库更改脚本进行部署时因手动错误而陷入噩梦,那么您将理解本课程的学习过程有多么富有成效。

关注点

互联网上有许多关于为 Web 应用程序创建 CICD 管道的教程,但很少看到关于如何为数据库完成此操作的文章。即使您找到了,它们也非常旧,而且过程中涉及的一些方法令人困惑,不够完全自动化,也无法扩展。

本课程通过演示最简单的方法来制作,可能是关于 SQL Server 数据库的源代码控制、持续集成和持续部署主题的最全面的指南。整个指南/课程/教程被分解为多个步骤,并在每个可能的步骤中都提供了截图。

最后,我仍然想强调,这是对您在实际组织中将遇到的场景的简化。会有许多因素需要考虑,例如为每个环境使用不同的 Docker 容器,需要使用 VPN/代理才能访问数据库服务器,根据用户角色限制对部署的访问权限等。尽管基础架构可能变得复杂,但创建管道的方法仍然相同。您可以在相应的层中配置这些设置。我敢肯定,您会弄清楚的。

感谢您的阅读。希望您学到了很多,祝您开发愉快,部署顺利!

历史

  • 2019 年 10 月 20 日:本文初稿
© . All rights reserved.