将 PostGraphile v5 部署到 Google Cloud Platform(App Engine + Cloud SQL)
2026/9/23 14:08:24 网站建设 项目流程

将 PostGraphile v5 部署到 Google Cloud Platform(App Engine + Cloud SQL)

【免费下载链接】crystal🔮 Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystal

本指南讲解如何将 PostGraphile v5 部署到 Google Cloud Platform(GCP),核心场景是让运行在 Google App Engine(GAE)上的 Node.js 服务连接 Google Cloud SQL 中的 PostgreSQL 数据库,对外提供 GraphQL API。读完本文,你将掌握两种实战方案:直接用postgraphileCLI 启动服务的极简部署,以及将 PostGraphile 作为 Express 中间件嵌入自定义 Node 服务的灵活部署,同时理解cloud_sql_instances连接配置、app.yaml各项参数的含义,以及 Cloud SQL 上 PostgreSQL 角色授权的注意事项。

本文内容以仓库中 deploying-gcp.md 为主线,并结合 PostGraphile v5 源码(presets/amber.ts、cli.ts、index.ts)对配置项逐一印证。

部署方案总览

把 PostGraphile 放到 GCP 上,本质上要解决三件事:

  1. 数据库连接:PostGraphile 需要连上 Cloud SQL 里的 PostgreSQL 实例。App Engine Flex 环境可以通过beta_settings.cloud_sql_instances建立与 Cloud SQL 实例之间的 Unix socket / TCP 通道;
  2. 服务监听:PostGraphile 的 grafserv 需要监听0.0.0.0:8080,因为 GAE 的 nginx 代理只会把请求转发到这个端口;
  3. 启动方式:既可以直接用postgraphileCLI 作为启动命令(适合快速上线),也可以把 PostGraphile 作为库嵌入 Express 应用(适合需要自定义中间件、WebSocket 订阅等场景)。

下文分别给出这两种方案的完整配置。

方案一:PostGraphile CLI + Cloud SQL

该方案的典型架构是:PostgreSQL 托管在 Google Cloud SQL,前端 Angular 应用托管在 App Engine 的默认 service 上,而 PostGraphile 作为独立的 App Engine service 对外提供 GraphQL 接口。

前置条件

  • 已创建一个 GCP 项目,并开启了Cloud SQL Admin APIApp Engine
  • 项目中已有可用的Cloud SQL PostgreSQL 实例(在 Cloud SQL 控制台的 "Connect to this instance" 区域可以看到完整的实例连接名,形如project-id:region:instance-name);
  • 将 App Engine 的默认 service 保留给前端应用,PostGraphile 使用自定义 service 名(如wgraphile)独立部署;
  • 连接 Cloud SQL 必须使用cloud_sql_instances配置(这是 GAE 访问 Cloud SQL 的官方通道)。

编写 app.yaml

在项目根目录创建部署文件app.yaml,示例内容如下:

beta_settings: cloud_sql_instances: webstr-dev-######:us-central1:webstr-dev=tcp:5432 # [START runtime] runtime: nodejs env: flex threadsafe: yes service: wgraphile manual_scaling: instances: 1 resources: cpu: .5 memory_gb: .5 disk_size_gb: 10 health_check: enable_health_check: False # [END runtime] handlers: - url: /(.*) static_files: ./\1 upload: ./(.*) # settings to keep gcloud from uploading files not required for deployment skip_files: - ^node_modules$ - ^README\..* - ^package-lock.json - \.gitignore - \.es* - ^\.git$ - ^errors\.log

各配置段的作用:

  • beta_settings.cloud_sql_instances:声明要连接的 Cloud SQL 实例通道。值为项目ID:区域:实例名=tcp:5432,含义是"打开一条到 GCP 项目webstr-dev-######、位于us-central1(central region 1)、名为webstr-dev的 Cloud SQL 实例的通道"。=tcp:5432把 Unix socket 映射到本机 TCP 5432 端口,PostGraphile 即可通过localhost:5432访问数据库;
    • 实际部署经验:直接使用 Unix socket 路径容易失败,因此文档作者采用了 TCP 端口映射的方式;
    • 完整的实例连接名可以从 Cloud SQL 控制台 "Connect to this instance" 区域复制。
  • runtime: nodejs+env: flex:使用 Node.js 运行时 + Flex 环境。Flexible 环境提供真正的 VM 与更自由的网络配置,也是支持 WebSocket(订阅功能)的前提(详见方案二);
  • service: wgraphile:把该版本部署到名为wgraphile的 App Engine service,避免占用默认 service(默认 service 留给前端);
  • manual_scaling.instances: 1:固定为 1 个实例,适合小流量或开发验证阶段;
  • resources:为实例分配 0.5 核 CPU、0.5 GB 内存、10 GB 磁盘;
  • health_check.enable_health_check: False:关闭 GAE 的健康检查(文档中即如此配置,避免健康检查探针干扰 GraphQL 端点);
  • handlers:将任意 URL 映射到静态文件(该配置在服务本身只提供 API 时通常可以精简,原文档中保留用于说明静态资源场景);
  • skip_files:用正则排除无需上传的本地文件(node_modules、README、package-lock.json.gitignore.eslintrc等以.es开头的文件、.git目录、errors.log),加快部署并减小上传体积。

编写 graphile.config.mjs

package.json同级创建graphile.config.mjs,PostGraphile 会自动加载它:

import { PostGraphileAmberPreset } from "postgraphile/presets/amber"; import { makePgService } from "postgraphile/adaptors/pg"; export default { extends: [PostGraphileAmberPreset], pgServices: [makePgService({ connectionString: process.env.DATABASE_URL })], grafserv: { host: "0.0.0.0", port: 8080, graphqlPath: "/", // Quick hack for development; use a proper CORS policy in production. // dangerouslyAllowAllCORSRequests: true, }, };
  • extends: [PostGraphileAmberPreset]:启用 PostGraphile 推荐的 Amber preset。该 preset 在源码中定义为 PostGraphileAmberPreset,它组合了graphile-buildgraphile-build-pg的默认 preset,并按与 PostGraphile v4 兼容的顺序排布了PgBasicsPluginPgIntrospectionPluginPgTablesPluginPgRelationsPluginPgMutationCreatePluginPgMutationUpdateDeletePluginPgOrderAllAttributesPlugin等核心插件,同时加入SwallowErrorsPlugin
  • makePgService({ connectionString: process.env.DATABASE_URL }):声明一个 PostgreSQL 数据源。makePgService来自postgraphile/adaptors/pg,其底层是@dataplan/pgpg适配器(见 adaptors/pg.ts),连接串通过环境变量DATABASE_URL注入(App Engine 的env_variables或 Secret Manager 均可提供),避免把密码写死在配置里;
  • grafserv.host: "0.0.0.0":让服务监听所有网卡,GAE 的 nginx 才能成功绑定并转发请求;
  • grafserv.port: 8080:绑定到 8080 端口。这是 GCP 约定暴露的端口,GAE 会把请求自动转发到该端口,因此部署后可通过 service 名直接访问;
  • grafserv.graphqlPath: "/":把 GraphQL 端点从默认的/graphql改到根路径/

编写 package.json

package.json需要声明postgraphile依赖与启动脚本:

{ "name": "myprojectname", "version": "1.0.0", "scripts": { "start": "postgraphile" }, "engines": { "node": ">=24" }, "license": "ISC", "dependencies": { "postgraphile": "^5.0.0" } }
  • scripts.start: "postgraphile":GAE Flex 启动时执行npm start,从而启动 PostGraphile CLI 服务。CLI 会自动读取同目录下的graphile.config.mjs(见 cli.ts 中loadConfig的加载逻辑);
  • postgraphile: ^5.0.0:当前仓库中的 PostGraphile 为 v5.1.4(见 postgraphile/package.json),包本身声明engines.node >= 22,文档示例中写>=24属于更保守的要求,请以你使用的版本与 GAE 运行时实际为准。

部署与访问

在项目目录下执行:

gcloud init # 首次使用时初始化 gcloud 并登录你的 GCP 项目 gcloud app deploy # 将当前目录部署到 App Engine

部署完成后:

  • 服务的访问地址为https://[project-name].appspot.com/
  • GraphQL 端点即该 URL(因为graphqlPath设为/);
  • 可以在https://[project-name].appspot.com/graphiql打开 Ruru(PostGraphile 自带的 GraphQL IDE,对应包导出见 postgraphile/package.json 中的./grafserv/ruru)。

方案二:将 PostGraphile 嵌入 Express 应用

如果需要在 GraphQL 服务旁边叠加自定义 HTTP 逻辑(如鉴权中间件、文件上传、WebSocket 订阅等),可以改用"以库的形式"部署:在 GAE 上启动一个 Express 应用,把 PostGraphile 挂载进去。

app.yaml 与数据库环境变量

GCP 侧的配置:

runtime: nodejs env: flex env_variables: PGUSER: "your-database-user" PGHOST: "/cloudsql/your-cloudsql-instance-connection-string" PGPASSWORD: "your-password" PGDATABASE: "your-database-name" beta_settings: cloud_sql_instances: your-cloudsql-instance-connection-string

要点:

  • 这里没有显式指定port,但 Express 服务仍需监听 8080(见下文src/index.mjsapp.listen(8080));
  • env_variables提供了传统的 PostgreSQL 环境变量(PGUSER/PGHOST/PGPASSWORD/PGDATABASE),pg客户端会自动读取;
  • PGHOST指向/cloudsql/<连接串>,这是 App Engine Flex 暴露的 Cloud SQL Unix socket 路径;
  • 必须使用 Flexible 环境,因为它支持 WebSocket,这是 GraphQL 订阅(实时功能)的前提;如果不需要实时特性,可以改用 Standard 环境以降低成本,此时需移除beta_settings段;
  • 若使用 Standard 环境或无法依赖 Unix socket,也可沿用方案一中的=tcp:5432映射方式,并让连接串指向localhost:5432

项目结构

最小项目结构如下:

/project |--package.json |--/src |--index.mjs |--graphile.config.mjs

package.json

{ "scripts": { "start": "node src/index.mjs" } }

启动命令改为直接运行 Node 入口文件。

graphile.config.mjs

import { PostGraphileAmberPreset } from "postgraphile/presets/amber"; import { makePgService } from "postgraphile/adaptors/pg"; export default { extends: [PostGraphileAmberPreset], pgServices: [ makePgService({ connectionString: process.env.DATABASE_URL, }), ], grafserv: { host: "0.0.0.0", port: 8080, }, };

与方案一的差异是这里不设置graphqlPath,因此 GraphQL 端点保持 grafserv 默认的/graphql

src/index.mjs:挂载 PostGraphile

import express from "express"; import preset from "./graphile.config.mjs"; import { postgraphile } from "postgraphile"; import { grafserv } from "postgraphile/grafserv/express/v4"; const app = express(); const pgl = postgraphile(preset); const serv = pgl.createServ(grafserv); await serv.addTo(app); app.listen(8080);

这段代码的调用链与仓库源码一一对应:

  1. postgraphile(preset)返回一个PostGraphileInstance(定义见 postgraphile/src/index.ts),它会先resolvePreset解析配置,再构建 GraphQL schema;
  2. pgl.createServ(grafserv)创建 grafserv 实例,把解析后的 preset 与 schema 交给 grafserv(见 index.ts);
  3. grafservpostgraphile/grafserv/express/v4导入,这是面向 Express 4 的适配器(对应包导出./grafserv/express/v4,见 postgraphile/package.json);
  4. await serv.addTo(app)把 GraphQL 路由挂载到 Express 应用上,随后app.listen(8080)监听 GCP 约定端口。

postgraphile/grafserv/express/v4只是 PostGraphile 支持的多种服务器适配器之一;同仓库还提供./grafserv/node./grafserv/koa/v2./grafserv/koa/v3./grafserv/fastify/v4./grafserv/fastify/v5./grafserv/hono/v4./grafserv/lambda/v1等导出(见 postgraphile/package.json),可根据你的服务端框架选择。

Cloud SQL 上的 PostgreSQL 授权问题

Google Cloud SQL 中的postgres用户不是 superuser,这与本地开发时常用的 PostgreSQL 超级用户账户不同。因此,如果 PostGraphile 运行中需要SET LOCAL role TO <某角色>;(例如切换到anonymous匿名角色来应用行级权限控制),必须先显式地把该角色授予postgres用户。

例如,数据库中已创建角色anonymous,希望postgres角色能够执行SET LOCAL role TO anonymous;,则执行:

GRANT anonymous TO postgres;

这条语句让postgres获得切换到anonymous角色的权限,从而保证 PostGraphile 在 Cloud SQL 上也能像本地开发时一样完成角色切换与权限隔离。

配置项与源码印证

为了便于按图索骥,这里把上文涉及的配置与其源码位置对应起来:

配置 / 能力作用仓库中的实现位置
PostGraphileAmberPreset推荐 preset,聚合 Graphile 插件并按 v4 兼容顺序排序presets/amber.ts
makePgService({ connectionString, schemas, pubsub, ... })声明 PostgreSQL 数据源,可选schemas(暴露的 schema 列表)、superuserConnectionStringpubsub(订阅)等dataplan-pg/src/interfaces.ts
grafserv.host/grafserv.portgrafserv 监听地址与端口;CLI 中由--host/--port覆盖postgraphile/src/cli.ts
grafserv.graphqlPathGraphQL 端点路径,默认/graphqlpostgraphile/src/cli.ts
CLI 自动加载graphile.config.mjsCLI 启动时通过loadConfig加载配置,再resolvePreset解析postgraphile/src/cli.ts
postgraphile()库入口解析 preset、构建 schema、创建 grafserv 实例postgraphile/src/index.ts

值得一提的底层细节:@dataplan/pgpg适配器(adaptors/pg.ts)在初始化连接池时会对查询做性能取向的调优,例如默认禁用 PostgreSQL 的 JIT 编译以规避高成本查询下 JIT 带来的巨大耗时(可通过环境变量DATAPLAN_PG_DONT_DISABLE_JIT=1恢复),并默认缓存 100 条 prepared statements(可通过DATAPLAN_PG_PREPARED_STATEMENT_CACHE_SIZE=0关闭)。这些参数在 GCP 高负载场景下也可能影响连接池表现,可作为排查性能问题的参考。

常见注意事项小结

  1. 端口必须是 8080:GAE 只会把流量转发到实例的 8080 端口,grafserv.port(或app.listen(8080))务必与之匹配;
  2. host 必须是0.0.0.0:否则 GAE 的 nginx 无法绑定服务;
  3. cloud_sql_instances的三种写法
    • 只写实例连接串(project:region:instance):App Engine 在/cloudsql/下暴露 Unix socket,配合PGHOST=/cloudsql/<连接串>使用;
    • 追加=tcp:5432:映射到本机 TCP 5432 端口,连接串写作postgres://user:pass@localhost:5432/db
    • 注意方案一文档作者反馈"直接用 Unix socket 失败",若遇到连接问题可优先切换到 TCP 映射;
  4. Flexible vs Standard:需要 WebSocket 订阅时只能用 Flexible;不需要实时功能时 Standard 更省钱;
  5. postgres用户权限:Cloud SQL 的postgres非 superuser,跨角色切换前先GRANT role TO postgres;
  6. 敏感信息:数据库密码建议通过 GAE 的env_variables或 Secret Manager 注入DATABASE_URL,避免出现在app.yaml与代码库中。

部署完成后,访问https://[project-name].appspot.com/graphiql(方案一)或https://[project-name].appspot.com/graphql(方案二)即可验证 GraphQL 服务是否正常响应。

【免费下载链接】crystal🔮 Graphile's Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystal

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询