如何通过Azure CI / CD部署SQL脚本?

问题描述 投票:0回答:1

我们有一堆SQL脚本(.sql文件),我们手动将其从一个服务器部署到另一个服务器。

所有SQL脚本都通过Azure中的SQL Project进行管理。

如何通过Azure CI / CD部署SQL脚本?

sql-server azure-devops
1个回答
1
投票

管理数据库模式以及如何在环境中进行升级应同等考虑应用程序和基础架构部署。这是一些高级指南。

  1. 源代码管理 - 您需要将脚本放在源代码管理中。如果您使用的是Azure DevOps,请使用Git存储库来存储生成的所有脚本。此外,我们在源代码控制中需要它们,因此我们的CI / CD工具可以实现它。如果你是一名DBA,这听起来很怪异,我很抱歉,你必须习惯它。 1B。启用Pull请求 - 将源存储库配置为仅接受来自pull-request的更改。这可确保在将架构更改接受到存储库之前对其进行审核。改善团队的知识共享并提高整体质量,因为它可以在部署之前发现错误。
  2. 安全性 - 锁定数据库,以便随机用户无法部署随机更改。创建专用帐户以应用数据库架构更改,并仅向Continous Delivery Tool提供凭据。在此模型下,如果它不在源代码管理中,则它不存在。我们的CI / CD工具将负责为我们部署这些更改。
  3. 使用工具 - 并手动停止!我们的团队决定使用名为db-migrate的开源框架来管理数据库模式的更改。我们之所以选择db-migrate,是因为它是开源的,可以在许多不同的平台上运行。 Microsoft使用EntityFramework Code-First Migrations,db-migrate基于。 迁移的工作原理:基本上,每次需要修改数据库时,都会创建一个包含SQL脚本更改的“迁移”。当工具针对您的数据库运行时,它会在数据库中创建一个表,以跟踪先前运行的迁移,因此它只运行任何新的迁移。简而言之,迁移应该是非破坏性的,以防止数据丢失,并且一旦脚本应用于任何数据库,脚本应被视为只读。 (在使用它之后,不应该更改迁移sql脚本;而是创建一个新的迁移)
  4. 持续集成 - 每次将新迁移检入源代码管理时,CI服务器都会将脚本打包为下一阶段的工件。
  5. 持续交付 - 持续交付系统获取构建工件并针对每个目标环境运行db-migrate工具(node.js)。 CD工具使用允许进行数据库架构更改的专用SQL用户帐户。如#2所示,这应该是部署更改的唯一方法。

更新:使用实体框架

从上面列出的方法可以看出,我显然非常有兴趣将数据库架构更改限制在特定用户帐户,以防止使用具有不受限制访问权限的用户帐户意外部署应用程序。您的里程可能会有所不同,但您可以使用以下几种方法:

  1. 使用migrate.exe执行迁移 - 此工具随EntityFramework一起提供,可以将您的代码优先迁移作为部署步骤调用。这与我上面使用db-migrate的方式非常相似。
  2. 在应用程序启动期间编写迁移脚本 - 您可以在Web应用程序初始化逻辑中将代码编写到perform any outstanding migrations。这可能是最容易实现的,但要求您使用具有不受限制访问权限的数据库帐户运行应用程序。此外,如果数据库迁移出现问题,则在部署应用程序之前您将无法知道。从CI / CD的角度来看,我希望在完全搞乱网站之前使部署失败并可能回滚。
  3. 配置发布配置文件 - 您可以将发布配置文件配置为outlined in this article以“更新数据库”。这有效地将一个databaseInitializer添加到web.config以在应用程序启动时更新数据库。这有类似的缺点,但至少允许您使用不同的用户帐户来应用数据库更改。

enter image description here

请注意,将存储过程作为资源嵌入到迁移中是完全可行的,然后只需从迁移中调用原始sql语句:

基础迁移:

/// <summary>
/// Custom DbMigration with helper methods
/// </summary>
public abstract class BaseDbMigration : DbMigration
{
    /// <summary>
    /// Apply a SQL statement stored in an embedded resource
    /// </summary>
    /// <param name="resourceName"></param>
    protected void SqlFromEmbeddedResource(string resourceName)
    {
        Assembly assembly = typeof(BaseDbMigration).Assembly;

        string baseNamespace = typeof(BaseDbMigration).Namespace;

        resourceName = baseNamespace + "." + resourceName;

        bool exists = assembly.GetManifestResourceNames().Where(r => r == resourceName).SingleOrDefault() != null;

        if (exists)
        {
            string sql = null;

            using (var stream = assembly.GetManifestResourceStream(resourceName))
            {
                var reader = new StreamReader(stream);
                sql = reader.ReadToEnd();
            }

            base.Sql(sql);
        }
    }
}

示例迁移:

/// <summary>
/// Migration: Deploy Stored Proc
/// </summary>
public partial class CalculateTotalsV1 : BaseDbMigration
{
    /// <summary>
    /// </summary>
    public override void Up()
    {
        base.SqlFromEmbeddedResource("sp_CalculateTotals.v1.Up.sql");
    }

    /// <summary>
    /// </summary>
    public override void Down()
    {
        base.SqlFromEmbeddedResource("sp_CalculateTotals.v1.Down.sql");
    }
}

此外,如果您希望将数据库迁移与应用程序部署分开,则应该不要说您希望将代码优先迁移分离到自己的.net程序集中。这样可以更轻松地调用迁移。

© www.soinside.com 2019 - 2024. All rights reserved.