Database Post-Deploy Verification
Run schema migrations on AppOnboard-created databases (listed in prepare-plan.json.services[]) before health checks. The app must be running first — if it's crashing, fix that before attempting migrations.
Create App Database (if needed)
⛔ Azure PostgreSQL/MySQL Flexible Server only creates the system
postgres/mysqldatabase by default. If the app's config references a named database (e.g.,car_sale_db,myapp_production), create it BEFORE the container starts:az postgres flexible-server db create -g {rg} -s {serverName} -d {dbName}Detect the database name from: (1)
prereq-output.json.initCommands[]withtype: "db-migrate", (2) app config files (config-docker.yml,.env,database.yml), (3) composePOSTGRES_DBenv var. If the container crashes withdatabase "X" does not exist, this step was missed.
Discover the migration command from the codebase (check in order):
| Signal | Command | Working directory |
|---|---|---|
alembic.ini exists |
alembic upgrade head |
Directory containing alembic.ini |
Django manage.py exists |
python manage.py migrate |
Directory containing manage.py |
prisma/schema.prisma exists |
npx prisma migrate deploy |
Project root |
EF Migrations/ directory |
dotnet ef database update |
Project root |
Rails db/migrate/ directory |
rails db:migrate |
Project root |
Sequelize migrations/ + .sequelizerc |
npx sequelize-cli db:migrate |
Project root |
Execute via the Deployed Environment
App Service (Linux only)
az webapp ssh -n {app} -g {rg} --subscription {sub}
# Then run the migration command interactivelyContainer Apps
az containerapp exec -n {ca} -g {rg} --subscription {sub} --command "{migration_command}"
# If the app's WORKDIR differs from migration tool location:
az containerapp exec -n {ca} -g {rg} --subscription {sub} --command "cd /app/backend && alembic upgrade head"Error Handling
If the migration command fails, classify as IAC_ERROR and check based on the database type:
- DB unreachable → check firewall rules (PostgreSQL:
AllowAllAzureServicesAndResourcesWithinAzureIps, SQL: server firewall, MySQL: similar) - Extension/feature missing → check DB-specific config (PostgreSQL:
azure.extensions, SQL: compatibility level, MySQL:require_secure_transport) - Module not found → verify the runtime includes the migration tool
⛔
{pass}MUST be the same password passed toaz deployment sub create --parameters pgAdminPassword={value}. See deploy-safety.md § Deploy Checklist — generate each secret ONCE, persist todeploy-secrets.env, reuse everywhere. Mismatched passwords cause silent auth failures on migrations and connectivity checks.
PostgreSQL-Specific Checks
Run BEFORE migrations when services[] includes PostgreSQL Flexible Server:
- Firewall connectivity:
az postgres flexible-server execute -n {pg} -g {rg} -u {admin} -p {pass} -d postgres --querytext "SELECT 1"— if this fails, the firewall rule is missing or RBAC propagation hasn't completed. CheckAllowAllAzureServicesAndResourcesWithinAzureIpsexists, wait 60s, retry - Extension availability:
az postgres flexible-server parameter show -g {rg} -n {pg} --name azure.extensions --query value -o tsv— verify the extensions the app needs (e.g.,uuid-osspfor Alembic/Django UUID fields) are in the allow-list. If missing, the Bicep module should have set them — checkinfra/modules/postgresql.bicep
MySQL Flexible Server Checks
Run BEFORE migrations when services[] includes MySQL Flexible Server:
- Firewall connectivity:
az mysql flexible-server execute -n {mysql} -u {admin} -p {pass} -d mysql -q "SELECT 1"— if this fails, check the firewall rule and RBAC propagation. Note:executeresolves by server name (no-gneeded) - SSL enforcement:
az mysql flexible-server parameter show -g {rg} -n {mysql} --name require_secure_transport --query value -o tsv— verify matches the app's connection string SSL mode
Azure SQL Checks
Run BEFORE migrations when services[] includes Azure SQL:
- Firewall connectivity:
az sql db show -g {rg} -s {sqlServer} -n {dbName} --query status -o tsv— verify the database isOnline - Server firewall:
az sql server firewall-rule list -g {rg} -s {sqlServer} -o table— verifyAllowAllWindowsAzureIps(0.0.0.0 → 0.0.0.0) exists for Azure-internal access