Deployments including database tasks
Implement a deployment that includes database tasks
Database rollback depends on the operation and deployment phase. Additive schema changes and copied data can preserve an application-rollback window; destructive contract steps can discard information and may require a tested restore.
Backward compatibility is the whole strategy
Because application and schema deploy at different moments, the schema must be compatible with both the old and the new application version for the duration of the rollout. That is what makes a rollback survivable.
The standard sequence for a breaking change — renaming a column — is expand / migrate / contract:
- Expand — add the new column. Old code ignores it; new code can use it.
- Migrate — deploy code that writes both, backfill existing rows.
- Contract — only once no running version reads the old column, drop it.
Expand and migrate preserve the old schema while both application versions can coexist. Contract is deliberately last: dropping the old column can close that rollback window and lose information. A direct rename can preserve the column's data, but it is not backward-compatible while old and new application versions coexist.
Implement the database task
For Azure SQL Database, a pipeline can deploy a reviewed DACPAC with the built-in task and a dedicated Azure service connection whose database identity has only the required deployment permissions:
- task: SqlAzureDacpacDeployment@1
inputs:
azureSubscription: $(databaseServiceConnection)
AuthenticationType: servicePrincipal
ServerName: $(sqlServerName)
DatabaseName: $(databaseName)
deployType: DacpacTask
DeploymentAction: Publish
DacpacFile: $(Pipeline.Workspace)/drop/database.dacpacThe same task can run a SQL script, and a framework-specific migration bundle can be used when that better fits the application stack. Whichever artifact you choose, inspect and test the generated migration before production; do not generate an unreviewed schema change at deployment time.
Ordering and gating
Express the required order and conditions at the appropriate stage, job, or step boundary. Expansion must precede code that needs the new schema; contraction must wait until no running version reads the old schema. Merely placing database and application work in the same stage proves neither order nor compatibility. Migrations should be:
- Idempotent, so a retried stage does not double-apply.
- Transactional where the database provider and operation support it.
- Protected by recovery, with a current recovery point and a restore procedure tested against recovery objectives before destructive work.
An on: failure hook runs the rollback or cleanup steps you author. Redeploying an earlier application build does not recreate a dropped column or its data.
The most dangerous deployment is the one whose rollback plan is "restore from backup" without anyone having tested the restore.
Primary sources
- https://learn.microsoft.com/en-us/credentials/certifications/resources/study-guides/az-400
- https://learn.microsoft.com/en-us/azure/devops/pipelines/targets/azure-sqldb
- https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/sql-azure-dacpac-deployment-v1
- https://learn.microsoft.com/en-us/azure/aks/zero-downtime-migration
- https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/modernize/execute-cloud-modernization
- https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/applying
- https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/managing
- https://learn.microsoft.com/en-us/azure/devops/pipelines/process/deployment-jobs
- https://learn.microsoft.com/en-us/azure/devops/pipelines/process/stages
- https://learn.microsoft.com/en-us/azure/well-architected/reliability/reliability-test