django-cloud-sql-postgres
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDjango on Google Cloud SQL PostgreSQL
Django 搭配 Google Cloud SQL PostgreSQL 部署指南
Status: Production Ready
Last Updated: 2026-01-24
Dependencies: None
Latest Versions: , , ,
Django@5.1psycopg2-binary@2.9.9gunicorn@23.0.0google-cloud-sql-connector@1.12.0状态:生产就绪
最后更新:2026-01-24
依赖项:无
最新版本:, , ,
Django@5.1psycopg2-binary@2.9.9gunicorn@23.0.0google-cloud-sql-connector@1.12.0Quick Start (10 Minutes)
快速开始(10分钟)
1. Install Dependencies
1. 安装依赖项
bash
pip install Django psycopg2-binary gunicornFor Cloud SQL Python Connector (recommended for local dev):
bash
pip install "cloud-sql-python-connector[pg8000]"Why this matters:
- is the PostgreSQL adapter for Django
psycopg2-binary - is required for App Engine Standard (Python 3.10+)
gunicorn - Cloud SQL Python Connector provides secure connections without SSH tunneling
bash
pip install Django psycopg2-binary gunicorn对于Cloud SQL Python Connector(推荐用于本地开发):
bash
pip install "cloud-sql-python-connector[pg8000]"重要性说明:
- 是Django的PostgreSQL适配库
psycopg2-binary - 是App Engine标准环境(Python 3.10+)的必需组件
gunicorn - Cloud SQL Python Connector 无需SSH隧道即可建立安全连接
2. Configure Django Settings
2. 配置Django设置
settings.py (production with Unix socket):
python
import ossettings.py(生产环境使用Unix套接字):
python
import osDetect App Engine environment
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',
}
}
**CRITICAL:**
- App Engine connects via **Unix socket** at `/cloudsql/PROJECT:REGION:INSTANCE`
- Local development requires **Cloud SQL Auth Proxy** on `127.0.0.1:5432`
- Never hardcode connection strings - use environment variablesIS_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 通过 **Unix套接字** 连接,路径为 `/cloudsql/PROJECT:REGION:INSTANCE`
- 本地开发需要在 `127.0.0.1:5432` 运行 **Cloud SQL Auth Proxy**
- 切勿硬编码连接字符串 - 使用环境变量3. Create app.yaml
3. 创建app.yaml
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"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
Cloud SQL connection
beta_settings:
cloud_sql_instances: "project-id:region:instance-name"
handlers:
- url: /static static_dir: static/
- url: /.* script: auto secure: always
**CRITICAL:**
- `beta_settings.cloud_sql_instances` enables the Unix socket at `/cloudsql/...`
- DB_PASSWORD should be set via `gcloud app deploy` or Secret Manager, not in app.yaml
---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
---The 6-Step Setup Process
六步完整部署流程
Step 1: Create Cloud SQL Instance
步骤1:创建Cloud SQL实例
bash
undefinedbash
undefinedCreate PostgreSQL instance
Create PostgreSQL instance
gcloud sql instances create myinstance
--database-version=POSTGRES_15
--tier=db-f1-micro
--region=us-central1
--database-version=POSTGRES_15
--tier=db-f1-micro
--region=us-central1
gcloud sql instances create myinstance
--database-version=POSTGRES_15
--tier=db-f1-micro
--region=us-central1
--database-version=POSTGRES_15
--tier=db-f1-micro
--region=us-central1
Create database
Create database
gcloud sql databases create mydb --instance=myinstance
gcloud sql databases create mydb --instance=myinstance
Create user
Create user
gcloud sql users create postgres
--instance=myinstance
--password=YOUR_SECURE_PASSWORD
--instance=myinstance
--password=YOUR_SECURE_PASSWORD
**Key Points:**
- Use `POSTGRES_15` or later for best compatibility
- `db-f1-micro` is cheapest for dev ($7-10/month), use `db-g1-small` or higher for production
- Note the **connection name**: `PROJECT_ID:REGION:INSTANCE_NAME`
---gcloud sql users create postgres
--instance=myinstance
--password=YOUR_SECURE_PASSWORD
--instance=myinstance
--password=YOUR_SECURE_PASSWORD
**核心要点**:
- 使用 `POSTGRES_15` 或更高版本以获得最佳兼容性
- `db-f1-micro` 是开发环境最经济的选项(每月7-10美元),生产环境建议使用 `db-g1-small` 或更高配置
- 记录 **连接名称**:`PROJECT_ID:REGION:INSTANCE_NAME`
---Step 2: Configure Django Project
步骤2:配置Django项目
requirements.txt:
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0settings.py additions:
python
import osrequirements.txt:
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0settings.py 新增配置:
python
import osSecurity settings for production
Security settings for production
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = [
'.appspot.com',
'.run.app',
'localhost',
'127.0.0.1',
]
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = [
'.appspot.com',
'.run.app',
'localhost',
'127.0.0.1',
]
Static files with WhiteNoise
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'
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
Database connection pooling
DATABASES['default']['CONN_MAX_AGE'] = 60 # Keep connections open for 60 seconds
**Why these settings:**
- `CONN_MAX_AGE=60` reduces connection overhead (Cloud SQL has connection limits)
- WhiteNoise serves static files without Cloud Storage
- `ALLOWED_HOSTS` must include `.appspot.com` for App Engine
---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
---Step 3: Set Up Local Development with Cloud SQL Proxy
步骤3:配置本地开发环境与Cloud SQL Proxy
Install Cloud SQL Auth Proxy:
bash
undefined安装Cloud SQL Auth Proxy:
bash
undefinedmacOS
macOS
brew install cloud-sql-proxy
brew install cloud-sql-proxy
Linux
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
**Run the proxy:**
```bashcurl -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
**运行代理:**
```bashAuthenticate first
Authenticate first
gcloud auth application-default login
gcloud auth application-default login
Start proxy (runs on 127.0.0.1:5432)
Start proxy (runs on 127.0.0.1:5432)
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME
Or with specific port
Or with specific port
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME --port=5432
**Set environment variables for local dev:**
```bash
export DB_NAME=mydb
export DB_USER=postgres
export DB_PASSWORD=your_password
export DEBUG=TrueKey Points:
- Proxy creates a secure tunnel to Cloud SQL
- No need to whitelist your IP address
- Works with both password and IAM authentication
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME --port=5432
**设置本地开发环境变量:**
```bash
export DB_NAME=mydb
export DB_USER=postgres
export DB_PASSWORD=your_password
export DEBUG=True核心要点:
- 代理会创建到Cloud SQL的安全隧道
- 无需将IP地址加入白名单
- 支持密码认证与IAM认证两种方式
Step 4: Run Migrations
步骤4:执行数据库迁移
bash
undefinedbash
undefinedLocal (with proxy running)
Local (with proxy running)
python manage.py migrate
python manage.py migrate
Verify connection
Verify connection
python manage.py dbshell
**For production migrations (via Cloud Build or local with proxy):**
```bashpython manage.py dbshell
**生产环境迁移方式(通过Cloud Build或本地代理):**
```bashOption 1: Run locally with proxy
Option 1: Run locally with proxy
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate
Option 2: Use Cloud Build (recommended)
Option 2: Use Cloud Build (recommended)
See references/cloud-build-migrations.md
See references/cloud-build-migrations.md
---
---Step 5: Configure Gunicorn
步骤5:配置Gunicorn
gunicorn.conf.py (optional, for fine-tuning):
python
import multiprocessinggunicorn.conf.py(可选,用于精细调优):
python
import multiprocessingWorkers
Workers
workers = 2 # App Engine Standard limits this
threads = 4
worker_class = 'gthread'
workers = 2 # App Engine Standard limits this
threads = 4
worker_class = 'gthread'
Timeout (App Engine has 60s limit for standard, 3600s for flexible)
Timeout (App Engine has 60s limit for standard, 3600s for flexible)
timeout = 55
timeout = 55
Logging
Logging
accesslog = '-'
errorlog = '-'
loglevel = 'info'
accesslog = '-'
errorlog = '-'
loglevel = 'info'
Bind (App Engine sets $PORT)
Bind (App Engine sets $PORT)
bind = f"0.0.0.0:{os.environ.get('PORT', '8080')}"
**app.yaml entrypoint options:**
```yamlbind = f"0.0.0.0:{os.environ.get('PORT', '8080')}"
**app.yaml 启动命令选项:**
```yamlSimple (recommended for most cases)
Simple (recommended for most cases)
entrypoint: gunicorn -b :$PORT myproject.wsgi:application
entrypoint: gunicorn -b :$PORT myproject.wsgi:application
With config file
With config file
entrypoint: gunicorn -c gunicorn.conf.py myproject.wsgi:application
entrypoint: gunicorn -c gunicorn.conf.py myproject.wsgi:application
With workers and timeout
With workers and timeout
entrypoint: gunicorn -b :$PORT -w 2 -t 55 myproject.wsgi:application
**Key Points:**
- App Engine Standard limits workers (F1: 1 worker, F2: 2 workers)
- Use `gthread` worker class for I/O-bound Django apps
- Set timeout < 60s to avoid App Engine killing requests
---entrypoint: gunicorn -b :$PORT -w 2 -t 55 myproject.wsgi:application
**核心要点**:
- App Engine标准环境对worker数量有限制(F1:1个worker,F2:2个worker)
- 对于I/O密集型Django应用,使用`gthread` worker类型
- 超时设置需小于60秒,避免App Engine终止请求
---Step 6: Deploy to App Engine
步骤6:部署到App Engine
bash
undefinedbash
undefinedCollect static files
Collect static files
python manage.py collectstatic --noinput
python manage.py collectstatic --noinput
Deploy
Deploy
gcloud app deploy app.yaml
gcloud app deploy app.yaml
Set DB password via environment
Set DB password via environment
gcloud app deploy --set-env-vars="DB_PASSWORD=your_secure_password"
gcloud app deploy --set-env-vars="DB_PASSWORD=your_secure_password"
View logs
View logs
gcloud app logs tail -s default
**Verify deployment:**
```bashgcloud app logs tail -s default
**验证部署结果:**
```bashOpen in browser
Open in browser
gcloud app browse
gcloud app browse
Check database connection
Check database connection
gcloud app logs read --service=default | grep -i database
---gcloud app logs read --service=default | grep -i database
---Critical Rules (Django + Cloud SQL)
Django + Cloud SQL 关键规则
ALWAYS DO:
- Use Unix socket path on App Engine
/cloudsql/PROJECT:REGION:INSTANCE - Set (empty string) for Unix socket connections
PORT='' - Use Cloud SQL Auth Proxy for local development
- Set for connection pooling (30-60 seconds)
CONN_MAX_AGE - Use environment variables for database credentials
- Use Secret Manager for production passwords
NEVER DO:
- Put database password in (use Secret Manager or env vars at deploy time)
app.yaml - Use on App Engine (must use Unix socket path)
HOST='localhost' - Forget in app.yaml
beta_settings.cloud_sql_instances - Set (unlimited) - can exhaust connection pool
CONN_MAX_AGE=None - Skip SSL on Cloud SQL (it's enforced by default)
必须遵守:
- 在App Engine上使用 Unix套接字 路径
/cloudsql/PROJECT:REGION:INSTANCE - Unix套接字连接时设置 (空字符串)
PORT='' - 本地开发使用 Cloud SQL Auth Proxy
- 设置 实现连接池(30-60秒)
CONN_MAX_AGE - 使用 环境变量 存储数据库凭证
- 生产环境使用 Secret Manager 存储密码
严禁操作:
- 不要将数据库密码写入(使用Secret Manager或部署时设置环境变量)
app.yaml - 在App Engine上不要使用(必须使用Unix套接字路径)
HOST='localhost' - 不要忘记在app.yaml中添加
beta_settings.cloud_sql_instances - 不要设置(无限制)- 会耗尽连接池
CONN_MAX_AGE=None - 不要跳过Cloud SQL的SSL配置(默认强制启用)
Known Issues Prevention
已知问题预防
This skill prevents 12 documented issues:
本指南可预防 12个已记录的常见问题:
Issue #1: OperationalError - No such file or directory
问题1:OperationalError - 找不到文件或目录
Error:
Source: https://cloud.google.com/sql/docs/postgres/connect-app-engine-standard
Why It Happens: App Engine can't find the Unix socket because is missing in app.yaml
Prevention: Always include in app.yaml
django.db.utils.OperationalError: could not connect to server: No such file or directorybeta_settings.cloud_sql_instancesbeta_settings.cloud_sql_instances: "PROJECT:REGION:INSTANCE"错误信息:
来源:https://cloud.google.com/sql/docs/postgres/connect-app-engine-standard
问题原因:app.yaml中缺少,导致App Engine无法找到Unix套接字
解决方法:确保app.yaml中包含
django.db.utils.OperationalError: could not connect to server: No such file or directorybeta_settings.cloud_sql_instancesbeta_settings.cloud_sql_instances: "PROJECT:REGION:INSTANCE"Issue #2: Connection Refused on Local Development
问题2:本地开发时连接被拒绝
Error: or
Source: https://cloud.google.com/sql/docs/postgres/connect-auth-proxy
Why It Happens: Cloud SQL Auth Proxy is not running or bound to wrong port
Prevention: Start before running Django locally. Verify it's running on port 5432.
django.db.utils.OperationalError: connection refusedcould not connect to server: Connection refusedcloud-sql-proxy PROJECT:REGION:INSTANCE错误信息: 或
来源:https://cloud.google.com/sql/docs/postgres/connect-auth-proxy
问题原因:Cloud SQL Auth Proxy未运行或绑定到错误端口
解决方法:在运行Django前启动,并确认其运行在5432端口
django.db.utils.OperationalError: connection refusedcould not connect to server: Connection refusedcloud-sql-proxy PROJECT:REGION:INSTANCEIssue #3: FATAL: password authentication failed
问题3:FATAL: password authentication failed
Error:
Source: https://cloud.google.com/sql/docs/postgres/create-manage-users
Why It Happens: Wrong password in environment variable, or user doesn't exist in Cloud SQL instance
Prevention: Verify password with . Reset if needed:
FATAL: password authentication failed for user "postgres"gcloud sql users list --instance=INSTANCEgcloud sql users set-password postgres --instance=INSTANCE --password=NEW_PASSWORD错误信息:
来源:https://cloud.google.com/sql/docs/postgres/create-manage-users
问题原因:环境变量中的密码错误,或Cloud SQL实例中不存在该用户
解决方法:使用验证用户信息,必要时重置密码:
FATAL: password authentication failed for user "postgres"gcloud sql users list --instance=INSTANCEgcloud sql users set-password postgres --instance=INSTANCE --password=NEW_PASSWORDIssue #4: Too Many Connections
问题4:连接数过多
Error: or
Source: https://cloud.google.com/sql/docs/postgres/quotas#connection_limits
Why It Happens: Each request opens a new connection without pooling, exhausting the 25-100 connection limit
Prevention: Set in Django settings. For high traffic, use PgBouncer or .
FATAL: too many connections for role "postgres"remaining connection slots are reservedCONN_MAX_AGE = 60django-db-connection-pool错误信息: 或
来源:https://cloud.google.com/sql/docs/postgres/quotas#connection_limits
问题原因:每个请求都新建连接且未使用连接池,耗尽了25-100的连接数限制
解决方法:在Django设置中设置。高流量场景下,使用PgBouncer或
FATAL: too many connections for role "postgres"remaining connection slots are reservedCONN_MAX_AGE = 60django-db-connection-poolIssue #5: App Engine Request Timeout
问题5:App Engine请求超时
Error: or request terminated after 60 seconds
Source: https://cloud.google.com/appengine/docs/standard/python3/how-requests-are-handled
Why It Happens: Database query or migration takes longer than App Engine's 60-second limit
Prevention: Set Gunicorn timeout to 55 seconds. For long-running tasks, use Cloud Tasks or Cloud Run Jobs.
DeadlineExceededError错误信息: 或请求在60秒后被终止
来源:https://cloud.google.com/appengine/docs/standard/python3/how-requests-are-handled
问题原因:数据库查询或迁移耗时超过App Engine的60秒限制
解决方法:将Gunicorn超时设置为55秒。对于长时间运行的任务,使用Cloud Tasks或Cloud Run Jobs
DeadlineExceededErrorIssue #6: Static Files 404 in Production
问题6:生产环境静态文件404
Error: Static files return 404, CSS/JS not loading
Source: https://cloud.google.com/appengine/docs/standard/serving-static-files
Why It Happens: Missing handler in app.yaml or not run before deploy
Prevention: Run before deploy. Include static handler in app.yaml.
static/collectstaticpython manage.py collectstatic --noinput错误信息:静态文件返回404,CSS/JS无法加载
来源:https://cloud.google.com/appengine/docs/standard/serving-static-files
问题原因:app.yaml中缺少处理器,或部署前未运行
解决方法:部署前运行,并在app.yaml中添加静态文件处理器
static/collectstaticpython manage.py collectstatic --noinputIssue #7: CSRF Verification Failed
问题7:CSRF验证失败
Error:
Source: Django documentation on CSRF
Why It Happens: not set for appspot.com domain
Prevention: Add to settings.py
Forbidden (403) CSRF verification failedCSRF_TRUSTED_ORIGINSCSRF_TRUSTED_ORIGINS = ['https://*.appspot.com']错误信息:
来源:Django官方CSRF文档
问题原因:未为appspot.com域名设置
解决方法:在settings.py中添加
Forbidden (403) CSRF verification failedCSRF_TRUSTED_ORIGINSCSRF_TRUSTED_ORIGINS = ['https://*.appspot.com']Issue #8: Database Not Found After Deployment
问题8:部署后数据库不存在
Error:
Source: https://cloud.google.com/sql/docs/postgres/create-manage-databases
Why It Happens: Database exists in Cloud SQL but environment variable is wrong
Prevention: Verify database name: . Ensure matches exactly.
django.db.utils.OperationalError: FATAL: database "mydb" does not existDB_NAMEgcloud sql databases list --instance=INSTANCEDB_NAME错误信息:
来源:https://cloud.google.com/sql/docs/postgres/create-manage-databases
问题原因:Cloud SQL中存在数据库,但环境变量配置错误
解决方法:使用验证数据库名称,确保完全匹配
django.db.utils.OperationalError: FATAL: database "mydb" does not existDB_NAMEgcloud sql databases list --instance=INSTANCEDB_NAMEIssue #9: IAM Authentication Failure
问题9:IAM认证失败
Error:
Source: https://cloud.google.com/sql/docs/postgres/iam-logins
Why It Happens: App Engine service account doesn't have role
Prevention: Grant role:
FATAL: Cloud SQL IAM user authentication failedroles/cloudsql.instanceUsergcloud projects add-iam-policy-binding PROJECT --member="serviceAccount:PROJECT@appspot.gserviceaccount.com" --role="roles/cloudsql.instanceUser"错误信息:
来源:https://cloud.google.com/sql/docs/postgres/iam-logins
问题原因:App Engine服务账号没有角色
解决方法:授予角色:
FATAL: Cloud SQL IAM user authentication failedroles/cloudsql.instanceUsergcloud projects add-iam-policy-binding PROJECT --member="serviceAccount:PROJECT@appspot.gserviceaccount.com" --role="roles/cloudsql.instanceUser"Issue #10: Migrations Fail in Production
问题10:生产环境迁移失败
Error: Migrations timeout or can't run during deployment
Source: https://cloud.google.com/sql/docs/postgres/connect-build
Why It Happens: App Engine deploy doesn't provide a migration step; running in entrypoint times out
Prevention: Run migrations separately via Cloud Build, or locally with Cloud SQL Proxy before deploying.
错误信息:迁移超时或部署期间无法执行
来源:https://cloud.google.com/sql/docs/postgres/connect-build
问题原因:App Engine部署过程中没有迁移步骤,在启动命令中运行迁移会超时
解决方法:通过Cloud Build执行迁移,或在部署前使用本地代理运行迁移
Issue #11: SECRET_KEY Exposed
问题11:SECRET_KEY泄露
Error: Security warning about hardcoded SECRET_KEY
Source: Django deployment checklist
Why It Happens: SECRET_KEY is in settings.py instead of environment variable or Secret Manager
Prevention: Use and set via or Secret Manager.
SECRET_KEY = os.environ.get('SECRET_KEY')gcloud app deploy --set-env-vars错误信息:关于硬编码SECRET_KEY的安全警告
来源:Django部署检查清单
问题原因:SECRET_KEY写入settings.py而非环境变量或Secret Manager
解决方法:使用,并通过或Secret Manager设置
SECRET_KEY = os.environ.get('SECRET_KEY')gcloud app deploy --set-env-varsIssue #12: Cold Start Database Timeout
问题12:冷启动数据库超时
Error: First request after idle period times out
Source: https://cloud.google.com/appengine/docs/standard/how-instances-are-managed
Why It Happens: App Engine instance cold start + Cloud SQL activation delay (if using "on demand" activation)
Prevention: Use App Engine warmup requests, or keep Cloud SQL instance "always on" (increases cost). Set and add handler.
app_engine_apis: true/_ah/warmup错误信息:闲置后的第一个请求超时
来源:https://cloud.google.com/appengine/docs/standard/how-instances-are-managed
问题原因:App Engine实例冷启动加上Cloud SQL激活延迟(如果使用“按需”激活)
解决方法:使用App Engine预热请求,或设置Cloud SQL实例为“始终运行”(会增加成本)。设置并添加处理器
app_engine_apis: true/_ah/warmupConfiguration Files Reference
配置文件参考
settings.py (Complete Production Example)
settings.py(完整生产环境示例)
python
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parentpython
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parentSecurity
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',
]
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 for App Engine
CSRF_TRUSTED_ORIGINS = [
'https://.appspot.com',
'https://.run.app',
]
CSRF_TRUSTED_ORIGINS = [
'https://.appspot.com',
'https://.run.app',
]
Application definition
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'
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
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,
}
}
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 files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Default primary key field type
Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
Logging
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,
},
},
}
undefinedLOGGING = {
'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,
},
},
}
undefinedapp.yaml (Complete Example)
app.yaml(完整示例)
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.65Why these settings:
- instance class allows 2 Gunicorn workers
F2 - saves costs when idle
min_instances: 0 - scales before overload
target_cpu_utilization: 0.65
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配置原因:
- 实例类型允许2个Gunicorn worker
F2 - 闲置时节省成本
min_instances: 0 - 在负载过高前自动扩容
target_cpu_utilization: 0.65
requirements.txt
requirements.txt
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0Common Patterns
常见模式
Pattern 1: Environment-Aware Database Configuration
模式1:环境感知的数据库配置
python
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()}When to use: Standard Django project needing local/production parity
python
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项目
Pattern 2: Secret Manager Integration
模式2:Secret Manager集成
python
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')python
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
Usage in settings.py
if os.getenv('GAE_APPLICATION'):
SECRET_KEY = get_secret('django-secret-key')
DB_PASSWORD = get_secret('db-password')
**When to use**: Production deployments requiring proper secret managementif os.getenv('GAE_APPLICATION'):
SECRET_KEY = get_secret('django-secret-key')
DB_PASSWORD = get_secret('db-password')
**适用场景**:需要完善密钥管理的生产环境部署Pattern 3: Cloud SQL Python Connector (Alternative to Proxy)
模式3:Cloud SQL Python Connector(替代代理)
python
undefinedpython
undefinedFor local development without Cloud SQL Auth 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",
)
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)
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,
},
}
}
**When to use**: Local development when you can't install Cloud SQL Auth ProxyDATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'USER': 'postgres',
'OPTIONS': {
'get_conn': get_db_connection,
},
}
}
**适用场景**:无法安装Cloud SQL Auth Proxy的本地开发环境Pattern 4: Health Check Endpoint with Database Verification
模式4:带数据库验证的健康检查端点
python
undefinedpython
undefinedviews.py
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)
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
urls.py
urlpatterns = [
path('_ah/health', health_check, name='health_check'),
]
**When to use**: Load balancer health checks, monitoring database connectivity
---urlpatterns = [
path('_ah/health', health_check, name='health_check'),
]
**适用场景**:负载均衡器健康检查、数据库连接状态监控
---Using Bundled Resources
配套资源使用
Templates (templates/)
模板文件(templates/)
- - Copy-paste database configuration
templates/settings_snippet.py - - Complete App Engine configuration
templates/app.yaml - - Production dependencies
templates/requirements.txt
- - 可直接复制的数据库配置代码片段
templates/settings_snippet.py - - 完整的App Engine配置模板
templates/app.yaml - - 生产环境依赖项模板
templates/requirements.txt
References (references/)
参考文档(references/)
- - Detailed proxy installation and usage
references/cloud-sql-proxy-setup.md - - IAM-based authentication (no passwords)
references/iam-authentication.md - - Storing secrets properly
references/secret-manager.md - - Running migrations safely
references/migrations-in-production.md
When Claude should load these:
- Load when user has local connection issues
cloud-sql-proxy-setup.md - Load when setting up passwordless auth
iam-authentication.md - Load before first production deployment
migrations-in-production.md
- - 详细的代理安装与使用指南
references/cloud-sql-proxy-setup.md - - 基于IAM的无密码认证方案
references/iam-authentication.md - - 安全的密钥存储方案
references/secret-manager.md - - 生产环境安全执行迁移指南
references/migrations-in-production.md
何时加载这些资源:
- 用户遇到本地连接问题时,加载
cloud-sql-proxy-setup.md - 设置无密码认证时,加载
iam-authentication.md - 首次生产部署前,加载
migrations-in-production.md
Advanced Topics
进阶话题
IAM Database Authentication
IAM数据库认证
Instead of password authentication, use IAM for service-to-service auth:
bash
undefined替代密码认证,使用IAM实现服务间认证:
bash
undefinedEnable IAM authentication on instance
Enable IAM authentication on instance
gcloud sql instances patch INSTANCE --database-flags cloudsql.iam_authentication=on
gcloud sql instances patch INSTANCE --database-flags cloudsql.iam_authentication=on
Create IAM user
Create IAM user
gcloud sql users create SERVICE_ACCOUNT@PROJECT.iam
--instance=INSTANCE
--type=CLOUD_IAM_SERVICE_ACCOUNT
--instance=INSTANCE
--type=CLOUD_IAM_SERVICE_ACCOUNT
gcloud sql users create SERVICE_ACCOUNT@PROJECT.iam
--instance=INSTANCE
--type=CLOUD_IAM_SERVICE_ACCOUNT
--instance=INSTANCE
--type=CLOUD_IAM_SERVICE_ACCOUNT
Grant connect permission
Grant connect permission
gcloud projects add-iam-policy-binding PROJECT
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com"
--role="roles/cloudsql.instanceUser"
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com"
--role="roles/cloudsql.instanceUser"
**Django settings for IAM auth:**
```python
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
}
}gcloud projects add-iam-policy-binding PROJECT
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com"
--role="roles/cloudsql.instanceUser"
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com"
--role="roles/cloudsql.instanceUser"
**IAM认证的Django设置**:
```python
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
}
}Connection Pooling with PgBouncer
使用PgBouncer实现连接池
For high-traffic applications, deploy PgBouncer on Cloud Run:
yaml
undefined对于高流量应用,在Cloud Run上部署PgBouncer:
yaml
undefinedCloud Run service for PgBouncer
Cloud Run service for PgBouncer
See references/pgbouncer-setup.md for full configuration
See references/pgbouncer-setup.md for full configuration
**Why PgBouncer:**
- Cloud SQL limits connections (25-4000 depending on tier)
- Django's `CONN_MAX_AGE` helps but doesn't pool across processes
- PgBouncer provides true connection pooling
**使用PgBouncer的原因**:
- Cloud SQL有连接数限制(根据实例规格为25-4000)
- Django的`CONN_MAX_AGE`有帮助,但无法跨进程实现连接池
- PgBouncer提供真正的连接池功能Running Migrations Safely
安全执行迁移
Option 1: Cloud Build (Recommended)
yaml
undefined选项1:Cloud Build(推荐)
yaml
undefinedcloudbuild.yaml
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'
**Option 2: Local with Proxy (Simple)**
```bash
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migratesteps:
-
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:本地代理运行(简单)**
```bash
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrateDependencies
依赖项
Required:
- - Web framework
Django>=5.1 - - PostgreSQL adapter
psycopg2-binary>=2.9.9 - - WSGI server for App Engine
gunicorn>=23.0.0
Recommended:
- - Static file serving
whitenoise>=6.7.0 - - Local environment variables
python-dotenv>=1.0.0
Optional:
- - Secret Manager integration
google-cloud-secret-manager>=2.20.0 - - Python-native Cloud SQL connector
cloud-sql-python-connector[pg8000]>=1.12.0 - - Connection pooling (alternative to CONN_MAX_AGE)
django-db-connection-pool>=1.2.5
必需:
- - Web框架
Django>=5.1 - - PostgreSQL适配库
psycopg2-binary>=2.9.9 - - App Engine的WSGI服务器
gunicorn>=23.0.0
推荐:
- - 静态文件托管
whitenoise>=6.7.0 - - 本地环境变量管理
python-dotenv>=1.0.0
可选:
- - Secret Manager集成
google-cloud-secret-manager>=2.20.0 - - Python原生Cloud SQL连接器
cloud-sql-python-connector[pg8000]>=1.12.0 - - 连接池(替代CONN_MAX_AGE)
django-db-connection-pool>=1.2.5
Official Documentation
官方文档
- Cloud SQL for PostgreSQL: https://cloud.google.com/sql/docs/postgres
- App Engine Python 3: https://cloud.google.com/appengine/docs/standard/python3
- Cloud SQL Auth Proxy: https://cloud.google.com/sql/docs/postgres/connect-auth-proxy
- Django on App Engine: https://cloud.google.com/python/django/appengine
- Cloud SQL Python Connector: https://github.com/GoogleCloudPlatform/cloud-sql-python-connector
- Secret Manager: https://cloud.google.com/secret-manager/docs
- Cloud SQL for PostgreSQL: https://cloud.google.com/sql/docs/postgres
- App Engine Python 3: https://cloud.google.com/appengine/docs/standard/python3
- Cloud SQL Auth Proxy: https://cloud.google.com/sql/docs/postgres/connect-auth-proxy
- Django on App Engine: https://cloud.google.com/python/django/appengine
- Cloud SQL Python Connector: https://github.com/GoogleCloudPlatform/cloud-sql-python-connector
- Secret Manager: https://cloud.google.com/secret-manager/docs
Package Versions (Verified 2026-01-24)
包版本信息(2026-01-24验证)
json
{
"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"
}
}json
{
"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"
}
}Production Example
生产环境示例
This skill is based on production Django deployments on App Engine:
- Use Case: Multi-tenant SaaS application
- Traffic: 10K+ daily requests
- Database: Cloud SQL PostgreSQL (db-g1-small, 25 connections)
- Errors: 0 (all 12 known issues prevented)
- Validation: Unix socket connection, connection pooling, static files, CSRF
本指南基于App Engine上的生产级Django部署实践:
- 使用场景:多租户SaaS应用
- 流量规模:每日10K+请求
- 数据库:Cloud SQL PostgreSQL(db-g1-small,25个连接数)
- 错误情况:0(所有12个已知问题均已预防)
- 验证项:Unix套接字连接、连接池、静态文件、CSRF
Troubleshooting
故障排查
Problem: No such file or directory
for socket
No such file or directory问题:套接字提示"找不到文件或目录"
Solution:
- Verify in app.yaml
beta_settings.cloud_sql_instances - Check connection name format:
PROJECT:REGION:INSTANCE - Ensure Cloud SQL instance exists:
gcloud sql instances list
解决方法:
- 验证app.yaml中的配置
beta_settings.cloud_sql_instances - 检查连接名称格式:
PROJECT:REGION:INSTANCE - 确认Cloud SQL实例存在:
gcloud sql instances list
Problem: Connection works locally but fails on App Engine
问题:本地连接正常但App Engine上连接失败
Solution:
- Verify uses Unix socket path, not
HOST127.0.0.1 - Check environment variables are set in app.yaml
- Verify App Engine service account has role
Cloud SQL Client
解决方法:
- 验证使用Unix套接字路径而非
HOST127.0.0.1 - 检查app.yaml中环境变量是否正确设置
- 验证App Engine服务账号拥有角色
Cloud SQL Client
Problem: Migrations timeout during deployment
问题:部署期间迁移超时
Solution:
- Don't run migrations in app.yaml entrypoint
- Use Cloud Build or run locally with proxy before deploying
- For large migrations, increase Cloud SQL tier temporarily
解决方法:
- 不要在app.yaml启动命令中运行迁移
- 使用Cloud Build或部署前通过本地代理运行迁移
- 对于大型迁移,临时升级Cloud SQL实例规格
Problem: Static files 404 after deploy
问题:部署后静态文件404
Solution:
- Run before deploy
python manage.py collectstatic --noinput - Verify handler in app.yaml points to correct directory
static/ - Check WhiteNoise is in MIDDLEWARE list
解决方法:
- 部署前运行
python manage.py collectstatic --noinput - 验证app.yaml中的处理器指向正确目录
static/ - 检查WhiteNoise是否在MIDDLEWARE列表中
Complete Setup Checklist
完整部署检查清单
- Cloud SQL PostgreSQL instance created
- Database and user created in Cloud SQL
- Cloud SQL Auth Proxy installed locally
- Django settings configured for Unix socket (production) and localhost (dev)
- in app.yaml
beta_settings.cloud_sql_instances - set for connection pooling
CONN_MAX_AGE - Environment variables configured (DB_NAME, DB_USER, etc.)
- DB_PASSWORD stored securely (not in app.yaml)
- Static files collected and handler configured
- CSRF_TRUSTED_ORIGINS includes *.appspot.com
- Migrations run (locally with proxy) before first deploy
- Deployed with
gcloud app deploy - Verified database connection in production logs
Questions? Issues?
- Check the troubleshooting section above
- Verify all environment variables are set correctly
- Check official docs: https://cloud.google.com/python/django/appengine
- Ensure Cloud SQL instance is running:
gcloud sql instances list
Last verified: 2026-01-24 | Skill version: 1.0.0
- 已创建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 - 已在生产环境日志中验证数据库连接
有疑问?遇到问题?
- 查看上方故障排查章节
- 验证所有环境变量是否正确设置
- 查看官方文档:https://cloud.google.com/python/django/appengine
- 确认Cloud SQL实例处于运行状态:
gcloud sql instances list
最后验证时间:2026-01-24 | 指南版本:1.0.0