Google App Engine
Google App Engine
Status: Production Ready
Last Updated: 2026-01-24
Dependencies: Google Cloud SDK (gcloud CLI)
Skill Version: 1.0.0
状态:可用于生产环境
最后更新:2026-01-24
依赖项:Google Cloud SDK(gcloud CLI)
技能版本:1.0.0
Quick Start (10 Minutes)
快速入门(10分钟)
Install Google Cloud SDK
Install Google Cloud SDK
brew install google-cloud-sdk
brew install google-cloud-sdk
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
Enable required APIs
Enable required APIs
gcloud services enable appengine.googleapis.com
gcloud services enable sqladmin.googleapis.com
gcloud services enable secretmanager.googleapis.com
gcloud services enable appengine.googleapis.com
gcloud services enable sqladmin.googleapis.com
gcloud services enable secretmanager.googleapis.com
2. Create app.yaml
2. 创建app.yaml
app.yaml - Standard Environment (Python 3.12)
app.yaml - Standard Environment (Python 3.12)
runtime: python312
instance_class: F2
env_variables:
DJANGO_SETTINGS_MODULE: "myproject.settings.production"
handlers:
Static files (served directly by App Engine)
- url: /static
static_dir: staticfiles/
secure: always
All other requests go to the app
- url: /.*
script: auto
secure: always
automatic_scaling:
min_instances: 0
max_instances: 10
target_cpu_utilization: 0.65
runtime: python312
instance_class: F2
env_variables:
DJANGO_SETTINGS_MODULE: "myproject.settings.production"
handlers:
Static files (served directly by App Engine)
- url: /static
static_dir: staticfiles/
secure: always
All other requests go to the app
- url: /.*
script: auto
secure: always
automatic_scaling:
min_instances: 0
max_instances: 10
target_cpu_utilization: 0.65
Deploy to App Engine
Deploy to App Engine
Deploy with specific version
Deploy with specific version
gcloud app deploy --version=v1 --no-promote
gcloud app deploy --version=v1 --no-promote
gcloud app logs tail -s default
gcloud app logs tail -s default
Standard vs Flexible Environment
标准环境 vs 弹性环境
Standard Environment (Recommended for Most Apps)
标准环境(推荐用于大多数应用)
Use when: Building typical web apps, APIs, or services that fit within runtime constraints.
| Aspect | Standard |
|---|
| Startup | Fast (milliseconds) |
| Scaling | Scale to zero |
| Pricing | Pay per request |
| Runtimes | Python 3.8-3.12 |
| Instance Classes | F1, F2, F4, F4_1G |
| Max Request | 60 seconds |
| Background | Cloud Tasks only |
适用场景:构建符合运行时约束的典型Web应用、API或服务。
| 维度 | 标准环境 |
|---|
| 启动速度 | 快(毫秒级) |
| 扩缩容 | 可缩容至0实例 |
| 定价 | 按请求付费 |
| 运行时 | Python 3.8-3.12 |
| 实例类型 | F1, F2, F4, F4_1G |
| 最长请求时长 | 60秒 |
| 后台任务 | 仅支持Cloud Tasks |
app.yaml - Standard
app.yaml - Standard
runtime: python312
instance_class: F2
runtime: python312
instance_class: F2
Use when: Need custom runtimes, Docker, longer request timeouts, or background threads.
| Aspect | Flexible |
|---|
| Startup | Slower (minutes) |
| Scaling | Min 1 instance |
| Pricing | Per-hour VM |
| Runtimes | Any (Docker) |
| Max Request | 60 minutes |
| Background | Native threads |
适用场景:需要自定义运行时、Docker、更长请求超时或后台线程的场景。
| 维度 | 弹性环境 |
|---|
| 启动速度 | 较慢(分钟级) |
| 扩缩容 | 最少1个实例 |
| 定价 | 按VM小时付费 |
| 运行时 | 任意(Docker) |
| 最长请求时长 | 60分钟 |
| 后台任务 | 支持原生线程 |
app.yaml - Flexible
app.yaml - Flexible
runtime: python
env: flex
runtime_config:
runtime_version: "3.12"
resources:
cpu: 1
memory_gb: 0.5
disk_size_gb: 10
automatic_scaling:
min_num_instances: 1
max_num_instances: 5
**Cost Warning**: Flexible always runs at least 1 instance (~$30-40/month minimum).
---
runtime: python
env: flex
runtime_config:
runtime_version: "3.12"
resources:
cpu: 1
memory_gb: 0.5
disk_size_gb: 10
automatic_scaling:
min_num_instances: 1
max_num_instances: 5
**成本警告**:弹性环境始终至少运行1个实例(每月最低约30-40美元)。
---
Cloud SQL Connection
Cloud SQL连接
Standard Environment (Unix Socket)
标准环境(Unix套接字)
App Engine Standard connects to Cloud SQL via Unix sockets, not TCP/IP.
App Engine标准环境通过Unix套接字而非TCP/IP连接到Cloud SQL。
import os
if os.getenv('GAE_APPLICATION'):
# Production: Cloud SQL 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: Cloud SQL Proxy or local DB
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'localdb'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
import os
if os.getenv('GAE_APPLICATION'):
# Production: Cloud SQL 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: Cloud SQL Proxy or local DB
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'localdb'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
env_variables:
DB_NAME: "mydb"
DB_USER: "myuser"
CLOUD_SQL_CONNECTION_NAME: "project:region:instance"
env_variables:
DB_NAME: "mydb"
DB_USER: "myuser"
CLOUD_SQL_CONNECTION_NAME: "project:region:instance"
CRITICAL: Beta settings for Cloud SQL socket
CRITICAL: Beta settings for Cloud SQL socket
beta_settings:
cloud_sql_instances: "project:region:instance"
**CRITICAL**: The `beta_settings.cloud_sql_instances` enables the Unix socket. Without it, connection fails.
beta_settings:
cloud_sql_instances: "project:region:instance"
**关键提示**:`beta_settings.cloud_sql_instances`用于启用Unix套接字。如果缺少此项,连接将失败。
Local Development with Cloud SQL Proxy
使用Cloud SQL Proxy进行本地开发
Download and run Cloud SQL Proxy
Download and run Cloud SQL Proxy
cloud-sql-proxy PROJECT:REGION:INSTANCE --port=5432
cloud-sql-proxy PROJECT:REGION:INSTANCE --port=5432
Or use Docker
Or use Docker
docker run -p 5432:5432
gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
PROJECT:REGION:INSTANCE
docker run -p 5432:5432
gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
PROJECT:REGION:INSTANCE
Static Files with Cloud Storage
使用Cloud Storage托管静态文件
Option 1: App Engine Static Handlers (Simple)
选项1:App Engine静态文件处理器(简单方案)
handlers:
- url: /static
static_dir: staticfiles/
secure: always
expiration: "1d"
handlers:
- url: /static
static_dir: staticfiles/
secure: always
expiration: "1d"
Collect static files before deploy
Collect static files before deploy
python manage.py collectstatic --noinput
gcloud app deploy
**Limitation**: Files bundled with deploy, limited to 32MB per file.
python manage.py collectstatic --noinput
gcloud app deploy
**限制**:文件随部署包一起上传,单个文件最大限制为32MB。
Option 2: Cloud Storage (Recommended for Production)
选项2:Cloud Storage(生产环境推荐)
from google.cloud import storage
GS_BUCKET_NAME = os.environ.get('GS_BUCKET_NAME')
STATICFILES_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'
DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'
from google.cloud import storage
GS_BUCKET_NAME = os.environ.get('GS_BUCKET_NAME')
STATICFILES_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'
DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage'
Or with django-storages
Or with django-storages
STORAGES = {
"default": {
"BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
"OPTIONS": {
"bucket_name": GS_BUCKET_NAME,
"location": "media",
},
},
"staticfiles": {
"BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
"OPTIONS": {
"bucket_name": GS_BUCKET_NAME,
"location": "static",
},
},
}
STORAGES = {
"default": {
"BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
"OPTIONS": {
"bucket_name": GS_BUCKET_NAME,
"location": "media",
},
},
"staticfiles": {
"BACKEND": "storages.backends.gcloud.GoogleCloudStorage",
"OPTIONS": {
"bucket_name": GS_BUCKET_NAME,
"location": "static",
},
},
}
Install django-storages
Install django-storages
pip install django-storages[google]
pip install django-storages[google]
Create bucket with public access for static files
Create bucket with public access for static files
gsutil mb -l us-central1 gs://YOUR_BUCKET_NAME
gsutil iam ch allUsers:objectViewer gs://YOUR_BUCKET_NAME
gsutil mb -l us-central1 gs://YOUR_BUCKET_NAME
gsutil iam ch allUsers:objectViewer gs://YOUR_BUCKET_NAME
Environment Variables and Secrets
环境变量与密钥
Simple: app.yaml env_variables
简单方案:app.yaml env_variables
app.yaml - NOT for secrets!
app.yaml - NOT for secrets!
env_variables:
DJANGO_SETTINGS_MODULE: "myproject.settings.production"
DEBUG: "False"
**Warning**: `app.yaml` is committed to source control. Never put secrets here.
env_variables:
DJANGO_SETTINGS_MODULE: "myproject.settings.production"
DEBUG: "False"
**警告**:`app.yaml`会提交到版本控制系统。切勿在此处存放密钥。
Production: Secret Manager
生产环境方案:Secret Manager
from google.cloud import secretmanager
def get_secret(secret_id, version="latest"):
"""Fetch 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}"
response = client.access_secret_version(request={"name": name})
return response.payload.data.decode("UTF-8")
from google.cloud import secretmanager
def get_secret(secret_id, version="latest"):
"""Fetch 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}"
response = client.access_secret_version(request={"name": name})
return response.payload.data.decode("UTF-8")
if os.getenv('GAE_APPLICATION'):
SECRET_KEY = get_secret('django-secret-key')
DB_PASSWORD = get_secret('db-password')
if os.getenv('GAE_APPLICATION'):
SECRET_KEY = get_secret('django-secret-key')
DB_PASSWORD = get_secret('db-password')
Create secrets
Create secrets
echo -n "your-secret-key" | gcloud secrets create django-secret-key --data-file=-
echo -n "db-password" | gcloud secrets create db-password --data-file=-
echo -n "your-secret-key" | gcloud secrets create django-secret-key --data-file=-
echo -n "db-password" | gcloud secrets create db-password --data-file=-
Grant App Engine access
Grant App Engine access
gcloud secrets add-iam-policy-binding django-secret-key
--member="serviceAccount:YOUR_PROJECT@appspot.gserviceaccount.com"
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding django-secret-key
--member="serviceAccount:YOUR_PROJECT@appspot.gserviceaccount.com"
--role="roles/secretmanager.secretAccessor"
Scaling Configuration
扩缩容配置
Automatic Scaling (Default)
自动扩缩容(默认)
yaml
automatic_scaling:
min_instances: 0 # Scale to zero when idle
max_instances: 10 # Cap maximum instances
target_cpu_utilization: 0.65
target_throughput_utilization: 0.6
max_concurrent_requests: 80
min_pending_latency: 30ms
max_pending_latency: automatic
yaml
automatic_scaling:
min_instances: 0 # 空闲时缩容至0实例
max_instances: 10 # 最大实例数上限
target_cpu_utilization: 0.65
target_throughput_utilization: 0.6
max_concurrent_requests: 80
min_pending_latency: 30ms
max_pending_latency: automatic
Basic Scaling (Background Tasks)
基础扩缩容(后台任务)
yaml
basic_scaling:
max_instances: 5
idle_timeout: 5m
Use for: Services that need to run background work without scaling to zero immediately.
yaml
basic_scaling:
max_instances: 5
idle_timeout: 5m
适用场景:需要运行后台任务且无需立即缩容至0的服务。
Manual Scaling (Fixed Instances)
手动扩缩容(固定实例数)
yaml
manual_scaling:
instances: 3
Use for: Predictable workloads, WebSocket connections, or when you need guaranteed capacity.
yaml
manual_scaling:
instances: 3
适用场景:可预测的工作负载、WebSocket连接,或需要保证容量的场景。
| Class | Memory | CPU | Cost/hour |
|---|
| F1 | 256 MB | 600 MHz | $0.05 |
| F2 | 512 MB | 1.2 GHz | $0.10 |
| F4 | 1 GB | 2.4 GHz | $0.20 |
| F4_1G | 2 GB | 2.4 GHz | $0.30 |
| 类型 | 内存 | CPU | 每小时成本 |
|---|
| F1 | 256 MB | 600 MHz | $0.05 |
| F2 | 512 MB | 1.2 GHz | $0.10 |
| F4 | 1 GB | 2.4 GHz | $0.20 |
| F4_1G | 2 GB | 2.4 GHz | $0.30 |
Recommended for Django
Recommended for Django
instance_class: F2 # 512MB usually sufficient
**Upgrade to F4** if you see memory errors or slow response times.
---
instance_class: F2 # 512MB通常足够Django使用
**升级建议**:如果遇到内存错误或响应缓慢,升级到F4实例。
---
Known Issues Prevention
已知问题预防
This skill prevents 6 documented issues:
Issue #1: Cloud SQL Connection Refused
问题1:Cloud SQL连接被拒绝
Error:
could not connect to server: Connection refused
Why It Happens: Missing
beta_settings.cloud_sql_instances
in app.yaml
Prevention: Always include:
yaml
beta_settings:
cloud_sql_instances: "project:region:instance"
错误:
could not connect to server: Connection refused
原因:app.yaml中缺少
beta_settings.cloud_sql_instances
配置
预防方案:始终添加以下配置:
yaml
beta_settings:
cloud_sql_instances: "project:region:instance"
Issue #2: Static Files 404
问题2:静态文件返回404
Error: Static files return 404 after deploy
Why It Happens:
not run, or handler order wrong
Prevention:
bash
python manage.py collectstatic --noinput
And ensure static handler comes before catch-all:
yaml
handlers:
- url: /static
static_dir: staticfiles/
- url: /.*
script: auto
错误:部署后静态文件返回404
原因:未运行
,或处理器顺序错误
预防方案:
bash
python manage.py collectstatic --noinput
并确保静态文件处理器在通配符处理器之前:
yaml
handlers:
- url: /static
static_dir: staticfiles/
- url: /.*
script: auto
Issue #3: 502 Bad Gateway
问题3:502 Bad Gateway
Error: 502 errors on first request or under load
Why It Happens: Cold start timeout, app takes too long to initialize
Prevention:
- Optimize app startup (lazy imports, connection pooling)
- Use to avoid cold starts
- Increase for more CPU/memory
错误:首次请求或高负载下出现502错误
原因:冷启动超时,应用初始化时间过长
预防方案:
- 优化应用启动(延迟导入、连接池)
- 设置避免冷启动
- 升级以获取更多CPU/内存
Issue #4: Memory Limit Exceeded
问题4:内存限制超出
Error:
Exceeded soft memory limit
in logs
Why It Happens: F1 class (256MB) too small for Django + dependencies
Prevention: Use
minimum for Django apps
错误:日志中出现
Exceeded soft memory limit
原因:F1实例(256MB)对于Django及依赖来说太小
预防方案:Django应用至少使用
Issue #5: Request Timeout
问题5:请求超时
Error:
after 60 seconds
Why It Happens: Standard environment has 60s request limit
Prevention:
- Move long tasks to Cloud Tasks
- Use Flexible environment for longer timeouts
- Optimize database queries
错误:60秒后出现
原因:标准环境请求时长限制为60秒
预防方案:
- 将长任务迁移至Cloud Tasks
- 使用弹性环境以获得更长超时
- 优化数据库查询
Issue #6: Secret Key in Source Control
问题6:密钥泄露到版本控制系统
Error: Django
exposed in git history
Why It Happens: Putting secrets in
env_variables
Prevention: Use Secret Manager (see Environment Variables section)
错误:Django
在git历史中暴露
原因:将密钥存放在
的env_variables中
预防方案:使用Secret Manager(参见环境变量章节)
Deploy default service
Deploy default service
Deploy specific service
Deploy specific service
gcloud app deploy app.yaml --service=api
gcloud app deploy app.yaml --service=api
Deploy without promoting (for testing)
Deploy without promoting (for testing)
gcloud app deploy --version=v2 --no-promote
gcloud app deploy --version=v2 --no-promote
Split traffic between versions
Split traffic between versions
gcloud app services set-traffic default --splits=v1=0.5,v2=0.5
gcloud app services set-traffic default --splits=v1=0.5,v2=0.5
Promote version
Promote version
gcloud app versions migrate v2
gcloud app versions migrate v2
gcloud app logs tail -s default
gcloud app logs tail -s default
Open app in browser
Open app in browser
List versions
List versions
Delete old versions
Delete old versions
gcloud app versions delete v1 v2 --quiet
gcloud app versions delete v1 v2 --quiet
Multi-Service Architecture
多服务架构
myproject/
├── app.yaml # Default service
├── api/
│ └── app.yaml # API service
├── worker/
│ └── app.yaml # Background worker
└── dispatch.yaml # URL routing
myproject/
├── app.yaml # Default service
├── api/
│ └── app.yaml # API service
├── worker/
│ └── app.yaml # Background worker
└── dispatch.yaml # URL routing
dispatch.yaml
dispatch.yaml
dispatch:
- url: "/api/"
service: api
- url: "/tasks/"
service: worker
dispatch:
- url: "/api/"
service: api
- url: "/tasks/"
service: worker
Deploy all services
Deploy all services
gcloud app deploy app.yaml api/app.yaml worker/app.yaml dispatch.yaml
gcloud app deploy app.yaml api/app.yaml worker/app.yaml dispatch.yaml
Health Check Endpoint
健康检查端点
urlpatterns = [
path('_ah/health', lambda r: HttpResponse('ok')),
# ... other urls
]
urlpatterns = [
path('_ah/health', lambda r: HttpResponse('ok')),
# ... other urls
]
liveness_check:
path: "/_ah/health"
check_interval_sec: 30
timeout_sec: 4
failure_threshold: 2
success_threshold: 2
readiness_check:
path: "/_ah/health"
check_interval_sec: 5
timeout_sec: 4
failure_threshold: 2
success_threshold: 2
liveness_check:
path: "/_ah/health"
check_interval_sec: 30
timeout_sec: 4
failure_threshold: 2
success_threshold: 2
readiness_check:
path: "/_ah/health"
check_interval_sec: 5
timeout_sec: 4
failure_threshold: 2
success_threshold: 2
urlpatterns = [
path('_ah/warmup', warmup_view),
]
urlpatterns = [
path('_ah/warmup', warmup_view),
]
def warmup_view(request):
"""Pre-warm caches and connections."""
from django.db import connection
connection.ensure_connection()
return HttpResponse('ok')
def warmup_view(request):
"""Pre-warm caches and connections."""
from django.db import connection
connection.ensure_connection()
return HttpResponse('ok')
handlers:
- url: /.*
script: auto
secure: always # Redirects HTTP to HTTPS
handlers:
- url: /.*
script: auto
secure: always # Redirects HTTP to HTTPS
Using Cloud SQL Proxy
使用Cloud SQL Proxy
Terminal 1: Run Cloud SQL Proxy
Terminal 1: Run Cloud SQL Proxy
cloud-sql-proxy PROJECT:REGION:INSTANCE --port=5432
cloud-sql-proxy PROJECT:REGION:INSTANCE --port=5432
Terminal 2: Run Django
Terminal 2: Run Django
export DB_HOST=127.0.0.1
export DB_PORT=5432
python manage.py runserver
export DB_HOST=127.0.0.1
export DB_PORT=5432
python manage.py runserver
Using dev_appserver (Legacy)
使用dev_appserver(旧版)
Not recommended - use Django's runserver instead
Not recommended - use Django's runserver instead
dev_appserver.py app.yaml
dev_appserver.py app.yaml
Environment Detection
环境检测
Detect App Engine environment
Detect App Engine environment
IS_GAE = os.getenv('GAE_APPLICATION') is not None
IS_GAE_LOCAL = os.getenv('GAE_ENV') == 'localdev'
if IS_GAE:
DEBUG = False
ALLOWED_HOSTS = ['.appspot.com', '.your-domain.com']
else:
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
IS_GAE = os.getenv('GAE_APPLICATION') is not None
IS_GAE_LOCAL = os.getenv('GAE_ENV') == 'localdev'
if IS_GAE:
DEBUG = False
ALLOWED_HOSTS = ['.appspot.com', '.your-domain.com']
else:
DEBUG = True
ALLOWED_HOSTS = ['localhost', '127.0.0.1']
Templates (templates/)
模板(templates/)
- - Standard environment configuration
- - Flexible environment configuration
- - Common dependencies for App Engine
- - 标准环境配置
- - 弹性环境配置
- - App Engine常用依赖
References (references/)
参考文档(references/)
- - Detailed instance class comparison
- - Error messages and solutions
Official Documentation
官方文档
requirements.txt
requirements.txt
gunicorn>=21.0.0
google-cloud-secret-manager>=2.16.0
google-cloud-storage>=2.10.0
django-storages[google]>=1.14.0
psycopg2-binary>=2.9.9 # For PostgreSQL
gunicorn>=21.0.0
google-cloud-secret-manager>=2.16.0
google-cloud-storage>=2.10.0
django-storages[google]>=1.14.0
psycopg2-binary>=2.9.9 # For PostgreSQL
Production Checklist
生产环境检查清单
Last verified: 2026-01-24 | Skill version: 1.0.0
最后验证:2026-01-24 | 技能版本:1.0.0