将 PostGraphile v5 部署到 Google Cloud Platform(App Engine + Cloud SQL)
将 PostGraphile v5 部署到 Google Cloud PlatformApp Engine Cloud SQL【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystal本指南讲解如何将 PostGraphile v5 部署到 Google Cloud PlatformGCP核心场景是让运行在 Google App EngineGAE上的 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 上本质上要解决三件事数据库连接PostGraphile 需要连上 Cloud SQL 里的 PostgreSQL 实例。App Engine Flex 环境可以通过beta_settings.cloud_sql_instances建立与 Cloud SQL 实例之间的 Unix socket / TCP 通道服务监听PostGraphile 的 grafserv 需要监听0.0.0.0:8080因为 GAE 的 nginx 代理只会把请求转发到这个端口启动方式既可以直接用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 API与App 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-devtcp: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-central1central 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: nodejsenv: 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.mjsPostGraphile 会自动加载它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-build与graphile-build-pg的默认 preset并按与 PostGraphile v4 兼容的顺序排布了PgBasicsPlugin、PgIntrospectionPlugin、PgTablesPlugin、PgRelationsPlugin、PgMutationCreatePlugin、PgMutationUpdateDeletePlugin、PgOrderAllAttributesPlugin等核心插件同时加入SwallowErrorsPluginmakePgService({ connectionString: process.env.DATABASE_URL })声明一个 PostgreSQL 数据源。makePgService来自postgraphile/adaptors/pg其底层是dataplan/pg的pg适配器见 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.jsonpackage.json需要声明postgraphile依赖与启动脚本{ name: myprojectname, version: 1.0.0, scripts: { start: postgraphile }, engines: { node: 24 }, license: ISC, dependencies: { postgraphile: ^5.0.0 } }scripts.start: postgraphileGAE 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打开 RuruPostGraphile 自带的 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.mjs的app.listen(8080)env_variables提供了传统的 PostgreSQL 环境变量PGUSER/PGHOST/PGPASSWORD/PGDATABASEpg客户端会自动读取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.mjspackage.json{ scripts: { start: node src/index.mjs } }启动命令改为直接运行 Node 入口文件。graphile.config.mjsimport { 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挂载 PostGraphileimport 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);这段代码的调用链与仓库源码一一对应postgraphile(preset)返回一个PostGraphileInstance定义见 postgraphile/src/index.ts它会先resolvePreset解析配置再构建 GraphQL schemapgl.createServ(grafserv)创建 grafserv 实例把解析后的 preset 与 schema 交给 grafserv见 index.tsgrafserv从postgraphile/grafserv/express/v4导入这是面向 Express 4 的适配器对应包导出./grafserv/express/v4见 postgraphile/package.jsonawait 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.tsmakePgService({ connectionString, schemas, pubsub, ... })声明 PostgreSQL 数据源可选schemas暴露的 schema 列表、superuserConnectionString、pubsub订阅等dataplan-pg/src/interfaces.tsgrafserv.host/grafserv.portgrafserv 监听地址与端口CLI 中由--host/--port覆盖postgraphile/src/cli.tsgrafserv.graphqlPathGraphQL 端点路径默认/graphqlpostgraphile/src/cli.tsCLI 自动加载graphile.config.mjsCLI 启动时通过loadConfig加载配置再resolvePreset解析postgraphile/src/cli.tspostgraphile()库入口解析 preset、构建 schema、创建 grafserv 实例postgraphile/src/index.ts值得一提的底层细节dataplan/pg的pg适配器adaptors/pg.ts在初始化连接池时会对查询做性能取向的调优例如默认禁用 PostgreSQL 的 JIT 编译以规避高成本查询下 JIT 带来的巨大耗时可通过环境变量DATAPLAN_PG_DONT_DISABLE_JIT1恢复并默认缓存 100 条 prepared statements可通过DATAPLAN_PG_PREPARED_STATEMENT_CACHE_SIZE0关闭。这些参数在 GCP 高负载场景下也可能影响连接池表现可作为排查性能问题的参考。常见注意事项小结端口必须是 8080GAE 只会把流量转发到实例的 8080 端口grafserv.port或app.listen(8080)务必与之匹配host 必须是0.0.0.0否则 GAE 的 nginx 无法绑定服务cloud_sql_instances的三种写法只写实例连接串project:region:instanceApp Engine 在/cloudsql/下暴露 Unix socket配合PGHOST/cloudsql/连接串使用追加tcp:5432映射到本机 TCP 5432 端口连接串写作postgres://user:passlocalhost:5432/db注意方案一文档作者反馈直接用 Unix socket 失败若遇到连接问题可优先切换到 TCP 映射Flexible vs Standard需要 WebSocket 订阅时只能用 Flexible不需要实时功能时 Standard 更省钱postgres用户权限Cloud SQL 的postgres非 superuser跨角色切换前先GRANT role TO postgres;敏感信息数据库密码建议通过 GAE 的env_variables或 Secret Manager 注入DATABASE_URL避免出现在app.yaml与代码库中。部署完成后访问https://[project-name].appspot.com/graphiql方案一或https://[project-name].appspot.com/graphql方案二即可验证 GraphQL 服务是否正常响应。【免费下载链接】crystal Graphiles Crystal Monorepo; home to Grafast, PostGraphile, pg-introspection, pg-sql2 and much more!项目地址: https://gitcode.com/gh_mirrors/cry/crystal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考