将使用 SQL Server 的 Django 应用部署到 Azure 应用服务

本文介绍如何部署使用mssql-django后端Azure 应用服务的 Django 应用程序,包括 ODBC 驱动程序配置、基于环境的机密和托管标识身份验证。

先决条件

  • Azure 订阅服务
  • 可从Azure访问的Azure SQL 数据库或SQL Server实例
  • 一个配置了 mssql-django 的 Django 项目
  • 已安装 Azure CLI

Azure 应用服务上的 ODBC 驱动程序

Azure 应用服务 Linux 实例包括 Microsoft ODBC Driver for SQL Server。 可以通过运行以下命令来验证已安装的驱动程序版本:

az webapp ssh --resource-group <your-rg> --name <your-app>
odbcinst -j

Note

Azure 应用服务通常包括 LINUX 计划中预安装的 ODBC 驱动程序 17 和/或 18。 Windows 应用服务计划还包括 ODBC 驱动程序。

使用环境变量存储敏感信息

不要在settings.py中硬编码数据库凭据。 使用环境变量并将其配置为应用服务应用程序设置:

import os

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": os.environ.get("DB_NAME", "<your-database>"),
        "USER": os.environ.get("DB_USER", ""),
        "PASSWORD": os.environ.get("DB_PASSWORD", ""),
        "HOST": os.environ.get("DB_HOST", "<your-server>.database.windows.net"),
        "PORT": os.environ.get("DB_PORT", "1433"),
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
        },
    },
}

Tip

对于像 DB_NAMEDB_HOST 这样的必需值,建议考虑使用 os.environ["DB_NAME"](即不提供默认值),这样一来,如果缺少环境变量,应用程序会立即失败,并显示清晰的 KeyError

在Azure 应用服务中设置环境变量:

az webapp config appsettings set \
    --resource-group <your-rg> \
    --name <your-app> \
    --settings DB_NAME=<your-database> DB_HOST=<your-server>.database.windows.net DB_USER=<your-username> DB_PASSWORD=<your-password>

使用托管标识身份验证

对于生产部署,请使用托管标识来避免存储凭据。 在应用服务上启用系统分配的托管标识:

az webapp identity assign --resource-group <your-rg> --name <your-app>

授予托管标识对 Azure SQL 数据库的访问权限:

CREATE USER [<your-app-name>] FOR EXTERNAL PROVIDER;

ALTER ROLE db_datareader ADD MEMBER [<your-app-name>];
ALTER ROLE db_datawriter ADD MEMBER [<your-app-name>];
ALTER ROLE db_ddladmin ADD MEMBER [<your-app-name>];

Note

仅授予应用程序所需的角色。 仅当应用程序运行迁移时,才需要 db_ddladmin 固定数据库角色。 对于只读工作负荷, db_datareader 已足够。

如果您的服务器配置为仅限 Microsoft Entra 的身份验证,则 FROM EXTERNAL PROVIDER 会因 Msg 33130 而失败,因为服务器无法访问 Microsoft Graph 来解析该标识名称。 使用 CREATE USER [<your-app-name>] WITH SID = 0x<sid-hex>, TYPE = E 手动创建用户,其中 <sid-hex> 派生自托管标识 的应用程序(客户端)ID,而不是其对象 ID。 有关转换步骤,请参阅Azure SQL中授予标识访问权限

settings.py 配置为使用托管标识:

import os

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": os.environ.get("DB_NAME", "<your-database>"),
        "HOST": os.environ.get("DB_HOST", "<your-server>.database.windows.net"),
        "PORT": "1433",
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
            "extra_params": "Authentication=ActiveDirectoryMsi",
        },
    },
}

将访问令牌与 ManagedIdentityCredential 配合使用

或者,配合 azure.identity 使用 TOKEN 设置:

注意

该值 TOKEN 在进程启动时提取一次,并在 60-90 分钟后过期。 对于运行时间较长的 App Service 部署,仅当你还实现了令牌刷新逻辑或短生命周期工作进程回收时,才使用此方法。 如果直接使用 ActiveDirectoryMsi 模式在您的环境中可行,就可以避免启动时的令牌问题。

import os
from azure.identity import ManagedIdentityCredential

credential = ManagedIdentityCredential()
token = credential.get_token("https://database.windows.net/.default").token

DATABASES = {
    "default": {
        "ENGINE": "mssql",
        "NAME": os.environ.get("DB_NAME", "<your-database>"),
        "HOST": os.environ.get("DB_HOST", "<your-server>.database.windows.net"),
        "PORT": "1433",
        "TOKEN": token,
        "OPTIONS": {
            "driver": "ODBC Driver 18 for SQL Server",
        },
    },
}

Tip

DefaultAzureCredential对于开发和共享代码库来说很方便,因为它会自动尝试多个凭据类型,因此相同的代码适用于笔记本电脑、CI 和 Azure。 但是,不应用的每个凭据类型都会增加几秒钟的超时时间,这会减慢启动速度。 由于应用服务始终提供可用的托管标识,ManagedIdentityCredential 无需经过探测链即可立即完成身份验证。 在要求文件中安装 azure-identitypip install azure-identity

在部署期间执行迁移

添加部署后脚本或启动命令以自动运行迁移:

az webapp config set \
    --resource-group <your-rg> \
    --name <your-app> \
    --startup-file "python manage.py migrate && gunicorn myproject.wsgi"

收集静态文件

为生产配置静态文件处理:

STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

在部署过程中运行 collectstatic

python manage.py collectstatic --noinput

部署到应用服务

应用服务可以通过两种方式托管 Django 应用:

  • 内置 Linux Python映像:应用服务从源代码生成代码,并提供Python运行时。
  • 自定义 Docker 映像:自行生成映像,并从容器注册表引用该映像。

这两个路径都可以使用系统分配的托管标识对Azure SQL进行身份验证,但方案有所不同。 选择与部署匹配的选项卡。

使用内置的 Linux Python 镜像,App Service 的 Oryx 生成器会自动安装 requirements.txt,并在 gunicorn 下启动你的 Django 应用。 本地托管身份 HTTP 代理使 Authentication=ActiveDirectoryMsi 可直接在 ODBC 连接字符串中使用。 使用使用托管标识身份验证中所示的settings.py

使用 az webapp up、启用系统分配的托管标识部署代码,并设置数据库环境变量:

az webapp up \
    --resource-group <your-rg> \
    --name <your-app> \
    --runtime "PYTHON:3.12" \
    --sku B1

az webapp identity assign --resource-group <your-rg> --name <your-app>

az webapp config appsettings set \
    --resource-group <your-rg> \
    --name <your-app> \
    --settings DB_NAME=<your-database> DB_HOST=<your-server>.database.windows.net

然后,如 使用托管标识身份验证中所述,在 SQL 中授予托管标识访问权限。

使用 Docker Compose 进行本地开发

对于本地开发和测试,请使用 Docker Compose 与 SQL Server 容器一起运行 Django 应用:

# docker-compose.yml
services:
  db:
    image: mcr.microsoft.com/mssql/server:2022-latest
    environment:
      ACCEPT_EULA: "Y"
      MSSQL_SA_PASSWORD: "<password>"  # Must meet SQL Server complexity requirements
    ports:
      - "1433:1433"

  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      DB_HOST: db
      DB_NAME: mydb
      DB_USER: sa
      DB_PASSWORD: "<password>"
    depends_on:
      - db

Tip

SQL Server容器不会自动创建应用程序数据库。 启动容器后,创建数据库并运行迁移:

docker compose exec db /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "<password>" -No -Q "CREATE DATABASE mydb"
docker compose exec web python manage.py migrate

SQL Server 容器镜像需要 ACCEPT_EULA=Y 和高强度的 SA 密码。 对于生产环境,请使用 Azure SQL 数据库,并使用托管标识而不是 SQL Server 凭据。 请参阅 使用托管标识进行身份验证