django-cloud-sql-postgres by jezweb/claude-skills
npx skills add https://github.com/jezweb/claude-skills --skill django-cloud-sql-postgres状态 : 生产就绪 最后更新 : 2026-01-24 依赖项 : 无 最新版本 : Django@5.1, psycopg2-binary@2.9.9, gunicorn@23.0.0, google-cloud-sql-connector@1.12.0
pip install Django psycopg2-binary gunicorn
对于 Cloud SQL Python 连接器 (推荐用于本地开发):
pip install "cloud-sql-python-connector[pg8000]"
为何重要:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
psycopg2-binarygunicorn 是 App Engine Standard (Python 3.10+) 所必需的settings.py (生产环境使用 Unix 套接字):
import os
# 检测 App Engine 环境
IS_APP_ENGINE = os.getenv('GAE_APPLICATION', None)
if IS_APP_ENGINE:
# 生产环境: 通过 Unix 套接字连接
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': '', # Unix 套接字留空
}
}
else:
# 本地开发: 通过 Cloud SQL 代理连接
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',
}
}
关键要点:
/cloudsql/PROJECT:REGION:INSTANCE 连接127.0.0.1:5432 上运行 Cloud SQL 认证代理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 连接
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 套接字gcloud app deploy 或 Secret Manager 设置,而非在 app.yaml 中# 创建 PostgreSQL 实例
gcloud sql instances create myinstance \
--database-version=POSTGRES_15 \
--tier=db-f1-micro \
--region=us-central1
# 创建数据库
gcloud sql databases create mydb --instance=myinstance
# 创建用户
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_NAMErequirements.txt:
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0
settings.py 补充内容:
import os
# 生产环境安全设置
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = [
'.appspot.com',
'.run.app',
'localhost',
'127.0.0.1',
]
# 使用 WhiteNoise 处理静态文件
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# 数据库连接池
DATABASES['default']['CONN_MAX_AGE'] = 60 # 保持连接打开 60 秒
为何需要这些设置:
CONN_MAX_AGE=60 减少连接开销 (Cloud SQL 有连接限制)ALLOWED_HOSTS 必须包含 .appspot.com 以用于 App Engine安装 Cloud SQL 认证代理:
# 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
运行代理:
# 首先进行身份验证
gcloud auth application-default login
# 启动代理 (运行在 127.0.0.1:5432)
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME
# 或指定端口
./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
关键点:
# 本地 (代理运行时)
python manage.py migrate
# 验证连接
python manage.py dbshell
生产环境迁移 (通过 Cloud Build 或本地使用代理):
# 选项 1: 本地使用代理运行
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate
# 选项 2: 使用 Cloud Build (推荐)
# 参见 references/cloud-build-migrations.md
gunicorn.conf.py (可选,用于微调):
import multiprocessing
# Workers
workers = 2 # App Engine Standard 对此有限制
threads = 4
worker_class = 'gthread'
# 超时 (App Engine Standard 限制为 60 秒,Flexible 为 3600 秒)
timeout = 55
# 日志记录
accesslog = '-'
errorlog = '-'
loglevel = 'info'
# 绑定 (App Engine 设置 $PORT)
bind = f"0.0.0.0:{os.environ.get('PORT', '8080')}"
app.yaml entrypoint 选项:
# 简单 (大多数情况推荐)
entrypoint: gunicorn -b :$PORT myproject.wsgi:application
# 使用配置文件
entrypoint: gunicorn -c gunicorn.conf.py myproject.wsgi:application
# 指定 workers 和 timeout
entrypoint: gunicorn -b :$PORT -w 2 -t 55 myproject.wsgi:application
关键点:
gthread worker 类# 收集静态文件
python manage.py collectstatic --noinput
# 部署
gcloud app deploy app.yaml
# 通过环境变量设置数据库密码
gcloud app deploy --set-env-vars="DB_PASSWORD=your_secure_password"
# 查看日志
gcloud app logs tail -s default
验证部署:
# 在浏览器中打开
gcloud app browse
# 检查数据库连接
gcloud app logs read --service=default | grep -i database
务必做到:
/cloudsql/PROJECT:REGION:INSTANCEPORT='' (空字符串)CONN_MAX_AGE 用于连接池 (30-60 秒)切勿做到:
app.yaml 中 (部署时使用 Secret Manager 或环境变量)HOST='localhost' (必须使用 Unix 套接字路径)beta_settings.cloud_sql_instancesCONN_MAX_AGE=None (无限) - 可能耗尽连接池此技能可预防 12 个已记录的问题 :
错误 : 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 Engine 找不到 Unix 套接字,因为 app.yaml 中缺少 beta_settings.cloud_sql_instances 预防措施 : 始终在 app.yaml 中包含 beta_settings.cloud_sql_instances: "PROJECT:REGION:INSTANCE"
错误 : 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 认证代理未运行或绑定到错误的端口 预防措施 : 在本地运行 Django 之前启动 cloud-sql-proxy PROJECT:REGION:INSTANCE。验证其运行在端口 5432 上。
错误 : 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
错误 : 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。
错误 : DeadlineExceededError 或请求在 60 秒后终止 来源 : https://cloud.google.com/appengine/docs/standard/python3/how-requests-are-handled 发生原因 : 数据库查询或迁移耗时超过 App Engine 的 60 秒限制 预防措施 : 将 Gunicorn 超时设置为 55 秒。对于长时间运行的任务,使用 Cloud Tasks 或 Cloud Run Jobs。
错误 : 静态文件返回 404,CSS/JS 无法加载 来源 : https://cloud.google.com/appengine/docs/standard/serving-static-files 发生原因 : app.yaml 中缺少 static/ 处理程序,或部署前未运行 collectstatic 预防措施 : 部署前运行 python manage.py collectstatic --noinput。在 app.yaml 中包含静态文件处理程序。
错误 : Forbidden (403) CSRF verification failed 来源 : Django 关于 CSRF 的文档 发生原因 : 未为 appspot.com 域名设置 CSRF_TRUSTED_ORIGINS 预防措施 : 在 settings.py 中添加 CSRF_TRUSTED_ORIGINS = ['https://*.appspot.com']
错误 : 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 完全匹配。
错误 : 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:PROJECT@appspot.gserviceaccount.com" --role="roles/cloudsql.instanceUser"
错误 : 迁移超时或部署期间无法运行 来源 : https://cloud.google.com/sql/docs/postgres/connect-build 发生原因 : App Engine 部署不提供迁移步骤;在 entrypoint 中运行会超时 预防措施 : 通过 Cloud Build 单独运行迁移,或在部署前使用 Cloud SQL 代理在本地运行。
错误 : 关于硬编码 SECRET_KEY 的安全警告 来源 : Django 部署清单 发生原因 : SECRET_KEY 在 settings.py 中,而不是在环境变量或 Secret Manager 中 预防措施 : 使用 SECRET_KEY = os.environ.get('SECRET_KEY') 并通过 gcloud app deploy --set-env-vars 或 Secret Manager 设置。
错误 : 空闲期后的第一个请求超时 来源 : 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 处理程序。
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
# 安全设置
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',
]
# App Engine 的 CSRF 设置
CSRF_TRUSTED_ORIGINS = [
'https://*.appspot.com',
'https://*.run.app',
]
# 应用定义
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 您的应用在此处
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # 静态文件
'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'
# 数据库
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_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'static'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
# 默认主键字段类型
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# 日志记录
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,
},
},
}
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 workersmin_instances: 0 在空闲时节省成本target_cpu_utilization: 0.65 在过载前进行扩展Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0
import os
def get_database_config():
"""根据环境返回数据库配置。"""
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 项目
from google.cloud import secretmanager
def get_secret(secret_id, version_id='latest'):
"""从 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')
# 在 settings.py 中的用法
if os.getenv('GAE_APPLICATION'):
SECRET_KEY = get_secret('django-secret-key')
DB_PASSWORD = get_secret('db-password')
使用场景 : 需要适当密钥管理的生产环境部署
# 用于无需 Cloud SQL 认证代理的本地开发
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",
)
# 在 settings.py 中用于本地开发 (需要 pg8000 驱动)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'USER': 'postgres',
'OPTIONS': {
'get_conn': get_db_connection,
},
}
}
使用场景 : 无法安装 Cloud SQL 认证代理时的本地开发
# views.py
from django.http import JsonResponse
from django.db import connection
def health_check(request):
"""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/settings_snippet.py - 复制粘贴数据库配置templates/app.yaml - 完整的 App Engine 配置templates/requirements.txt - 生产环境依赖项references/cloud-sql-proxy-setup.md - 详细的代理安装和使用说明references/iam-authentication.md - 基于 IAM 的身份验证 (无密码)references/secret-manager.md - 正确存储密钥references/migrations-in-production.md - 安全运行迁移Claude 应在何时加载这些文件:
cloud-sql-proxy-setup.mdiam-authentication.mdmigrations-in-production.md使用 IAM 进行服务到服务的身份验证,而非密码身份验证:
# 在实例上启用 IAM 身份验证
gcloud sql instances patch INSTANCE --database-flags cloudsql.iam_authentication=on
# 创建 IAM 用户
gcloud sql users create SERVICE_ACCOUNT@PROJECT.iam \
--instance=INSTANCE \
--type=CLOUD_IAM_SERVICE_ACCOUNT
# 授予连接权限
gcloud projects add-iam-policy-binding PROJECT \
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com" \
--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': '',
# IAM 身份验证无需 PASSWORD
}
}
对于高流量应用,在 Cloud Run 上部署 PgBouncer:
# 用于 PgBouncer 的 Cloud Run 服务
# 完整配置请参见 references/pgbouncer-setup.md
为何使用 PgBouncer:
CONN_MAX_AGE 有帮助,但不在进程间共享连接池选项 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: 本地使用代理 (简单)
./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 的替代方案){
"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 部署:
No such file or directory解决方案 :
beta_settings.cloud_sql_instancesPROJECT:REGION:INSTANCEgcloud sql instances list解决方案 :
HOST 使用 Unix 套接字路径,而非 127.0.0.1Cloud SQL Client 角色解决方案 :
解决方案 :
python manage.py collectstatic --noinputstatic/ 处理程序指向正确的目录beta_settings.cloud_sql_instancesCONN_MAX_AGE 用于连接池gcloud app deploy 部署有问题?遇到问题?
gcloud sql instances list最后验证 : 2026-01-24 | 技能版本 : 1.0.0
每周安装次数
272
仓库
GitHub Stars
652
首次出现
Jan 24, 2026
安全审计
Status : Production Ready Last Updated : 2026-01-24 Dependencies : None Latest Versions : Django@5.1, psycopg2-binary@2.9.9, gunicorn@23.0.0, google-cloud-sql-connector@1.12.0
pip install Django psycopg2-binary gunicorn
For Cloud SQL Python Connector (recommended for local dev):
pip install "cloud-sql-python-connector[pg8000]"
Why this matters:
psycopg2-binary is the PostgreSQL adapter for Djangogunicorn is required for App Engine Standard (Python 3.10+)settings.py (production with Unix socket):
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',
}
}
CRITICAL:
/cloudsql/PROJECT:REGION:INSTANCE127.0.0.1:5432runtime: 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
CRITICAL:
beta_settings.cloud_sql_instances enables the Unix socket at /cloudsql/...gcloud app deploy or Secret Manager, not in app.yaml# 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
Key Points:
POSTGRES_15 or later for best compatibilitydb-f1-micro is cheapest for dev ($7-10/month), use db-g1-small or higher for productionPROJECT_ID:REGION:INSTANCE_NAMErequirements.txt:
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0
settings.py additions:
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
Why these settings:
CONN_MAX_AGE=60 reduces connection overhead (Cloud SQL has connection limits)ALLOWED_HOSTS must include .appspot.com for App EngineInstall 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
Run the 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
Set environment variables for local dev:
export DB_NAME=mydb
export DB_USER=postgres
export DB_PASSWORD=your_password
export DEBUG=True
Key Points:
# Local (with proxy running)
python manage.py migrate
# Verify connection
python manage.py dbshell
For production migrations (via Cloud Build or local with proxy):
# 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
gunicorn.conf.py (optional, for fine-tuning):
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 options:
# 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
Key Points:
gthread worker class for I/O-bound Django apps# 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
Verify deployment:
# Open in browser
gcloud app browse
# Check database connection
gcloud app logs read --service=default | grep -i database
ALWAYS DO:
/cloudsql/PROJECT:REGION:INSTANCE on App EnginePORT='' (empty string) for Unix socket connectionsCONN_MAX_AGE for connection pooling (30-60 seconds)NEVER DO:
app.yaml (use Secret Manager or env vars at deploy time)HOST='localhost' on App Engine (must use Unix socket path)beta_settings.cloud_sql_instances in app.yamlCONN_MAX_AGE=None (unlimited) - can exhaust connection poolThis skill prevents 12 documented issues :
Error : django.db.utils.OperationalError: could not connect to server: No such file or directory Source : https://cloud.google.com/sql/docs/postgres/connect-app-engine-standard Why It Happens : App Engine can't find the Unix socket because beta_settings.cloud_sql_instances is missing in app.yaml Prevention : Always include beta_settings.cloud_sql_instances: "PROJECT:REGION:INSTANCE" in app.yaml
Error : django.db.utils.OperationalError: connection refused or could not connect to server: Connection refused 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 cloud-sql-proxy PROJECT:REGION:INSTANCE before running Django locally. Verify it's running on port 5432.
Error : FATAL: password authentication failed for user "postgres" 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 gcloud sql users list --instance=INSTANCE. Reset if needed: gcloud sql users set-password postgres --instance=INSTANCE --password=NEW_PASSWORD
Error : FATAL: too many connections for role "postgres" or remaining connection slots are reserved 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 CONN_MAX_AGE = 60 in Django settings. For high traffic, use PgBouncer or django-db-connection-pool.
Error : DeadlineExceededError 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.
Error : Static files return 404, CSS/JS not loading Source : https://cloud.google.com/appengine/docs/standard/serving-static-files Why It Happens : Missing static/ handler in app.yaml or collectstatic not run before deploy Prevention : Run python manage.py collectstatic --noinput before deploy. Include static handler in app.yaml.
Error : Forbidden (403) CSRF verification failed Source : Django documentation on CSRF Why It Happens : CSRF_TRUSTED_ORIGINS not set for appspot.com domain Prevention : Add CSRF_TRUSTED_ORIGINS = ['https://*.appspot.com'] to settings.py
Error : django.db.utils.OperationalError: FATAL: database "mydb" does not exist Source : https://cloud.google.com/sql/docs/postgres/create-manage-databases Why It Happens : Database exists in Cloud SQL but DB_NAME environment variable is wrong Prevention : Verify database name: gcloud sql databases list --instance=INSTANCE. Ensure DB_NAME matches exactly.
Error : FATAL: Cloud SQL IAM user authentication failed Source : https://cloud.google.com/sql/docs/postgres/iam-logins Why It Happens : App Engine service account doesn't have roles/cloudsql.instanceUser role Prevention : Grant role: gcloud projects add-iam-policy-binding PROJECT --member="serviceAccount:PROJECT@appspot.gserviceaccount.com" --role="roles/cloudsql.instanceUser"
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.
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 SECRET_KEY = os.environ.get('SECRET_KEY') and set via gcloud app deploy --set-env-vars or Secret Manager.
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 app_engine_apis: true and add /_ah/warmup handler.
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,
},
},
}
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
Why these settings:
F2 instance class allows 2 Gunicorn workersmin_instances: 0 saves costs when idletarget_cpu_utilization: 0.65 scales before overloadDjango>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0
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
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')
When to use : Production deployments requiring proper secret management
# 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,
},
}
}
When to use : Local development when you can't install Cloud SQL Auth Proxy
# 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'),
]
When to use : Load balancer health checks, monitoring database connectivity
templates/settings_snippet.py - Copy-paste database configurationtemplates/app.yaml - Complete App Engine configurationtemplates/requirements.txt - Production dependenciesreferences/cloud-sql-proxy-setup.md - Detailed proxy installation and usagereferences/iam-authentication.md - IAM-based authentication (no passwords)references/secret-manager.md - Storing secrets properlyreferences/migrations-in-production.md - Running migrations safelyWhen Claude should load these:
cloud-sql-proxy-setup.md when user has local connection issuesiam-authentication.md when setting up passwordless authmigrations-in-production.md before first production deploymentInstead of password authentication, use IAM for service-to-service auth:
# Enable IAM authentication on instance
gcloud sql instances patch INSTANCE --database-flags cloudsql.iam_authentication=on
# Create IAM user
gcloud sql users create SERVICE_ACCOUNT@PROJECT.iam \
--instance=INSTANCE \
--type=CLOUD_IAM_SERVICE_ACCOUNT
# Grant connect permission
gcloud projects add-iam-policy-binding PROJECT \
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com" \
--role="roles/cloudsql.instanceUser"
Django settings for IAM auth:
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
}
}
For high-traffic applications, deploy PgBouncer on Cloud Run:
# Cloud Run service for PgBouncer
# See references/pgbouncer-setup.md for full configuration
Why PgBouncer:
CONN_MAX_AGE helps but doesn't pool across processesOption 1: Cloud Build (Recommended)
# 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)
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate
Required:
Django>=5.1 - Web frameworkpsycopg2-binary>=2.9.9 - PostgreSQL adaptergunicorn>=23.0.0 - WSGI server for App EngineRecommended:
whitenoise>=6.7.0 - Static file servingpython-dotenv>=1.0.0 - Local environment variablesOptional:
google-cloud-secret-manager>=2.20.0 - Secret Manager integrationcloud-sql-python-connector[pg8000]>=1.12.0 - Python-native Cloud SQL connectordjango-db-connection-pool>=1.2.5 - Connection pooling (alternative to CONN_MAX_AGE){
"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"
}
}
This skill is based on production Django deployments on App Engine:
No such file or directory for socketSolution :
beta_settings.cloud_sql_instances in app.yamlPROJECT:REGION:INSTANCEgcloud sql instances listSolution :
HOST uses Unix socket path, not 127.0.0.1Cloud SQL Client roleSolution :
Solution :
python manage.py collectstatic --noinput before deploystatic/ handler in app.yaml points to correct directorybeta_settings.cloud_sql_instances in app.yamlCONN_MAX_AGE set for connection poolinggcloud app deployQuestions? Issues?
gcloud sql instances listLast verified : 2026-01-24 | Skill version : 1.0.0
Weekly Installs
272
Repository
GitHub Stars
652
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykPass
Installed on
claude-code224
gemini-cli181
opencode179
cursor167
antigravity159
codex159
Azure 升级评估与自动化工具 - 轻松迁移 Functions 计划、托管层级和 SKU
68,100 周安装