mcpField
D
django-cloud-sql-postgres

django-cloud-sql-postgres

github.com/jezweb云与 DevOps1.1k272 次安装3 周前更新
代码仓库

关于 django-cloud-sql-postgres

django-cloud-sql-postgres 是将 Django 部署到 Google Cloud SQL for PostgreSQL 和 App Engine 的配置指南,适合需要本地开发与生产环境连接方案的开发者。内容涵盖安全连接、迁移、Gunicorn 和常见故障排查。

主要功能

  1. 01Django 与 PostgreSQL 配置
  2. 02App Engine Unix Socket 连接
  3. 03本地 Cloud SQL Auth Proxy
  4. 04数据库迁移与部署流程
  5. 05Gunicorn 及静态文件配置
  6. 06常见连接错误排查

适用场景

  1. 01将 Django 应用部署到 App Engine
  2. 02通过代理在本地连接 Cloud SQL
  3. 03配置生产数据库凭据
  4. 04排查连接数或迁移故障

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jezweb/claude-skills --skill django-cloud-sql-postgres

安装后在 Claude Code 中输入/django-cloud-sql-postgres确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
.claude-plugin/
plugin.json
references/
cloud-sql-proxy-setup.md
iam-authentication.md
migrations-in-production.md
rules/
django-cloud-sql-postgres.md
templates/
app.yaml
requirements.txt
settings_cloudsql.py

详细介绍

Google Cloud SQL PostgreSQL 上的 Django

状态:已可用于生产环境
上次更新:2026-01-24
依赖项:无
最新版本:[email protected]、[email protected]、[email protected]、[email protected]


快速开始(10 分钟)

1. 安装依赖项
pip install Django psycopg2-binary gunicorn

适用于 Cloud SQL Python Connector(推荐用于本地开发):

pip install "cloud-sql-python-connector[pg8000]"

这很重要的原因:

  • psycopg2-binary 是 Django 的 PostgreSQL 适配器
  • App Engine Standard(Python 3.10+)需要 gunicorn
  • Cloud SQL Python Connector 可在无需 SSH 隧道的情况下提供安全连接
2. 配置 Django 设置

settings.py(使用 Unix 套接字的生产环境配置):

import os

# Detect App Engine environment
IS_APP_ENGINE = os.getenv('GAE_APPLICATION', None)

if IS_APP_ENGINE:
    # Production: Connect via Unix socket
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ['DB_NAME'],
            'USER': os.environ['DB_USER'],
            'PASSWORD': os.environ['DB_PASSWORD'],
            'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
            'PORT': '',  # Empty for Unix socket
        }
    }
else:
    # Local development: Connect via Cloud SQL Proxy
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ.get('DB_NAME', 'mydb'),
            'USER': os.environ.get('DB_USER', 'postgres'),
            'PASSWORD': os.environ.get('DB_PASSWORD', ''),
            'HOST': '127.0.0.1',
            'PORT': '5432',
        }
    }

重要:

  • App Engine 通过 /cloudsql/PROJECT:REGION:INSTANCE 处的 Unix 套接字连接
  • 本地开发需要在 127.0.0.1:5432 上运行 Cloud SQL Auth Proxy
  • 切勿将连接字符串硬编码,应使用环境变量
3. 创建 app.yaml
runtime: python310
entrypoint: gunicorn -b :$PORT myproject.wsgi:application

env_variables:
  DB_NAME: "mydb"
  DB_USER: "postgres"
  CLOUD_SQL_CONNECTION_NAME: "project-id:region:instance-name"

# Cloud SQL connection
beta_settings:
  cloud_sql_instances: "project-id:region:instance-name"

handlers:
  - url: /static
    static_dir: static/
  - url: /.*
    script: auto
    secure: always

重要:

  • beta_settings.cloud_sql_instances 会在 /cloudsql/... 启用 Unix 套接字
  • DB_PASSWORD 应通过 gcloud app deploy 或 Secret Manager 设置,而不是写入 app.yaml

6 步设置流程

步骤 1:创建 Cloud SQL 实例
# Create PostgreSQL instance
gcloud sql instances create myinstance \
  --database-version=POSTGRES_15 \
  --tier=db-f1-micro \
  --region=us-central1

# Create database
gcloud sql databases create mydb --instance=myinstance

# Create user
gcloud sql users create postgres \
  --instance=myinstance \
  --password=YOUR_SECURE_PASSWORD

要点:

  • 为获得最佳兼容性,请使用 POSTGRES_15 或更高版本
  • db-f1-micro 是最便宜的开发环境配置(每月 $7-10);生产环境请使用 db-g1-small 或更高规格
  • 记下 连接名称:PROJECT_ID:REGION:INSTANCE_NAME

步骤 2:配置 Django 项目

requirements.txt:

Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0

添加到 settings.py 的配置:

import os

# Security settings for production
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = [
    '.appspot.com',
    '.run.app',
    'localhost',
    '127.0.0.1',
]

# Static files with WhiteNoise
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# Database connection pooling
DATABASES['default']['CONN_MAX_AGE'] = 60  # Keep connections open for 60 seconds

这些设置的原因:

  • CONN_MAX_AGE=60 可减少连接开销(Cloud SQL 对连接数有限制)
  • WhiteNoise 无需 Cloud Storage 即可提供静态文件
  • ALLOWED_HOSTS 必须包含 .appspot.com,以供 App Engine 使用

步骤 3:使用 Cloud SQL Proxy 设置本地开发环境

安装 Cloud SQL Auth Proxy:

# macOS
brew install cloud-sql-proxy

# Linux
curl -o cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.14.1/cloud-sql-proxy.linux.amd64
chmod +x cloud-sql-proxy

运行代理:

# Authenticate first
gcloud auth application-default login

# Start proxy (runs on 127.0.0.1:5432)
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME

# Or with specific port
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME --port=5432

为本地开发设置环境变量:

export DB_NAME=mydb
export DB_USER=postgres
export DB_PASSWORD=your_password
export DEBUG=True

要点:

  • 代理会创建到 Cloud SQL 的安全隧道
  • 无需将你的 IP 地址加入允许列表
  • 支持密码和 IAM 身份验证

步骤 4:运行迁移
# Local (with proxy running)
python manage.py migrate

# Verify connection
python manage.py dbshell

生产环境迁移(通过 Cloud Build 或在本地使用代理):

# Option 1: Run locally with proxy
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate

# Option 2: Use Cloud Build (recommended)
# See references/cloud-build-migrations.md

步骤 5:配置 Gunicorn

gunicorn.conf.py(可选,用于微调):

import multiprocessing

# Workers
workers = 2  # App Engine Standard limits this
threads = 4
worker_class = 'gthread'

# Timeout (App Engine has 60s limit for standard, 3600s for flexible)
timeout = 55

# Logging
accesslog = '-'
errorlog = '-'
loglevel = 'info'

# Bind (App Engine sets $PORT)
bind = f"0.0.0.0:{os.environ.get('PORT', '8080')}"

app.yaml entrypoint 选项:

# Simple (recommended for most cases)
entrypoint: gunicorn -b :$PORT myproject.wsgi:application

# With config file
entrypoint: gunicorn -c gunicorn.conf.py myproject.wsgi:application

# With workers and timeout
entrypoint: gunicorn -b :$PORT -w 2 -t 55 myproject.wsgi:application

要点:

  • App Engine Standard 限制工作进程数量(F1:1 个工作进程,F2:2 个工作进程)
  • 对于 I/O 密集型 Django 应用,请使用 gthread 工作进程类
  • 将超时设为小于 60 秒,以避免 App Engine 终止请求

步骤 6:部署到 App Engine
# Collect static files
python manage.py collectstatic --noinput

# Deploy
gcloud app deploy app.yaml

# Set DB password via environment
gcloud app deploy --set-env-vars="DB_PASSWORD=your_secure_password"

# View logs
gcloud app logs tail -s default

验证部署:

# Open in browser
gcloud app browse

# Check database connection
gcloud app logs read --service=default | grep -i database

关键规则(Django + Cloud SQL)

务必做到:

  • 在 App Engine 上使用 Unix 套接字路径 /cloudsql/PROJECT:REGION:INSTANCE
  • 对 Unix 套接字连接设置 PORT=''(空字符串)
  • 本地开发使用 Cloud SQL Auth Proxy
  • 为连接池设置 CONN_MAX_AGE(30-60 秒)
  • 使用环境变量存储数据库凭据
  • 在生产环境中使用 Secret Manager 存储密码

切勿:

  • 将数据库密码写入 app.yaml(请使用 Secret Manager,或在部署时通过环境变量设置)
  • 在 App Engine 上使用 HOST='localhost'(必须使用 Unix 套接字路径)
  • 忘记在 app.yaml 中设置 beta_settings.cloud_sql_instances
  • 将 CONN_MAX_AGE=None 设为无限制——这可能耗尽连接池
  • 在 Cloud SQL 上跳过 SSL(默认情况下会强制使用 SSL)

避免已知问题

此技能可避免 12 个有记录的问题:

问题 #1:OperationalError - No such file or directory

错误:django.db.utils.OperationalError: could not connect to server: No such file or directory 来源:https://cloud.google.com/sql/docs/postgres/connect-app-engine-standard 原因:app.yaml 中缺少 beta_settings.cloud_sql_instances,导致 App Engine 找不到 Unix 套接字 预防措施:始终在 app.yaml 中加入 beta_settings.cloud_sql_instances: "PROJECT:REGION:INSTANCE"

问题 #2:本地开发时连接被拒绝

错误:django.db.utils.OperationalError: connection refused 或 could not connect to server: Connection refused 来源:https://cloud.google.com/sql/docs/postgres/connect-auth-proxy 原因:Cloud SQL Auth Proxy 未运行,或绑定到了错误的端口 预防措施:在本地运行 Django 前,先启动 cloud-sql-proxy PROJECT:REGION:INSTANCE。确认其在端口 5432 上运行。

问题 #3:FATAL:密码验证失败

错误:FATAL: password authentication failed for user "postgres" 来源:https://cloud.google.com/sql/docs/postgres/create-manage-users 原因:环境变量中的密码错误,或 Cloud SQL 实例中不存在该用户 预防措施:使用 gcloud sql users list --instance=INSTANCE 验证密码。如有需要,重置密码:gcloud sql users set-password postgres --instance=INSTANCE --password=NEW_PASSWORD

问题 #4:连接数过多

错误:FATAL: too many connections for role "postgres" 或 remaining connection slots are reserved 来源:https://cloud.google.com/sql/docs/postgres/quotas#connection_limits 原因:每个请求都会打开一个新连接,且未使用连接池,导致耗尽 25-100 个连接的限额 预防措施:在 Django 设置中设置 CONN_MAX_AGE = 60。如果流量较大,请使用 PgBouncer 或 django-db-connection-pool。

问题 #5:App Engine 请求超时

错误:DeadlineExceededError 或请求在 60 秒后终止 来源:https://cloud.google.com/appengine/docs/standard/python3/how-requests-are-handled 原因:数据库查询或迁移所需时间超过 App Engine 的 60 秒限额 预防措施:将 Gunicorn 超时设置为 55 秒。对于长时间运行的任务,请使用 Cloud Tasks 或 Cloud Run Jobs。

问题 #6:生产环境中的静态文件 404

错误:静态文件返回 404,CSS/JS 无法加载 来源:https://cloud.google.com/appengine/docs/standard/serving-static-files 原因:app.yaml 中缺少 static/ 处理程序,或部署前未运行 collectstatic 预防措施:部署前运行 python manage.py collectstatic --noinput。在 app.yaml 中加入静态文件处理程序。

问题 #7:CSRF 验证失败

错误:Forbidden (403) CSRF verification failed 来源:Django 关于 CSRF 的文档 原因:未为 appspot.com 域设置 CSRF_TRUSTED_ORIGINS 预防措施:在 settings.py 中添加 CSRF_TRUSTED_ORIGINS = ['https://*.appspot.com']

问题 #8:部署后找不到数据库

错误:django.db.utils.OperationalError: FATAL: database "mydb" does not exist 来源:https://cloud.google.com/sql/docs/postgres/create-manage-databases 原因:Cloud SQL 中存在该数据库,但 DB_NAME 环境变量不正确 预防措施:使用 gcloud sql databases list --instance=INSTANCE 验证数据库名称。确保 DB_NAME 与其完全一致。

问题 #9:IAM 身份验证失败

错误:FATAL: Cloud SQL IAM user authentication failed 来源:https://cloud.google.com/sql/docs/postgres/iam-logins 原因:App Engine 服务账号未获授 roles/cloudsql.instanceUser 角色 预防措施:授予角色:gcloud projects add-iam-policy-binding PROJECT --member="serviceAccount:[email protected]" --role="roles/cloudsql.instanceUser"

问题 #10:在生产环境中迁移失败

错误:迁移超时,或无法在部署期间运行 来源:https://cloud.google.com/sql/docs/postgres/connect-build 原因:App Engine 部署不提供迁移步骤;在入口点运行会超时 预防措施:通过 Cloud Build 单独运行迁移,或在部署前通过 Cloud SQL Proxy 在本地运行。

问题 #11:SECRET_KEY 暴露

错误:关于硬编码 SECRET_KEY 的安全警告 来源:Django 部署清单 原因:SECRET_KEY 位于 settings.py 中,而非环境变量或 Secret Manager 中 预防措施:使用 SECRET_KEY = os.environ.get('SECRET_KEY'),并通过 gcloud app deploy --set-env-vars 或 Secret Manager 设置。

问题 #12:冷启动数据库超时

错误:空闲一段时间后的第一个请求超时 来源:https://cloud.google.com/appengine/docs/standard/how-instances-are-managed 原因:App Engine 实例冷启动,加上 Cloud SQL 激活延迟(若使用“按需”激活) 预防措施:使用 App Engine 预热请求,或让 Cloud SQL 实例“始终开启”(会增加成本)。设置 app_engine_apis: true 并添加 /_ah/warmup 处理程序。


配置文件参考

settings.py(完整生产环境示例)
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# Security
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key-change-in-production')
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = [
    '.appspot.com',
    '.run.app',
    'localhost',
    '127.0.0.1',
]

# CSRF for App Engine
CSRF_TRUSTED_ORIGINS = [
    'https://*.appspot.com',
    'https://*.run.app',
]

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Your apps here
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  # Static files
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'myproject.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'myproject.wsgi.application'

# Database
IS_APP_ENGINE = os.getenv('GAE_APPLICATION', None)

if IS_APP_ENGINE:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ['DB_NAME'],
            'USER': os.environ['DB_USER'],
            'PASSWORD': os.environ['DB_PASSWORD'],
            'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
            'PORT': '',
            'CONN_MAX_AGE': 60,
            'OPTIONS': {
                'connect_timeout': 10,
            },
        }
    }
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ.get('DB_NAME', 'mydb'),
            'USER': os.environ.get('DB_USER', 'postgres'),
            'PASSWORD': os.environ.get('DB_PASSWORD', ''),
            'HOST': os.environ.get('DB_HOST', '127.0.0.1'),
            'PORT': os.environ.get('DB_PORT', '5432'),
            'CONN_MAX_AGE': 60,
        }
    }

# Static files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Logging
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'root': {
        'handlers': ['console'],
        'level': 'INFO',
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
            'propagate': False,
        },
    },
}
app.yaml(完整示例)
runtime: python310
entrypoint: gunicorn -b :$PORT -w 2 -t 55 --threads 4 myproject.wsgi:application

instance_class: F2

env_variables:
  DB_NAME: "mydb"
  DB_USER: "postgres"
  CLOUD_SQL_CONNECTION_NAME: "project-id:us-central1:instance-name"
  DEBUG: "False"

beta_settings:
  cloud_sql_instances: "project-id:us-central1:instance-name"

handlers:
  - url: /static
    static_dir: static/
    secure: always

  - url: /.*
    script: auto
    secure: always

automatic_scaling:
  min_instances: 0
  max_instances: 2
  target_cpu_utilization: 0.65

这些设置的作用:

  • F2 实例类型支持 2 个 Gunicorn 工作进程
  • min_instances: 0 可在空闲时节省成本
  • target_cpu_utilization: 0.65 可在过载前扩缩容
requirements.txt
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0

常见模式

模式 1:适应不同环境的数据库配置
import os

def get_database_config():
    """Return database config based on environment."""
    is_production = os.getenv('GAE_APPLICATION', None)

    if is_production:
        return {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ['DB_NAME'],
            'USER': os.environ['DB_USER'],
            'PASSWORD': os.environ['DB_PASSWORD'],
            'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
            'PORT': '',
            'CONN_MAX_AGE': 60,
        }
    else:
        return {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ.get('DB_NAME', 'mydb'),
            'USER': os.environ.get('DB_USER', 'postgres'),
            'PASSWORD': os.environ.get('DB_PASSWORD', ''),
            'HOST': '127.0.0.1',
            'PORT': '5432',
            'CONN_MAX_AGE': 60,
        }

DATABASES = {'default': get_database_config()}

适用场景:需要保持本地与生产环境一致的标准 Django 项目

模式 2:Secret Manager 集成
from google.cloud import secretmanager

def get_secret(secret_id, version_id='latest'):
    """Retrieve secret from Google Secret Manager."""
    client = secretmanager.SecretManagerServiceClient()
    project_id = os.environ.get('GOOGLE_CLOUD_PROJECT')
    name = f"projects/{project_id}/secrets/{secret_id}/versions/{version_id}"
    response = client.access_secret_version(request={"name": name})
    return response.payload.data.decode('UTF-8')

# Usage in settings.py
if os.getenv('GAE_APPLICATION'):
    SECRET_KEY = get_secret('django-secret-key')
    DB_PASSWORD = get_secret('db-password')

适用场景:需要妥善管理密钥的生产部署

模式 3:Cloud SQL Python Connector(Proxy 的替代方案)
# For local development without Cloud SQL Auth Proxy
from google.cloud.sql.connector import Connector

def get_db_connection():
    connector = Connector()
    return connector.connect(
        "project:region:instance",
        "pg8000",
        user="postgres",
        password=os.environ["DB_PASSWORD"],
        db="mydb",
    )

# In settings.py for local dev (requires pg8000 driver)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
        'USER': 'postgres',
        'OPTIONS': {
            'get_conn': get_db_connection,
        },
    }
}

适用场景:无法安装 Cloud SQL Auth Proxy 时的本地开发

模式 4:带数据库验证的运行状况检查端点
# views.py
from django.http import JsonResponse
from django.db import connection

def health_check(request):
    """Health check endpoint for App Engine."""
    try:
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1")
        return JsonResponse({
            'status': 'healthy',
            'database': 'connected',
        })
    except Exception as e:
        return JsonResponse({
            'status': 'unhealthy',
            'database': str(e),
        }, status=503)

# urls.py
urlpatterns = [
    path('_ah/health', health_check, name='health_check'),
]

适用场景:负载均衡器运行状况检查、监控数据库连通性


使用附带的资源

模板(templates/)
  • templates/settings_snippet.py - 可复制粘贴的数据库配置
  • templates/app.yaml - 完整的 App Engine 配置
  • templates/requirements.txt - 生产环境依赖项
参考资料(references/)
  • references/cloud-sql-proxy-setup.md - Proxy 的详细安装和使用说明
  • references/iam-authentication.md - 基于 IAM 的身份验证(无需密码)
  • references/secret-manager.md - 妥善存储密钥
  • references/migrations-in-production.md - 安全运行迁移

Claude 应在以下情况加载这些资料:

  • 用户遇到本地连接问题时,加载 cloud-sql-proxy-setup.md
  • 设置无密码身份验证时,加载 iam-authentication.md
  • 首次部署到生产环境前,加载 migrations-in-production.md

高级主题

IAM 数据库身份验证

使用 IAM 进行服务间身份验证,而非密码身份验证:

# Enable IAM authentication on instance
gcloud sql instances patch INSTANCE --database-flags cloudsql.iam_authentication=on

# Create IAM user
gcloud sql users create [email protected] \
  --instance=INSTANCE \
  --type=CLOUD_IAM_SERVICE_ACCOUNT

# Grant connect permission
gcloud projects add-iam-policy-binding PROJECT \
  --member="serviceAccount:[email protected]" \
  --role="roles/cloudsql.instanceUser"

用于 IAM 身份验证的 Django 设置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ['DB_NAME'],
        'USER': f"{os.environ['SERVICE_ACCOUNT']}@{os.environ['PROJECT_ID']}.iam",
        'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
        'PORT': '',
        # No PASSWORD needed with IAM auth
    }
}
使用 PgBouncer 进行连接池管理

对于高流量应用,可在 Cloud Run 上部署 PgBouncer:

# Cloud Run service for PgBouncer
# See references/pgbouncer-setup.md for full configuration

使用 PgBouncer 的原因:

  • Cloud SQL 对连接数有限制(根据层级不同,限制为 25–4000 个)
  • Django 的 CONN_MAX_AGE 有帮助,但无法跨进程建立连接池
  • PgBouncer 可提供真正的连接池
安全运行迁移

选项 1:Cloud Build(推荐)

# cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/gcloud'
    args: ['sql', 'connect', 'INSTANCE', '--quiet']

  - name: 'python:3.10'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        pip install -r requirements.txt
        python manage.py migrate --noinput
    env:
      - 'DB_NAME=mydb'
      - 'DB_USER=postgres'
      - 'DB_HOST=/cloudsql/PROJECT:REGION:INSTANCE'
    secretEnv: ['DB_PASSWORD']

availableSecrets:
  secretManager:
    - versionName: projects/PROJECT/secrets/db-password/versions/latest
      env: 'DB_PASSWORD'

选项 2:在本地使用 Proxy(简单)

./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate

依赖项

必需:

  • Django>=5.1 - Web 框架
  • psycopg2-binary>=2.9.9 - PostgreSQL 适配器
  • gunicorn>=23.0.0 - App Engine 的 WSGI 服务

推荐:

  • whitenoise>=6.7.0 - 静态文件服务
  • python-dotenv>=1.0.0 - 本地环境变量

可选:

  • google-cloud-secret-manager>=2.20.0 - Secret Manager 集成
  • cloud-sql-python-connector[pg8000]>=1.12.0 - 原生 Python Cloud SQL 连接器
  • django-db-connection-pool>=1.2.5 - 连接池(CONN_MAX_AGE 的替代方案)

官方文档


软件包版本(已于 2026-01-24 验证)

{
  "dependencies": {
    "Django": ">=5.1,<6.0",
    "psycopg2-binary": ">=2.9.9",
    "gunicorn": ">=23.0.0",
    "whitenoise": ">=6.7.0"
  },
  "optional": {
    "google-cloud-secret-manager": ">=2.20.0",
    "cloud-sql-python-connector": ">=1.12.0"
  }
}

生产环境示例

此技能基于 App Engine 上的 Django 生产部署:

  • 用例:多租户 SaaS 应用
  • 流量:每天 10K+ 个请求
  • 数据库:Cloud SQL PostgreSQL(db-g1-small,25 个连接)
  • 错误:0(已避免所有 12 个已知问题)
  • 验证:Unix 套接字连接、连接池、静态文件、CSRF

故障排除

问题:套接字报错 No such file or directory

解决方案:

  1. 验证 app.yaml 中的 beta_settings.cloud_sql_instances
  2. 检查连接名称格式:PROJECT:REGION:INSTANCE
  3. 确认 Cloud SQL 实例存在:gcloud sql instances list
问题:本地连接正常,但在 App Engine 上失败

解决方案:

  1. 确认 HOST 使用 Unix 套接字路径,而不是 127.0.0.1
  2. 检查 app.yaml 中是否设置了环境变量
  3. 确认 App Engine 服务账号具有 Cloud SQL Client 角色
问题:部署期间迁移超时

解决方案:

  1. 不要在 app.yaml 入口点运行迁移
  2. 使用 Cloud Build,或在部署前通过代理在本地运行
  3. 对于大型迁移,临时提高 Cloud SQL 层级
问题:部署后静态文件返回 404

解决方案:

  1. 部署前运行 python manage.py collectstatic --noinput
  2. 确认 app.yaml 中的 static/ 处理程序指向正确目录
  3. 检查 MIDDLEWARE 列表中是否包含 WhiteNoise

完整设置检查清单

  • 已创建 Cloud SQL PostgreSQL 实例
  • 已在 Cloud SQL 中创建数据库和用户
  • 已在本地安装 Cloud SQL Auth Proxy
  • Django 设置已配置为使用 Unix 套接字(生产环境)和 localhost(开发环境)
  • app.yaml 中已设置 beta_settings.cloud_sql_instances
  • 已为连接池设置 CONN_MAX_AGE
  • 已配置环境变量(DB_NAME、DB_USER 等)
  • 已安全存储 DB_PASSWORD(未放入 app.yaml)
  • 已收集静态文件并配置处理程序
  • CSRF_TRUSTED_ORIGINS 包含 *.appspot.com
  • 首次部署前已运行迁移(通过代理在本地运行)
  • 已使用 gcloud app deploy 部署
  • 已在生产日志中验证数据库连接

有疑问?遇到问题?

  1. 查看上方的故障排除部分
  2. 确认所有环境变量均已正确设置
  3. 查看官方文档:https://cloud.google.com/python/django/appengine
  4. 确认 Cloud SQL 实例正在运行:gcloud sql instances list

最后验证时间:2026-01-24 | 技能版本:1.0.0

评论

支持 Markdown