Deploying SQL databases using Entity Framework migrations and Octopus Deploy

This is part one of a two part mini-series on deploying SQL server assets using Octopus Deploy. Today we'll be deploying databases using Entity Framework migrations. In part two we'll be deploying SQL Server Reporting Services reports.

The samples below use my Contoso University sample solution which I use for demos and talks. All the source code is available on GitHub.

Why use Entity Framework migrations?

Entity Framework migrations provide a great way to manage your database schema changes in code. It produces the same SQL each time a migration is run, which means it can be run reliably in each environment as you promote code. It also avoids the overhead of manually producing SQL migration scripts and either handing them off to DBAs to run at deploy time or using tools such as DbUp to run them.

But can't you only run EF migrations in Visual Studio?

In short, no. If you've used EF migrations, you'll be familiar with the PowerShell command Update-Database to run your migrations in Visual Studio.

EF also ships with a little known tool called migrate.exe which allows us to run migrations from the command line. Using this tool we can wire a database deployment step into our Octopus Deploy process.

Packing the database project

In order to deploy our database we need to create a NuGet package for Octopus to use. Simply add the OctoPack NuGet package to the project which contains your DbContext and migrations.

The Deploy.ps1 hook

Octopus has a convention where if a package contains a Deploy.ps1 file, it will be run at deploy time. This is the hook we'll use to invoke migrate.exe. In my sample solution I have a Deploy.ps1 file which looks like this:

$connectionString = $OctopusParameters["SQL.ContosoUniversity.DeployConnectionString"]

.\migrate.exe ContosoUniversity.Data.dll /connectionString="$($connectionString)" /connectionProviderName="System.Data.SqlClient"

The important parts here are:

  1. Grab the deployment connection string from a Octopus variable. The SQL user in this connection string should have permissions to create databases and alter their schemas.
  2. The name of the assembly containing your DbContext and migrations

Set database permissions script

Once the database is deployed, you'll need to set some permissions on it. I like to include a SQL script to do this in my database project. In my sample solution I have a set-database-permissions.sql script which looks like this:

IF NOT EXISTS (  
    SELECT name 
    FROM [sys].[database_principals ]
    WHERE name = 'ContosoUniversitySite')
BEGIN  
    CREATE USER ContosoUniversitySite FROM LOGIN ContosoUniversitySite;
END

ALTER ROLE db_datareader ADD MEMBER ContosoUniversitySite;  
ALTER ROLE db_datawriter ADD MEMBER ContosoUniversitySite;  

You'll need to alter the database and user names, or better still parameterise the script so that Octopus can inject the correct values for each enviroment.

Customise the NuGet package

Out of the box, the Deploy.ps1 and custom SQL scripts won't be included in NuGet package produced by OctoPack. To include them we need to use a custom .nuspec file. In my sample solution I use this .nuspec:

<?xml version="1.0"?>  
<package >  
  <metadata>
    <id>ContosoUniversity.Data</id>
    <version>$version$</version>
    <authors>Kevin Kuszyk</authors>
    <description>ContosoUniversity.Data deplopyment package</description>
  </metadata>
  <files>
    <file src="bin\release\*.*"/>
    <file src="..\..\packages\EntityFramework.6.1.1\tools\migrate.exe" />
    <file src="*.ps1" />
    <file src="sql\*.sql" target="sql" />
  </files>
</package>  

The important part here is the files section. It tells OctoPack to:

  1. Include everything from the bin\release folder. This is the default behaviour, but as we a using a custom .nuspec we have to explicitly tell OctoPack which files to include in the package.
  2. Include the migrate.exe tool from the Entity Framework NuGet package. Note the EF package version is hard coded, so you'll need to remember to change it when you upgrade EF.
  3. Include all PowerShell scripts in the root folder of the project.
  4. Include all SQL scripts in the sql folder.

The Octopus Deploy process

To deploy the database I make a process in Octopus which looks like this:

Deploy database step

The Deploy Database step is simply a deploy package step.

Set database permissions step

The set database permissions step uses the execute SQL script file step template from the Octopus Deploy Library. I have it configured like this:

Variables

The final piece in the jigsaw are the Octopus variables. I have a variable set with the following names and values for my demo deployments:

Wrap up

To summarise, by packing the migrate.exe tool into a NuGet package along with our Entity Framework migrations and any additional SQL scripts to set permissions etc we can automate our SQL database deployment.

Thats all for today. In part two we'll see how to deploy SQL Server Reporting Services reports using Octopus Deploy.

References